diff options
Diffstat (limited to 'subversion/libsvn_ra_serf/util.c')
-rw-r--r-- | subversion/libsvn_ra_serf/util.c | 261 |
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) |