summaryrefslogtreecommitdiffstats
path: root/subversion/libsvn_ra_serf/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_ra_serf/util.c')
-rw-r--r--subversion/libsvn_ra_serf/util.c261
1 files changed, 180 insertions, 81 deletions
diff --git a/subversion/libsvn_ra_serf/util.c b/subversion/libsvn_ra_serf/util.c
index ce1e31a..55efca4 100644
--- a/subversion/libsvn_ra_serf/util.c
+++ b/subversion/libsvn_ra_serf/util.c
@@ -191,13 +191,65 @@ construct_realm(svn_ra_serf__session_t *session,
static char *
convert_organisation_to_str(apr_hash_t *org, apr_pool_t *pool)
{
- return apr_psprintf(pool, "%s, %s, %s, %s, %s (%s)",
- (char*)svn_hash_gets(org, "OU"),
- (char*)svn_hash_gets(org, "O"),
- (char*)svn_hash_gets(org, "L"),
- (char*)svn_hash_gets(org, "ST"),
- (char*)svn_hash_gets(org, "C"),
- (char*)svn_hash_gets(org, "E"));
+ const char *org_unit = svn_hash_gets(org, "OU");
+ const char *org_name = svn_hash_gets(org, "O");
+ const char *locality = svn_hash_gets(org, "L");
+ const char *state = svn_hash_gets(org, "ST");
+ const char *country = svn_hash_gets(org, "C");
+ const char *email = svn_hash_gets(org, "E");
+ svn_stringbuf_t *buf = svn_stringbuf_create_empty(pool);
+
+ if (org_unit)
+ {
+ svn_stringbuf_appendcstr(buf, org_unit);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (org_name)
+ {
+ svn_stringbuf_appendcstr(buf, org_name);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (locality)
+ {
+ svn_stringbuf_appendcstr(buf, locality);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (state)
+ {
+ svn_stringbuf_appendcstr(buf, state);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ if (country)
+ {
+ svn_stringbuf_appendcstr(buf, country);
+ svn_stringbuf_appendcstr(buf, ", ");
+ }
+
+ /* Chop ', ' if any. */
+ svn_stringbuf_chop(buf, 2);
+
+ if (email)
+ {
+ svn_stringbuf_appendcstr(buf, "(");
+ svn_stringbuf_appendcstr(buf, email);
+ svn_stringbuf_appendcstr(buf, ")");
+ }
+
+ return buf->data;
+}
+
+static void append_reason(svn_stringbuf_t *errmsg, const char *reason, int *reasons)
+{
+ if (*reasons < 1)
+ svn_stringbuf_appendcstr(errmsg, _(": "));
+ else
+ svn_stringbuf_appendcstr(errmsg, _(", "));
+ svn_stringbuf_appendcstr(errmsg, reason);
+ (*reasons)++;
}
/* This function is called on receiving a ssl certificate of a server when
@@ -258,11 +310,12 @@ ssl_server_cert(void *baton, int failures,
for (i = 0; i < san->nelts; i++) {
char *s = APR_ARRAY_IDX(san, i, char*);
if (apr_fnmatch(s, conn->session->session_url.hostname,
- APR_FNM_PERIOD) == APR_SUCCESS) {
+ APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_SUCCESS)
+ {
found_matching_hostname = 1;
cert_info.hostname = s;
break;
- }
+ }
}
}
@@ -270,7 +323,7 @@ ssl_server_cert(void *baton, int failures,
if (!found_matching_hostname && cert_info.hostname)
{
if (apr_fnmatch(cert_info.hostname, conn->session->session_url.hostname,
- APR_FNM_PERIOD) == APR_FNM_NOMATCH)
+ APR_FNM_PERIOD | APR_FNM_CASE_BLIND) == APR_FNM_NOMATCH)
{
svn_failures |= SVN_AUTH_SSL_CNMISMATCH;
}
@@ -301,7 +354,35 @@ ssl_server_cert(void *baton, int failures,
SVN_AUTH_PARAM_SSL_SERVER_CERT_INFO, NULL);
if (!server_creds)
- return svn_error_create(SVN_ERR_RA_SERF_SSL_CERT_UNTRUSTED, NULL, NULL);
+ {
+ svn_stringbuf_t *errmsg;
+ int reasons = 0;
+
+ errmsg = svn_stringbuf_create(
+ _("Server SSL certificate verification failed"),
+ scratch_pool);
+
+
+ if (svn_failures & SVN_AUTH_SSL_NOTYETVALID)
+ append_reason(errmsg, _("certificate is not yet valid"), &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_EXPIRED)
+ append_reason(errmsg, _("certificate has expired"), &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_CNMISMATCH)
+ append_reason(errmsg,
+ _("certificate issued for a different hostname"),
+ &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_UNKNOWNCA)
+ append_reason(errmsg, _("issuer is not trusted"), &reasons);
+
+ if (svn_failures & SVN_AUTH_SSL_OTHER)
+ append_reason(errmsg, _("and other reason(s)"), &reasons);
+
+ return svn_error_create(SVN_ERR_RA_SERF_SSL_CERT_UNTRUSTED, NULL,
+ errmsg->data);
+ }
return SVN_NO_ERROR;
}
@@ -746,8 +827,6 @@ svn_ra_serf__context_run_wait(svn_boolean_t *done,
the connection timed out. */
if (APR_STATUS_IS_TIMEUP(status))
{
- svn_error_clear(err);
- err = SVN_NO_ERROR;
status = 0;
if (sess->timeout)
@@ -758,8 +837,11 @@ svn_ra_serf__context_run_wait(svn_boolean_t *done,
}
else
{
- return svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
- _("Connection timed out"));
+ return
+ svn_error_compose_create(
+ err,
+ svn_error_create(SVN_ERR_RA_DAV_CONN_TIMEOUT, NULL,
+ _("Connection timed out")));
}
}
}
@@ -805,6 +887,23 @@ svn_ra_serf__context_run_one(svn_ra_serf__handler_t *handler,
/* Wait until the response logic marks its DONE status. */
err = svn_ra_serf__context_run_wait(&handler->done, handler->session,
scratch_pool);
+
+ /* A callback invocation has been canceled. In this simple case of
+ context_run_one, we can keep the ra-session operational by resetting
+ the connection.
+
+ If we don't do this, the next context run will notice that the connection
+ is still in the error state and will just return SVN_ERR_CEASE_INVOCATION
+ (=the last error for the connection) again */
+ if (err && err->apr_err == SVN_ERR_CEASE_INVOCATION)
+ {
+ apr_status_t status = serf_connection_reset(handler->conn->conn);
+
+ if (status)
+ err = svn_error_compose_create(err,
+ svn_ra_serf__wrap_err(status, NULL));
+ }
+
if (handler->server_error)
{
err = svn_error_compose_create(err, handler->server_error->error);
@@ -1388,19 +1487,22 @@ inject_to_parser(svn_ra_serf__xml_parser_t *ctx,
int xml_status;
xml_status = XML_Parse(ctx->xmlp, data, (int) len, 0);
- if (xml_status == XML_STATUS_ERROR && !ctx->ignore_errors)
+
+ if (! ctx->ignore_errors)
{
- if (sl == NULL)
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("XML parsing failed"));
+ SVN_ERR(ctx->error);
- return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
- _("XML parsing failed: (%d %s)"),
- sl->code, sl->reason);
- }
+ if (xml_status != XML_STATUS_OK)
+ {
+ if (sl == NULL)
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("XML parsing failed"));
- if (ctx->error && !ctx->ignore_errors)
- return svn_error_trace(ctx->error);
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("XML parsing failed: (%d %s)"),
+ sl->code, sl->reason);
+ }
+ }
return SVN_NO_ERROR;
}
@@ -1481,14 +1583,26 @@ svn_ra_serf__process_pending(svn_ra_serf__xml_parser_t *parser,
if (pending_empty &&
parser->pending->network_eof)
{
+ int xml_status;
SVN_ERR_ASSERT(parser->xmlp != NULL);
- /* Tell the parser that no more content will be parsed. Ignore the
- return status. We just don't care. */
- (void) XML_Parse(parser->xmlp, NULL, 0, 1);
+ /* Tell the parser that no more content will be parsed. */
+ xml_status = XML_Parse(parser->xmlp, NULL, 0, 1);
apr_pool_cleanup_run(parser->pool, &parser->xmlp, xml_parser_cleanup);
parser->xmlp = NULL;
+
+ if (! parser->ignore_errors)
+ {
+ SVN_ERR(parser->error);
+
+ if (xml_status != XML_STATUS_OK)
+ {
+ return svn_error_createf(SVN_ERR_RA_DAV_MALFORMED_DATA, NULL,
+ _("XML parsing failed"));
+ }
+ }
+
add_done_item(parser);
}
@@ -1588,22 +1702,6 @@ svn_ra_serf__handle_xml_parser(serf_request_t *request,
return svn_error_trace(err);
}
- if (ctx->headers_baton == NULL)
- ctx->headers_baton = serf_bucket_response_get_headers(response);
- else if (ctx->headers_baton != serf_bucket_response_get_headers(response))
- {
- /* We got a new response to an existing parser...
- This tells us the connection has restarted and we should continue
- where we stopped last time.
- */
-
- /* Is this a second attempt?? */
- if (!ctx->skip_size)
- ctx->skip_size = ctx->read_size;
-
- ctx->read_size = 0; /* New request, nothing read */
- }
-
if (!ctx->xmlp)
{
ctx->xmlp = XML_ParserCreate(NULL);
@@ -1623,41 +1721,11 @@ svn_ra_serf__handle_xml_parser(serf_request_t *request,
apr_size_t len;
status = serf_bucket_read(response, PARSE_CHUNK_SIZE, &data, &len);
-
if (SERF_BUCKET_READ_ERROR(status))
{
return svn_ra_serf__wrap_err(status, NULL);
}
- ctx->read_size += len;
-
- if (ctx->skip_size)
- {
- /* Handle restarted requests correctly: Skip what we already read */
- apr_size_t skip;
-
- if (ctx->skip_size >= ctx->read_size)
- {
- /* Eek. What did the file shrink or something? */
- if (APR_STATUS_IS_EOF(status))
- {
- SVN_ERR_MALFUNCTION();
- }
-
- /* Skip on to the next iteration of this loop. */
- if (APR_STATUS_IS_EAGAIN(status))
- {
- return svn_ra_serf__wrap_err(status, NULL);
- }
- continue;
- }
-
- skip = (apr_size_t)(len - (ctx->read_size - ctx->skip_size));
- data += skip;
- len -= skip;
- ctx->skip_size = 0;
- }
-
/* Note: once the callbacks invoked by inject_to_parser() sets the
PAUSED flag, then it will not be cleared. write_to_pending() will
only save the content. Logic outside of serf_context_run() will
@@ -1703,12 +1771,25 @@ svn_ra_serf__handle_xml_parser(serf_request_t *request,
in the PENDING structures, then we're completely done. */
if (!HAS_PENDING_DATA(ctx->pending))
{
+ int xml_status;
SVN_ERR_ASSERT(ctx->xmlp != NULL);
- /* Ignore the return status. We just don't care. */
- (void) XML_Parse(ctx->xmlp, NULL, 0, 1);
+ xml_status = XML_Parse(ctx->xmlp, NULL, 0, 1);
apr_pool_cleanup_run(ctx->pool, &ctx->xmlp, xml_parser_cleanup);
+
+ if (! ctx->ignore_errors)
+ {
+ SVN_ERR(ctx->error);
+
+ if (xml_status != XML_STATUS_OK)
+ {
+ return svn_error_create(
+ SVN_ERR_XML_MALFORMED, NULL,
+ _("The XML response contains invalid XML"));
+ }
+ }
+
add_done_item(ctx);
}
@@ -1828,12 +1909,26 @@ handle_response(serf_request_t *request,
{
/* Uh-oh. Our connection died. */
if (handler->response_error)
- SVN_ERR(handler->response_error(request, response, 0,
- handler->response_error_baton));
+ {
+ /* Give a handler chance to prevent request requeue. */
+ SVN_ERR(handler->response_error(request, response, 0,
+ handler->response_error_baton));
- /* Requeue another request for this handler.
- ### how do we know if the handler can deal with this?! */
- svn_ra_serf__request_create(handler);
+ svn_ra_serf__request_create(handler);
+ }
+ /* Response error callback is not configured. Requeue another request
+ for this handler only if we didn't started to process body.
+ Return error otherwise. */
+ else if (!handler->reading_body)
+ {
+ svn_ra_serf__request_create(handler);
+ }
+ else
+ {
+ return svn_error_createf(SVN_ERR_RA_DAV_REQUEST_FAILED, NULL,
+ _("%s request on '%s' failed"),
+ handler->method, handler->path);
+ }
return SVN_NO_ERROR;
}
@@ -2417,6 +2512,10 @@ svn_ra_serf__error_on_status(serf_status_line sline,
"server or an intermediate proxy does not accept "
"chunked encoding. Try setting 'http-chunked-requests' "
"to 'auto' or 'no' in your client configuration."));
+ case 501:
+ return svn_error_createf(SVN_ERR_UNSUPPORTED_FEATURE, NULL,
+ _("The requested feature is not supported by "
+ "'%s'"), path);
}
if (sline.code >= 300)
OpenPOWER on IntegriCloud