📄 util.c
字号:
/* * util.c : serf utility routines for ra_serf * * ==================================================================== * Copyright (c) 2006 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#define APR_WANT_STRFUNC#include <apr_want.h>#include <apr_base64.h>#include <serf.h>#include <serf_bucket_types.h>#include "svn_path.h"#include "svn_private_config.h"#include "ra_serf.h"/* Fix for older expat 1.95.x's that do not define * XML_STATUS_OK/XML_STATUS_ERROR */#ifndef XML_STATUS_OK#define XML_STATUS_OK 1#define XML_STATUS_ERROR 0#endifserf_bucket_t *svn_ra_serf__conn_setup(apr_socket_t *sock, void *baton, apr_pool_t *pool){ serf_bucket_t *bucket; svn_ra_serf__connection_t *conn = baton; bucket = serf_bucket_socket_create(sock, conn->bkt_alloc); if (conn->using_ssl) { bucket = serf_bucket_ssl_decrypt_create(bucket, conn->ssl_context, conn->bkt_alloc); if (!conn->ssl_context) { conn->ssl_context = serf_bucket_ssl_decrypt_context_get(bucket); } } return bucket;}serf_bucket_t*svn_ra_serf__accept_response(serf_request_t *request, serf_bucket_t *stream, void *acceptor_baton, apr_pool_t *pool){ serf_bucket_t *c; serf_bucket_alloc_t *bkt_alloc; bkt_alloc = serf_request_get_alloc(request); c = serf_bucket_barrier_create(stream, bkt_alloc); return serf_bucket_response_create(c, bkt_alloc);}static serf_bucket_t*accept_head(serf_request_t *request, serf_bucket_t *stream, void *acceptor_baton, apr_pool_t *pool){ serf_bucket_t *response; response = svn_ra_serf__accept_response(request, stream, acceptor_baton, pool); /* We know we shouldn't get a response body. */ serf_bucket_response_set_head(response); return response;}voidsvn_ra_serf__conn_closed(serf_connection_t *conn, void *closed_baton, apr_status_t why, apr_pool_t *pool){ svn_ra_serf__connection_t *our_conn = closed_baton; if (why) { abort(); } if (our_conn->using_ssl) { our_conn->ssl_context = NULL; }}apr_status_tsvn_ra_serf__cleanup_serf_session(void *data){ svn_ra_serf__session_t *serf_sess = data; int i; /* If we are cleaning up due to an error, don't call connection_close * as we're already on our way out of here and we'll defer to serf's * cleanups. */ if (serf_sess->pending_error) { return APR_SUCCESS; } for (i = 0; i < serf_sess->num_conns; i++) { if (serf_sess->conns[i]) { serf_connection_close(serf_sess->conns[i]->conn); serf_sess->conns[i] = NULL; } } return APR_SUCCESS;}voidsvn_ra_serf__setup_serf_req(serf_request_t *request, serf_bucket_t **req_bkt, serf_bucket_t **ret_hdrs_bkt, svn_ra_serf__connection_t *conn, const char *method, const char *url, serf_bucket_t *body_bkt, const char *content_type){ serf_bucket_t *hdrs_bkt; *req_bkt = serf_bucket_request_create(method, url, body_bkt, serf_request_get_alloc(request)); hdrs_bkt = serf_bucket_request_get_headers(*req_bkt); serf_bucket_headers_setn(hdrs_bkt, "Host", conn->hostinfo); serf_bucket_headers_setn(hdrs_bkt, "User-Agent", "svn/ra_serf"); if (content_type) { serf_bucket_headers_setn(hdrs_bkt, "Content-Type", content_type); } if (conn->auth_header && conn->auth_value) { serf_bucket_headers_setn(hdrs_bkt, conn->auth_header, conn->auth_value); } /* Set up SSL if we need to */ if (conn->using_ssl) { *req_bkt = serf_bucket_ssl_encrypt_create(*req_bkt, conn->ssl_context, serf_request_get_alloc(request)); if (!conn->ssl_context) { conn->ssl_context = serf_bucket_ssl_encrypt_context_get(*req_bkt); } } if (ret_hdrs_bkt) { *ret_hdrs_bkt = hdrs_bkt; }}svn_error_t *svn_ra_serf__context_run_wait(svn_boolean_t *done, svn_ra_serf__session_t *sess, apr_pool_t *pool){ apr_status_t status; sess->pending_error = SVN_NO_ERROR; while (!*done) { int i; status = serf_context_run(sess->context, SERF_DURATION_FOREVER, pool); if (APR_STATUS_IS_TIMEUP(status)) { continue; } if (status) { if (sess->pending_error) { return sess->pending_error; } return svn_error_wrap_apr(status, "Error running context"); } /* Debugging purposes only! */ serf_debug__closed_conn(sess->bkt_alloc); for (i = 0; i < sess->num_conns; i++) { serf_debug__closed_conn(sess->conns[i]->bkt_alloc); } } return SVN_NO_ERROR;}apr_status_tsvn_ra_serf__is_conn_closing(serf_bucket_t *response){ serf_bucket_t *hdrs; const char *val; hdrs = serf_bucket_response_get_headers(response); val = serf_bucket_headers_get(hdrs, "Connection"); if (val && strcasecmp("close", val) == 0) { return SERF_ERROR_CLOSING; } return APR_EOF;}/* * Expat callback invoked on a start element tag for an error response. */static svn_error_t *start_error(svn_ra_serf__xml_parser_t *parser, void *userData, svn_ra_serf__dav_props_t name, const char **attrs){ svn_ra_serf__server_error_t *ctx = userData; if (!ctx->in_error && strcmp(name.namespace, "DAV:") == 0 && strcmp(name.name, "error") == 0) { ctx->in_error = TRUE; } else if (ctx->in_error && strcmp(name.name, "human-readable") == 0) { const char *err_code; err_code = svn_ra_serf__find_attr(attrs, "errcode"); if (err_code) { ctx->error->apr_err = apr_atoi64(err_code); } else { ctx->error->apr_err = APR_EGENERAL; } ctx->collect_message = TRUE; } return SVN_NO_ERROR;}/* * Expat callback invoked on an end element tag for a PROPFIND response. */static svn_error_t *end_error(svn_ra_serf__xml_parser_t *parser, void *userData, svn_ra_serf__dav_props_t name){ svn_ra_serf__server_error_t *ctx = userData; if (ctx->in_error && strcmp(name.namespace, "DAV:") == 0 && strcmp(name.name, "error") == 0) { ctx->in_error = FALSE; } if (ctx->in_error && strcmp(name.name, "human-readable") == 0) { ctx->collect_message = FALSE; } return SVN_NO_ERROR;}/* * Expat callback invoked on CDATA elements in an error response. * * This callback can be called multiple times. */static svn_error_t *cdata_error(svn_ra_serf__xml_parser_t *parser, void *userData, const char *data, apr_size_t len){ svn_ra_serf__server_error_t *ctx = userData; /* Skip blank lines in the human-readable error responses. */ if (ctx->collect_message && (len != 1 || data[0] != '\n')) { svn_ra_serf__expand_string(&ctx->error->message, &ctx->message_len, data, len, ctx->error->pool); } return SVN_NO_ERROR;}apr_status_tsvn_ra_serf__handle_discard_body(serf_request_t *request, serf_bucket_t *response, void *baton, apr_pool_t *pool){ apr_status_t status; svn_ra_serf__server_error_t *server_err = baton; if (server_err) { if (!server_err->init) { serf_bucket_t *hdrs; const char *val; server_err->init = TRUE; hdrs = serf_bucket_response_get_headers(response); val = serf_bucket_headers_get(hdrs, "Content-Type"); if (val && strncasecmp(val, "text/xml", sizeof("text/xml") - 1) == 0) { server_err->error = svn_error_create(APR_SUCCESS, NULL, NULL); server_err->has_xml_response = TRUE; server_err->parser.pool = server_err->error->pool; server_err->parser.user_data = server_err; server_err->parser.start = start_error; server_err->parser.end = end_error; server_err->parser.cdata = cdata_error; server_err->parser.done = &server_err->done; server_err->parser.ignore_errors = TRUE; } else { server_err->error = SVN_NO_ERROR; } } if (server_err->has_xml_response) { status = svn_ra_serf__handle_xml_parser(request, response, &server_err->parser, pool); if (server_err->done && server_err->error->apr_err == APR_SUCCESS) { svn_error_clear(server_err->error); server_err->error = SVN_NO_ERROR; } return status; } } /* Just loop through and discard the body. */ while (1) { const char *data; apr_size_t len; status = serf_bucket_read(response, SERF_READ_ALL_AVAIL, &data, &len); if (status) { return status; } /* feed me */ }}apr_status_tsvn_ra_serf__handle_status_only(serf_request_t *request, serf_bucket_t *response, void *baton, apr_pool_t *pool){ apr_status_t status; svn_ra_serf__simple_request_context_t *ctx = baton; status = svn_ra_serf__handle_discard_body(request, response, &ctx->server_error, pool); if (APR_STATUS_IS_EOF(status)) { serf_status_line sl; apr_status_t rv; rv = serf_bucket_response_status(response, &sl); ctx->status = sl.code; ctx->reason = sl.reason; ctx->done = TRUE; } return status;}static apr_status_thandle_auth(svn_ra_serf__session_t *session, svn_ra_serf__connection_t *conn, serf_request_t *request, serf_bucket_t *response, apr_pool_t *pool){ void *creds; svn_auth_cred_simple_t *simple_creds; const char *tmp; apr_size_t tmp_len, encoded_len; svn_error_t *error; int i; if (!session->realm) { serf_bucket_t *hdrs; char *cur, *last, *auth_hdr, *realm_name; apr_port_t port; hdrs = serf_bucket_response_get_headers(response); auth_hdr = (char*)serf_bucket_headers_get(hdrs, "WWW-Authenticate"); if (!auth_hdr) { abort(); } cur = apr_strtok(auth_hdr, " ", &last); while (cur) { if (strcmp(cur, "Basic") == 0) { char *attr; attr = apr_strtok(NULL, "=", &last); if (strcmp(attr, "realm") == 0) { realm_name = apr_strtok(NULL, "=", &last); if (realm_name[0] == '\"') { apr_size_t realm_len; realm_len = strlen(realm_name); if (realm_name[realm_len - 1] == '\"') { realm_name[realm_len - 1] = '\0'; realm_name++; } } } else { abort(); } } else { /* Support more authentication mechanisms. */ abort(); } cur = apr_strtok(NULL, " ", &last); } if (!realm_name) { abort(); } if (session->repos_url.port_str) { port = session->repos_url.port; } else { port = apr_uri_port_of_scheme(session->repos_url.scheme); } session->realm = apr_psprintf(session->pool, "<%s://%s:%d> %s", session->repos_url.scheme, session->repos_url.hostname, port, realm_name); error = svn_auth_first_credentials(&creds, &session->auth_state, SVN_AUTH_CRED_SIMPLE, session->realm, session->wc_callbacks->auth_baton, session->pool); } else { error = svn_auth_next_credentials(&creds, session->auth_state,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -