diff options
author | Stefan Fritsch <sf@sfritsch.de> | 2011-12-27 19:42:53 +0100 |
---|---|---|
committer | Stefan Fritsch <sf@sfritsch.de> | 2011-12-27 19:42:53 +0100 |
commit | db26b587c04799e75b6dd0fcd4b46aaa168f9161 (patch) | |
tree | 127af2f77fd3eddb75604ebecedeeea163325078 /modules/proxy | |
parent | d9f98b967bedecc0bffe82682d1ed4e06c9df687 (diff) | |
download | apache2-db26b587c04799e75b6dd0fcd4b46aaa168f9161.tar.gz |
Upstream tarball 2.2.15upstream/2.2.15
Diffstat (limited to 'modules/proxy')
-rw-r--r-- | modules/proxy/NWGNUmakefile | 1 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxy | 27 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxyajp | 9 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxybalancer | 10 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxycon | 4 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxyftp | 6 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxyhtp | 7 | ||||
-rw-r--r-- | modules/proxy/NWGNUproxyscgi | 2 | ||||
-rw-r--r-- | modules/proxy/mod_proxy.h | 1 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_ajp.c | 7 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_connect.c | 2 | ||||
-rw-r--r-- | modules/proxy/mod_proxy_http.c | 59 | ||||
-rw-r--r-- | modules/proxy/proxy_util.c | 165 |
13 files changed, 232 insertions, 68 deletions
diff --git a/modules/proxy/NWGNUmakefile b/modules/proxy/NWGNUmakefile index 212a5be7..311282e2 100644 --- a/modules/proxy/NWGNUmakefile +++ b/modules/proxy/NWGNUmakefile @@ -158,6 +158,7 @@ TARGET_nlm = \ $(OBJDIR)/proxyhtp.nlm \ $(OBJDIR)/proxybalancer.nlm \ $(OBJDIR)/proxyajp.nlm \ + $(OBJDIR)/proxyscgi.nlm \ $(EOLIST) # diff --git a/modules/proxy/NWGNUproxy b/modules/proxy/NWGNUproxy index eede5a5c..4d3beee4 100644 --- a/modules/proxy/NWGNUproxy +++ b/modules/proxy/NWGNUproxy @@ -223,16 +223,7 @@ endif # Any symbols exported to here # FILES_nlm_exports = \ - proxy_module \ - proxy_hook_scheme_handler \ - proxy_hook_canon_handler \ - proxy_hook_pre_request \ - proxy_hook_post_request \ - ap_proxy_ssl_enable \ - ap_proxy_ssl_disable \ - ap_proxy_conn_is_https \ - ap_proxy_ssl_val \ - proxy_run_fixups \ + @$(OBJDIR)/mod_proxy.imp \ $(EOLIST) # @@ -248,7 +239,7 @@ FILES_lib_objs = \ libs :: $(OBJDIR) $(TARGET_lib) -nlms :: libs $(TARGET_nlm) +nlms :: libs $(OBJDIR)/mod_proxy.imp $(TARGET_nlm) # # Updated this target to create necessary directories and copy files to the @@ -262,6 +253,20 @@ install :: nlms FORCE vpath %.c ../arch/netware +$(OBJDIR)/mod_proxy.imp: + @echo Creating $@ + @echo # Exports of mod_proxy > $@ + @echo proxy_module, >> $@ + @echo proxy_hook_canon_handler, >> $@ + @echo proxy_hook_post_request, >> $@ + @echo proxy_hook_pre_request, >> $@ + @echo proxy_hook_scheme_handler, >> $@ + @echo proxy_run_fixups, >> $@ + @echo ap_proxy_conn_is_https, >> $@ + @echo ap_proxy_ssl_enable, >> $@ + @echo ap_proxy_ssl_disable, >> $@ + @echo ap_proxy_ssl_val >> $@ + # # Include the 'tail' makefile that has targets that depend on variables defined # in this makefile diff --git a/modules/proxy/NWGNUproxyajp b/modules/proxy/NWGNUproxyajp index 77942ffc..446549f8 100644 --- a/modules/proxy/NWGNUproxyajp +++ b/modules/proxy/NWGNUproxyajp @@ -213,15 +213,8 @@ FILE_nlm_copyright = FILES_nlm_Ximports = \ @$(APR)/aprlib.imp \ @$(NWOS)/httpd.imp \ + @$(OBJDIR)/mod_proxy.imp \ @libc.imp \ - proxy_module \ - proxy_hook_scheme_handler \ - proxy_hook_canon_handler \ - proxy_run_fixups \ - ap_proxy_ssl_enable \ - ap_proxy_ssl_disable \ - ap_proxy_conn_is_https \ - ap_proxy_ssl_val \ $(EOLIST) # Don't link with Winsock if standard sockets are being used diff --git a/modules/proxy/NWGNUproxybalancer b/modules/proxy/NWGNUproxybalancer index c50c48f6..7dc04b8e 100644 --- a/modules/proxy/NWGNUproxybalancer +++ b/modules/proxy/NWGNUproxybalancer @@ -209,16 +209,8 @@ FILE_nlm_copyright = FILES_nlm_Ximports = \ @$(APR)/aprlib.imp \ @$(NWOS)/httpd.imp \ + @$(OBJDIR)/mod_proxy.imp \ @libc.imp \ - proxy_module \ - proxy_hook_scheme_handler \ - proxy_hook_canon_handler \ - proxy_hook_pre_request \ - proxy_hook_post_request \ - proxy_hook_load_lbmethods \ - proxy_run_fixups \ - ap_proxy_ssl_enable \ - ap_proxy_ssl_disable \ $(EOLIST) # Don't link with Winsock if standard sockets are being used diff --git a/modules/proxy/NWGNUproxycon b/modules/proxy/NWGNUproxycon index 6650197b..4ce871cf 100644 --- a/modules/proxy/NWGNUproxycon +++ b/modules/proxy/NWGNUproxycon @@ -208,10 +208,8 @@ FILE_nlm_copyright = FILES_nlm_Ximports = \ @$(APR)/aprlib.imp \ @$(NWOS)/httpd.imp \ + @$(OBJDIR)/mod_proxy.imp \ @libc.imp \ - proxy_module \ - proxy_hook_scheme_handler \ - proxy_hook_canon_handler \ $(EOLIST) # diff --git a/modules/proxy/NWGNUproxyftp b/modules/proxy/NWGNUproxyftp index 89fef5ac..653d9d7b 100644 --- a/modules/proxy/NWGNUproxyftp +++ b/modules/proxy/NWGNUproxyftp @@ -209,12 +209,8 @@ FILE_nlm_copyright = FILES_nlm_Ximports = \ @$(APR)/aprlib.imp \ @$(NWOS)/httpd.imp \ + @$(OBJDIR)/mod_proxy.imp \ @libc.imp \ - proxy_module \ - proxy_hook_scheme_handler \ - proxy_hook_canon_handler \ - ap_proxy_ssl_enable \ - ap_proxy_ssl_disable \ $(EOLIST) # Don't link with Winsock if standard sockets are being used diff --git a/modules/proxy/NWGNUproxyhtp b/modules/proxy/NWGNUproxyhtp index 5f5c2ada..21debea1 100644 --- a/modules/proxy/NWGNUproxyhtp +++ b/modules/proxy/NWGNUproxyhtp @@ -209,13 +209,8 @@ FILE_nlm_copyright = FILES_nlm_Ximports = \ @$(APR)/aprlib.imp \ @$(NWOS)/httpd.imp \ + @$(OBJDIR)/mod_proxy.imp \ @libc.imp \ - proxy_module \ - proxy_hook_scheme_handler \ - proxy_hook_canon_handler \ - proxy_run_fixups \ - ap_proxy_ssl_enable \ - ap_proxy_ssl_disable \ $(EOLIST) # Don't link with Winsock if standard sockets are being used diff --git a/modules/proxy/NWGNUproxyscgi b/modules/proxy/NWGNUproxyscgi index 40d8bb24..4c51621f 100644 --- a/modules/proxy/NWGNUproxyscgi +++ b/modules/proxy/NWGNUproxyscgi @@ -94,7 +94,7 @@ endif # This is used by the link 'name' directive to name the nlm. If left blank # TARGET_nlm (see below) will be used. # -NLM_NAME = proxyscg +NLM_NAME = proxyscgi # # This is used by the link '-desc ' directive. diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 04b71066..358248f1 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -247,6 +247,7 @@ typedef struct { * which the backend currently answers. */ int need_flush;/* Flag to decide whether we need to flush the * filter chain or not */ + void *forward; /* opaque forward proxy data */ } proxy_conn_rec; typedef struct { diff --git a/modules/proxy/mod_proxy_ajp.c b/modules/proxy/mod_proxy_ajp.c index 66693aa9..fa8c41f8 100644 --- a/modules/proxy/mod_proxy_ajp.c +++ b/modules/proxy/mod_proxy_ajp.c @@ -257,7 +257,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "proxy: ap_get_brigade failed"); apr_brigade_destroy(input_brigade); - return HTTP_INTERNAL_SERVER_ERROR; + return HTTP_BAD_REQUEST; } /* have something */ @@ -469,7 +469,9 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, if (ap_pass_brigade(r->output_filters, output_brigade) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "proxy: error processing body"); + "proxy: error processing body.%s", + r->connection->aborted ? + " Client aborted connection." : ""); output_failed = 1; } data_sent = 1; @@ -507,6 +509,7 @@ static int ap_proxy_ajp_request(apr_pool_t *p, request_rec *r, conn->close++; output_failed = 0; result = CMD_AJP13_END_RESPONSE; + request_ended = 1; } /* diff --git a/modules/proxy/mod_proxy_connect.c b/modules/proxy/mod_proxy_connect.c index 8804359c..d66a50d8 100644 --- a/modules/proxy/mod_proxy_connect.c +++ b/modules/proxy/mod_proxy_connect.c @@ -201,7 +201,7 @@ static int proxy_connect_handler(request_rec *r, proxy_worker *worker, return DECLINED; } else { - return HTTP_BAD_GATEWAY; + return HTTP_SERVICE_UNAVAILABLE; } } diff --git a/modules/proxy/mod_proxy_http.c b/modules/proxy/mod_proxy_http.c index 34015263..7e4767f9 100644 --- a/modules/proxy/mod_proxy_http.c +++ b/modules/proxy/mod_proxy_http.c @@ -1369,6 +1369,10 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, {"Keep-Alive", "Proxy-Authenticate", "TE", "Trailer", "Upgrade", NULL}; int i; const char *te = NULL; + int original_status = r->status; + int proxy_status = OK; + const char *original_status_line = r->status_line; + const char *proxy_status_line = NULL; bb = apr_brigade_create(p, c->bucket_alloc); pass_bb = apr_brigade_create(p, c->bucket_alloc); @@ -1482,7 +1486,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, keepchar = buffer[12]; buffer[12] = '\0'; - r->status = atoi(&buffer[9]); + proxy_status = atoi(&buffer[9]); if (keepchar != '\0') { buffer[12] = keepchar; @@ -1493,8 +1497,13 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, buffer[12] = ' '; buffer[13] = '\0'; } - r->status_line = apr_pstrdup(p, &buffer[9]); + proxy_status_line = apr_pstrdup(p, &buffer[9]); + /* The status out of the front is the same as the status coming in + * from the back, until further notice. + */ + r->status = proxy_status; + r->status_line = proxy_status_line; /* read the headers. */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers*/ @@ -1570,7 +1579,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, if ((buf = apr_table_get(r->headers_out, "Content-Type"))) { ap_set_content_type(r, apr_pstrdup(p, buf)); } - if (!ap_is_HTTP_INFO(r->status)) { + if (!ap_is_HTTP_INFO(proxy_status)) { ap_proxy_pre_http_request(origin, rp); } @@ -1621,7 +1630,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, backend->close += 1; } - if (ap_is_HTTP_INFO(r->status)) { + if (ap_is_HTTP_INFO(proxy_status)) { interim_response++; } else { @@ -1660,7 +1669,7 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, * ProxyPassReverse/etc from here to ap_proxy_read_headers */ - if ((r->status == 401) && (conf->error_override)) { + if ((proxy_status == 401) && (conf->error_override)) { const char *buf; const char *wa = "WWW-Authenticate"; if ((buf = apr_table_get(r->headers_out, wa))) { @@ -1700,8 +1709,8 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, /* send body - but only if a body is expected */ if ((!r->header_only) && /* not HEAD request */ !interim_response && /* not any 1xx response */ - (r->status != HTTP_NO_CONTENT) && /* not 204 */ - (r->status != HTTP_NOT_MODIFIED)) { /* not 304 */ + (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ + (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ /* We need to copy the output headers and treat them as input * headers as well. BUT, we need to do this before we remove @@ -1727,11 +1736,22 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, * if we are overriding the errors, we can't put the content * of the page into the brigade */ - if (!conf->error_override || !ap_is_HTTP_ERROR(r->status)) { + if (!conf->error_override || !ap_is_HTTP_ERROR(proxy_status)) { /* read the body, pass it to the output filters */ apr_read_type_e mode = APR_NONBLOCK_READ; int finish = FALSE; + /* Handle the case where the error document is itself reverse + * proxied and was successful. We must maintain any previous + * error status so that an underlying error (eg HTTP_NOT_FOUND) + * doesn't become an HTTP_OK. + */ + if (conf->error_override && !ap_is_HTTP_ERROR(proxy_status) + && ap_is_HTTP_ERROR(original_status)) { + r->status = original_status; + r->status_line = original_status_line; + } + do { apr_off_t readbytes; apr_status_t rv; @@ -1848,25 +1868,27 @@ apr_status_t ap_proxy_http_process_response(apr_pool_t * p, request_rec *r, if (conf->error_override) { /* the code above this checks for 'OK' which is what the hook expects */ - if (!ap_is_HTTP_ERROR(r->status)) + if (!ap_is_HTTP_ERROR(proxy_status)) { return OK; + } else { /* clear r->status for override error, otherwise ErrorDocument * thinks that this is a recursive error, and doesn't find the * custom error page */ - int status = r->status; r->status = HTTP_OK; /* Discard body, if one is expected */ if (!r->header_only && /* not HEAD request */ - (status != HTTP_NO_CONTENT) && /* not 204 */ - (status != HTTP_NOT_MODIFIED)) { /* not 304 */ - ap_discard_request_body(rp); - } - return status; + (proxy_status != HTTP_NO_CONTENT) && /* not 204 */ + (proxy_status != HTTP_NOT_MODIFIED)) { /* not 304 */ + ap_discard_request_body(rp); + } + return proxy_status; } - } else + } + else { return OK; + } } static @@ -1974,10 +1996,7 @@ static int proxy_http_handler(request_rec *r, proxy_worker *worker, /* Step Two: Make the Connection */ if (ap_proxy_connect_backend(proxy_function, backend, worker, r->server)) { - if (r->proxyreq == PROXYREQ_PROXY) - status = HTTP_NOT_FOUND; - else - status = HTTP_SERVICE_UNAVAILABLE; + status = HTTP_SERVICE_UNAVAILABLE; goto cleanup; } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index b835832d..a70a8758 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -29,6 +29,18 @@ #define apr_socket_create apr_socket_create_ex #endif +/* + * Opaque structure containing target server info when + * using a forward proxy. + * Up to now only used in combination with HTTP CONNECT. + */ +typedef struct { + int use_http_connect; /* Use SSL Tunneling via HTTP CONNECT */ + const char *target_host; /* Target hostname */ + apr_port_t target_port; /* Target port */ + const char *proxy_auth; /* Proxy authorization */ +} forward_info; + /* Global balancer counter */ int PROXY_DECLARE_DATA proxy_lb_workers = 0; static int lb_workers_limit = 0; @@ -2085,6 +2097,34 @@ ap_proxy_determine_connection(apr_pool_t *p, request_rec *r, if (proxyname) { conn->hostname = apr_pstrdup(conn->pool, proxyname); conn->port = proxyport; + /* + * If we have a forward proxy and the protocol is HTTPS, + * then we need to prepend a HTTP CONNECT request before + * sending our actual HTTPS requests. + * Save our real backend data for using it later during HTTP CONNECT. + */ + if (conn->is_ssl) { + const char *proxy_auth; + + forward_info *forward = apr_pcalloc(conn->pool, sizeof(forward_info)); + conn->forward = forward; + forward->use_http_connect = 1; + forward->target_host = apr_pstrdup(conn->pool, uri->hostname); + forward->target_port = uri->port; + /* Do we want to pass Proxy-Authorization along? + * If we haven't used it, then YES + * If we have used it then MAYBE: RFC2616 says we MAY propagate it. + * So let's make it configurable by env. + * The logic here is the same used in mod_proxy_http. + */ + proxy_auth = apr_table_get(r->headers_in, "Proxy-Authorization"); + if (proxy_auth != NULL && + proxy_auth[0] != '\0' && + r->user == NULL && /* we haven't yet authenticated */ + apr_table_get(r->subprocess_env, "Proxy-Chain-Auth")) { + forward->proxy_auth = apr_pstrdup(conn->pool, proxy_auth); + } + } } else { conn->hostname = apr_pstrdup(conn->pool, uri->hostname); @@ -2224,6 +2264,102 @@ static int is_socket_connected(apr_socket_t *sock) } #endif /* USE_ALTERNATE_IS_CONNECTED */ + +/* + * Send a HTTP CONNECT request to a forward proxy. + * The proxy is given by "backend", the target server + * is contained in the "forward" member of "backend". + */ +static apr_status_t send_http_connect(proxy_conn_rec *backend, + server_rec *s) +{ + int status; + apr_size_t nbytes; + apr_size_t left; + int complete = 0; + char buffer[HUGE_STRING_LEN]; + char drain_buffer[HUGE_STRING_LEN]; + forward_info *forward = (forward_info *)backend->forward; + int len = 0; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "proxy: CONNECT: sending the CONNECT request for %s:%d " + "to the remote proxy %pI (%s)", + forward->target_host, forward->target_port, + backend->addr, backend->hostname); + /* Create the CONNECT request */ + nbytes = apr_snprintf(buffer, sizeof(buffer), + "CONNECT %s:%d HTTP/1.0" CRLF, + forward->target_host, forward->target_port); + /* Add proxy authorization from the initial request if necessary */ + if (forward->proxy_auth != NULL) { + nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, + "Proxy-Authorization: %s" CRLF, + forward->proxy_auth); + } + /* Set a reasonable agent and send everything */ + nbytes += apr_snprintf(buffer + nbytes, sizeof(buffer) - nbytes, + "Proxy-agent: %s" CRLF CRLF, + ap_get_server_banner()); + apr_socket_send(backend->sock, buffer, &nbytes); + + /* Receive the whole CONNECT response */ + left = sizeof(buffer) - 1; + /* Read until we find the end of the headers or run out of buffer */ + do { + nbytes = left; + status = apr_socket_recv(backend->sock, buffer + len, &nbytes); + len += nbytes; + left -= nbytes; + buffer[len] = '\0'; + if (strstr(buffer + len - nbytes, "\r\n\r\n") != NULL) { + complete = 1; + break; + } + } while (status == APR_SUCCESS && left > 0); + /* Drain what's left */ + if (!complete) { + nbytes = sizeof(drain_buffer) - 1; + while (status == APR_SUCCESS && nbytes) { + status = apr_socket_recv(backend->sock, drain_buffer, &nbytes); + buffer[nbytes] = '\0'; + nbytes = sizeof(drain_buffer) - 1; + if (strstr(drain_buffer, "\r\n\r\n") != NULL) { + complete = 1; + break; + } + } + } + + /* Check for HTTP_OK response status */ + if (status == APR_SUCCESS) { + int major, minor; + /* Only scan for three character status code */ + char code_str[4]; + + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, + "send_http_connect: response from the forward proxy: %s", + buffer); + + /* Extract the returned code */ + if (sscanf(buffer, "HTTP/%u.%u %3s", &major, &minor, code_str) == 3) { + status = atoi(code_str); + if (status == HTTP_OK) { + status = APR_SUCCESS; + } + else { + ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, + "send_http_connect: the forward proxy returned code is '%s'", + code_str); + status = APR_INCOMPLETE; + } + } + } + + return(status); +} + + PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, proxy_conn_rec *conn, proxy_worker *worker, @@ -2336,7 +2472,33 @@ PROXY_DECLARE(int) ap_proxy_connect_backend(const char *proxy_function, apr_socket_timeout_set(newsock, s->timeout); } - conn->sock = newsock; + conn->sock = newsock; + + if (conn->forward) { + forward_info *forward = (forward_info *)conn->forward; + /* + * For HTTP CONNECT we need to prepend CONNECT request before + * sending our actual HTTPS requests. + */ + if (forward->use_http_connect) { + rv = send_http_connect(conn, s); + /* If an error occurred, loop round and try again */ + if (rv != APR_SUCCESS) { + conn->sock = NULL; + apr_socket_close(newsock); + loglevel = backend_addr->next ? APLOG_DEBUG : APLOG_ERR; + ap_log_error(APLOG_MARK, loglevel, rv, s, + "proxy: %s: attempt to connect to %s:%d " + "via http CONNECT through %pI (%s) failed", + proxy_function, + forward->target_host, forward->target_port, + backend_addr, worker->hostname); + backend_addr = backend_addr->next; + continue; + } + } + } + connected = 1; } /* @@ -2516,4 +2678,3 @@ ap_proxy_buckets_lifetime_transform(request_rec *r, apr_bucket_brigade *from, } return rv; } - |