static apr_status_t setup_request(serf_request_t *request, void *setup_baton, serf_bucket_t **req_bkt, serf_response_acceptor_t *acceptor, void **acceptor_baton, serf_response_handler_t *handler, void **handler_baton, apr_pool_t *pool) { handler_baton_t *ctx = setup_baton; serf_bucket_t *hdrs_bkt; serf_bucket_t *body_bkt; if (ctx->req_body_path) { apr_file_t *file; apr_status_t status; status = apr_file_open(&file, ctx->req_body_path, APR_READ, APR_OS_DEFAULT, pool); if (status) { printf("Error opening file (%s)\n", ctx->req_body_path); return status; } body_bkt = serf_bucket_file_create(file, serf_request_get_alloc(request)); } else { body_bkt = NULL; } *req_bkt = serf_request_bucket_request_create(request, ctx->method, ctx->path, body_bkt, serf_request_get_alloc(request)); hdrs_bkt = serf_bucket_request_get_headers(*req_bkt); serf_bucket_headers_setn(hdrs_bkt, "User-Agent", "Serf/" SERF_VERSION_STRING); /* Shouldn't serf do this for us? */ serf_bucket_headers_setn(hdrs_bkt, "Accept-Encoding", "gzip"); #ifdef CONNECTION_CLOSE_HDR serf_bucket_headers_setn(hdrs_bkt, "Connection", "close"); #endif /* Add the extra headers from the command line */ if (ctx->req_hdrs != NULL) { serf_bucket_headers_do(ctx->req_hdrs, append_request_headers, hdrs_bkt); } *acceptor = ctx->acceptor; *acceptor_baton = ctx->acceptor_baton; *handler = ctx->handler; *handler_baton = ctx; return APR_SUCCESS; }
/* Dispatch authentication handling. This function matches the possible authentication mechanisms with those available. Server and proxy authentication are evaluated separately. */ static apr_status_t dispatch_auth(int code, serf_request_t *request, serf_bucket_t *response, void *baton, apr_pool_t *pool) { serf_bucket_t *hdrs; if (code == 401 || code == 407) { auth_baton_t ab = { 0 }; const char *auth_hdr; ab.code = code; ab.status = APR_SUCCESS; ab.request = request; ab.response = response; ab.baton = baton; ab.pool = pool; /* Before iterating over all authn headers, check if there are any. */ if (code == 401) ab.header = "WWW-Authenticate"; else ab.header = "Proxy-Authenticate"; hdrs = serf_bucket_response_get_headers(response); auth_hdr = serf_bucket_headers_get(hdrs, ab.header); if (!auth_hdr) { return SERF_ERROR_AUTHN_FAILED; } /* Iterate over all headers. Try to find a matching authentication scheme handler. Note: it is possible to have multiple Authentication: headers. We do not want to combine them (per normal header combination rules) as that would make it hard to parse. Instead, we want to individually parse and handle each header in the response, looking for one that we can work with. */ serf_bucket_headers_do(hdrs, handle_auth_header, &ab); if (ab.status != APR_SUCCESS) return ab.status; if (!ab.scheme || ab.scheme->name == NULL) { /* No matching authentication found. */ return SERF_ERROR_AUTHN_NOT_SUPPORTED; } } else { /* Validate the response authn headers if needed. */ } return APR_SUCCESS; }
/* Dispatch authentication handling. This function matches the possible authentication mechanisms with those available. Server and proxy authentication are evaluated separately. */ static apr_status_t dispatch_auth(int code, serf_request_t *request, serf_bucket_t *response, void *baton, apr_pool_t *pool) { serf_bucket_t *hdrs; if (code == 401 || code == 407) { auth_baton_t ab = { 0 }; const char *auth_hdr; ab.hdrs = apr_hash_make(pool); ab.pool = pool; /* Before iterating over all authn headers, check if there are any. */ if (code == 401) ab.header = "WWW-Authenticate"; else ab.header = "Proxy-Authenticate"; hdrs = serf_bucket_response_get_headers(response); auth_hdr = serf_bucket_headers_get(hdrs, ab.header); if (!auth_hdr) { return SERF_ERROR_AUTHN_FAILED; } serf__log_skt(AUTH_VERBOSE, __FILE__, request->conn->skt, "%s authz required. Response header(s): %s\n", code == 401 ? "Server" : "Proxy", auth_hdr); /* Store all WWW- or Proxy-Authenticate headers in a dictionary. Note: it is possible to have multiple Authentication: headers. We do not want to combine them (per normal header combination rules) as that would make it hard to parse. Instead, we want to individually parse and handle each header in the response, looking for one that we can work with. */ serf_bucket_headers_do(hdrs, store_header_in_dict, &ab); /* Iterate over all authentication schemes, in order of decreasing security. Try to find a authentication schema the server support. */ return handle_auth_headers(code, baton, ab.hdrs, request, response, pool); } return APR_SUCCESS; }
static const char * get_auth_header(serf_bucket_t *hdrs, const char *hdr_name, const char *auth_name, apr_pool_t *pool) { get_auth_header_baton_t b; b.auth_name = hdr_name; b.hdr_name = auth_name; b.hdr_value = NULL; b.pool = pool; serf_bucket_headers_do(hdrs, get_auth_header_cb, &b); return b.hdr_value; }
static apr_status_t handle_response(serf_request_t *request, serf_bucket_t *response, void *vbaton, apr_pool_t *pool) { apr_status_t rv; s_baton_t *ctx = vbaton; const char *data; apr_size_t len; serf_status_line sl; if (response == NULL) { ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR; return APR_EGENERAL; } /* XXXXXXX: Create better error message. */ rv = serf_bucket_response_status(response, &sl); if (rv) { if (APR_STATUS_IS_EAGAIN(rv)) { return APR_SUCCESS; } ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, APLOGNO(01121) "serf_bucket_response_status..."); ctx->rstatus = HTTP_INTERNAL_SERVER_ERROR; if (mpm_supprts_serf) { ap_mpm_register_timed_callback(apr_time_from_msec(1), timed_cleanup_callback, ctx); } return rv; } /** * XXXXX: If I understood serf buckets better, it might be possible to not * copy all of the data here, and better stream it to the client. **/ do { apr_brigade_cleanup(ctx->tmpbb); rv = serf_bucket_read(response, AP_IOBUFSIZE, &data, &len); if (SERF_BUCKET_READ_ERROR(rv)) { ap_log_rerror(APLOG_MARK, APLOG_ERR, rv, ctx->r, APLOGNO(01122) "serf_bucket_read(response)"); return rv; } if (!ctx->done_headers) { serf_bucket_t *hdrs; serf_status_line line; /* TODO: improve */ serf_bucket_response_status(response, &line); ctx->r->status = line.code; hdrs = serf_bucket_response_get_headers(response); serf_bucket_headers_do(hdrs, copy_headers_out, ctx); ctx->done_headers = 1; } if (len > 0) { /* TODO: make APR bucket <-> serf bucket stuff more magical. */ apr_brigade_write(ctx->tmpbb, NULL, NULL, data, len); } if (APR_STATUS_IS_EOF(rv)) { ctx->keep_reading = 0; ctx->rstatus = ap_pass_brigade(ctx->r->output_filters, ctx->tmpbb); if (mpm_supprts_serf) { ap_mpm_register_timed_callback(apr_time_from_msec(1), timed_cleanup_callback, ctx); } return APR_EOF; } ctx->rstatus = ap_pass_brigade(ctx->r->output_filters, ctx->tmpbb); /* XXXX: Should we send a flush now? */ if (APR_STATUS_IS_EAGAIN(rv)) { return APR_SUCCESS; } } while (1); }