/* Read the headers of the response and try the available handlers if authentication or validation is needed. */ apr_status_t serf__handle_auth_response(int *consumed_response, serf_request_t *request, serf_bucket_t *response, void *baton, apr_pool_t *pool) { apr_status_t status; serf_status_line sl; *consumed_response = 0; /* TODO: the response bucket was created by the application, not at all guaranteed that this is of type response_bucket!! */ status = serf_bucket_response_status(response, &sl); if (SERF_BUCKET_READ_ERROR(status)) { return status; } if (!sl.version && (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_EAGAIN(status))) { return status; } status = serf_bucket_response_wait_for_headers(response); if (status) { if (!APR_STATUS_IS_EOF(status)) { return status; } /* If status is APR_EOF, there were no headers to read. This can be ok in some situations, and it definitely means there's no authentication requested now. */ return APR_SUCCESS; } if (sl.code == 401 || sl.code == 407) { /* Authentication requested. */ /* Don't bother handling the authentication request if the response wasn't received completely yet. Serf will call serf__handle_auth_response again when more data is received. */ status = discard_body(response); *consumed_response = 1; /* Discard all response body before processing authentication. */ if (!APR_STATUS_IS_EOF(status)) { return status; } status = dispatch_auth(sl.code, request, response, baton, pool); if (status != APR_SUCCESS) { return status; } /* Requeue the request with the necessary auth headers. */ /* ### Application doesn't know about this request! */ if (request->ssltunnel) { serf__ssltunnel_request_create(request->conn, request->setup, request->setup_baton); } else { serf_connection_priority_request_create(request->conn, request->setup, request->setup_baton); } return APR_EOF; } else { serf__validate_response_func_t validate_resp; serf_connection_t *conn = request->conn; serf_context_t *ctx = conn->ctx; serf__authn_info_t *authn_info; apr_status_t resp_status = APR_SUCCESS; /* Validate the response server authn headers. */ authn_info = serf__get_authn_info_for_server(conn); if (authn_info->scheme) { validate_resp = authn_info->scheme->validate_response_func; resp_status = validate_resp(authn_info->scheme, HOST, sl.code, conn, request, response, pool); } /* Validate the response proxy authn headers. */ authn_info = &ctx->proxy_authn_info; if (!resp_status && authn_info->scheme) { validate_resp = authn_info->scheme->validate_response_func; resp_status = validate_resp(authn_info->scheme, PROXY, sl.code, conn, request, response, pool); } if (resp_status) { /* If there was an error in the final step of the authentication, consider the reponse body as invalid and discard it. */ status = discard_body(response); *consumed_response = 1; if (!APR_STATUS_IS_EOF(status)) { return status; } /* The whole body was discarded, now return our error. */ return resp_status; } } return APR_SUCCESS; }
/* If a 200 OK was received for the CONNECT request, consider the connection as ready for use. */ static apr_status_t handle_response(serf_request_t *request, serf_bucket_t *response, void *handler_baton, apr_pool_t *pool) { apr_status_t status; serf_status_line sl; req_ctx_t *ctx = handler_baton; serf_connection_t *conn = request->conn; /* CONNECT request was cancelled. Assuming that this is during connection reset, we can safely discard the request as a new one will be created when setting up the next connection. */ if (!response) return APR_SUCCESS; status = serf_bucket_response_status(response, &sl); if (SERF_BUCKET_READ_ERROR(status)) { return status; } if (!sl.version && (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_EAGAIN(status))) { return status; } status = serf_bucket_response_wait_for_headers(response); if (status && !APR_STATUS_IS_EOF(status)) { return status; } /* RFC 2817: Any successful (2xx) response to a CONNECT request indicates that the proxy has established a connection to the requested host and port, and has switched to tunneling the current connection to that server connection. */ if (sl.code >= 200 && sl.code < 300) { serf_bucket_t *hdrs; const char *val; conn->state = SERF_CONN_CONNECTED; /* Body is supposed to be empty. */ apr_pool_destroy(ctx->pool); serf_bucket_destroy(conn->ssltunnel_ostream); serf_bucket_destroy(conn->stream); conn->stream = NULL; ctx = NULL; serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, "successfully set up ssl tunnel.\n"); /* Fix for issue #123: ignore the "Connection: close" header here, leaving the header in place would make the serf's main context loop close this connection immediately after reading the 200 OK response. */ hdrs = serf_bucket_response_get_headers(response); val = serf_bucket_headers_get(hdrs, "Connection"); if (val && strcasecmp("close", val) == 0) { serf__log_skt(CONN_VERBOSE, __FILE__, conn->skt, "Ignore Connection: close header on this reponse, don't " "close the connection now that the tunnel is set up.\n"); serf__bucket_headers_remove(hdrs, "Connection"); } return APR_EOF; } /* Authentication failure and 2xx Ok are handled at this point, the rest are errors. */ return SERF_ERROR_SSLTUNNEL_SETUP_FAILED; }
/* Read the headers of the response and try the available handlers if authentication or validation is needed. */ apr_status_t serf__handle_auth_response(int *consumed_response, serf_request_t *request, serf_bucket_t *response, void *baton, apr_pool_t *pool) { apr_status_t status; serf_status_line sl; *consumed_response = 0; status = serf_bucket_response_status(response, &sl); if (SERF_BUCKET_READ_ERROR(status)) { return status; } if (!sl.version && (APR_STATUS_IS_EOF(status) || APR_STATUS_IS_EAGAIN(status))) { return status; } status = serf_bucket_response_wait_for_headers(response); if (status) { if (!APR_STATUS_IS_EOF(status)) { return status; } /* If status is APR_EOF, there were no headers to read. This can be ok in some situations, and it definitely means there's no authentication requested now. */ return APR_SUCCESS; } if (sl.code == 401 || sl.code == 407) { /* Authentication requested. */ /* Don't bother handling the authentication request if the response wasn't received completely yet. Serf will call serf__handle_auth_response again when more data is received. */ status = discard_body(response); *consumed_response = 1; /* Discard all response body before processing authentication. */ if (!APR_STATUS_IS_EOF(status)) { return status; } status = dispatch_auth(sl.code, request, response, baton, pool); if (status != APR_SUCCESS) { return status; } /* Requeue the request with the necessary auth headers. */ /* ### Application doesn't know about this request! */ serf_connection_priority_request_create(request->conn, request->setup, request->setup_baton); return APR_EOF; } return APR_SUCCESS; }