From: Ryan Bloom Date: Fri, 17 Nov 2000 00:19:30 +0000 (+0000) Subject: This removes all BUFF's from the HTTP proxy. This code is relatively X-Git-Tag: APACHE_2_0_ALPHA_8~46 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4baadb8ef1c67c2ca347ddd3648ebf2d9e373f0f;p=apache This removes all BUFF's from the HTTP proxy. This code is relatively ugly, but it does proxy pages. This even fixes the content-type bug that I introduced yesterday sometime. As soon as BUFF is removed from the FTP proxy, the buff.c and buff.h files need to go away. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@86988 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/include/http_protocol.h b/include/http_protocol.h index b56c8225e7..b7a33d97c0 100644 --- a/include/http_protocol.h +++ b/include/http_protocol.h @@ -496,6 +496,8 @@ void ap_finalize_sub_req_protocol(request_rec *sub_r); */ AP_CORE_DECLARE(void) ap_parse_uri(request_rec *r, const char *uri); +AP_CORE_DECLARE(int) ap_getline(char *s, int n, request_rec *r, int fold); + /** * Get the method number associated with the given string, assumed to * contain an HTTP method. Returns M_INVALID if not recognized. diff --git a/modules/http/http_protocol.c b/modules/http/http_protocol.c index 9b359b6e3a..e7f1d35728 100644 --- a/modules/http/http_protocol.c +++ b/modules/http/http_protocol.c @@ -818,7 +818,6 @@ struct dechunk_ctx { }; static long get_chunk_size(char *); -static int getline(char *s, int n, request_rec *r, int fold); apr_status_t ap_dechunk_filter(ap_filter_t *f, ap_bucket_brigade *bb, ap_input_mode_t mode) @@ -841,7 +840,7 @@ apr_status_t ap_dechunk_filter(ap_filter_t *f, ap_bucket_brigade *bb, */ char line[30]; - if ((rv = getline(line, sizeof(line), f->r, 0)) < 0) { + if ((rv = ap_getline(line, sizeof(line), f->r, 0)) < 0) { return rv; } switch(ctx->state) { @@ -1028,7 +1027,7 @@ apr_status_t ap_http_filter(ap_filter_t *f, ap_bucket_brigade *b, ap_input_mode_ * If no LF is detected on the last line due to a dropped connection * or a full buffer, that's considered an error. */ -static int getline(char *s, int n, request_rec *r, int fold) +int ap_getline(char *s, int n, request_rec *r, int fold) { char *pos = s; char *last_char; @@ -1224,7 +1223,7 @@ static int read_request_line(request_rec *r) ap_bsetflag(conn->client, B_SAFEREAD, 1); ap_bflush(conn->client); #endif - while ((len = getline(l, sizeof(l), r, 0)) <= 0) { + while ((len = ap_getline(l, sizeof(l), r, 0)) <= 0) { if (len < 0) { /* includes EOF */ #if 0 /* XXX: I am 99% sure that these are already taken care of, but I want to @@ -1276,7 +1275,7 @@ static int read_request_line(request_rec *r) ap_parse_uri(r, uri); - /* getline returns (size of max buffer - 1) if it fills up the + /* ap_getline returns (size of max buffer - 1) if it fills up the * buffer before finding the end-of-line. This is only going to * happen if it exceeds the configured limit for a request-line. */ @@ -1316,7 +1315,7 @@ static void get_mime_headers(request_rec *r) * Read header lines until we get the empty separator line, a read error, * the connection closes (EOF), reach the server limit, or we timeout. */ - while ((len = getline(field, sizeof(field), r, 1)) > 0) { + while ((len = ap_getline(field, sizeof(field), r, 1)) > 0) { if (r->server->limit_req_fields && (++fields_read > r->server->limit_req_fields)) { @@ -1326,7 +1325,7 @@ static void get_mime_headers(request_rec *r) "this server's limit.

\n"); return; } - /* getline returns (size of max buffer - 1) if it fills up the + /* ap_getline returns (size of max buffer - 1) if it fills up the * buffer before finding the end-of-line. This is only going to * happen if it exceeds the configured limit for a field size. */ @@ -2683,7 +2682,7 @@ AP_DECLARE(int) ap_setup_client_block(request_rec *r, int read_policy) #ifdef AP_DEBUG { - /* Make sure getline() didn't leave any droppings. */ + /* Make sure ap_getline() didn't leave any droppings. */ core_request_config *req_cfg = (core_request_config *)ap_get_module_config(r->request_config, &core_module); diff --git a/modules/proxy/mod_proxy.h b/modules/proxy/mod_proxy.h index 5fde7e2bd0..a5de889595 100644 --- a/modules/proxy/mod_proxy.h +++ b/modules/proxy/mod_proxy.h @@ -255,7 +255,7 @@ char *ap_proxy_canonenc(apr_pool_t *p, const char *x, int len, enum enctype t, char *ap_proxy_canon_netloc(apr_pool_t *p, char **const urlp, char **userp, char **passwordp, char **hostp, int *port); const char *ap_proxy_date_canon(apr_pool_t *p, const char *x); -apr_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f); +apr_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, conn_rec *c); long int ap_proxy_send_fb(proxy_completion *, BUFF *f, request_rec *r, ap_cache_el *c); void ap_proxy_send_headers(request_rec *r, const char *respline, apr_table_t *hdrs); int ap_proxy_liststr(const char *list, const char *val); diff --git a/modules/proxy/proxy_http.c b/modules/proxy/proxy_http.c index c6a4481b23..96652ea092 100644 --- a/modules/proxy/proxy_http.c +++ b/modules/proxy/proxy_http.c @@ -58,10 +58,13 @@ /* HTTP routines for Apache proxy */ +#define CORE_PRIVATE + #include "mod_proxy.h" #include "http_log.h" #include "http_main.h" #include "http_core.h" +#include "http_connection.h" #include "util_date.h" /* @@ -180,11 +183,10 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, apr_table_entry_t *reqhdrs; struct sockaddr_in server; struct in_addr destaddr; - BUFF *f; char buffer[HUGE_STRING_LEN]; + char *buffer2; char portstr[32]; apr_pool_t *p = r->pool; - const long int zero = 0L; int destport = 0; char *destportstr = NULL; const char *urlptr = NULL; @@ -192,7 +194,9 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, apr_ssize_t cntr; apr_file_t *cachefp = NULL; char *buf; - int rbb; + conn_rec *origin; + ap_bucket *e; + ap_bucket_brigade *bb = ap_brigade_create(r->pool); void *sconf = r->server->module_config; proxy_server_conf *conf = @@ -274,24 +278,24 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, desthost, NULL)); } - clear_connection(r->pool, r->headers_in); /* Strip connection-based headers */ + origin = ap_new_apr_connection(r->pool, r->server, sock, 0); + ap_add_output_filter("CORE", NULL, NULL, origin); - f = ap_bcreate(p, B_RDWR); - ap_bpush_socket(f, sock); + clear_connection(r->pool, r->headers_in); /* Strip connection-based headers */ buf = apr_pstrcat(r->pool, r->method, " ", proxyhost ? url : urlptr, " HTTP/1.0" CRLF, NULL); - rbb = strlen(buf); - apr_send(sock, buf, &rbb); + e = ap_bucket_create_pool(buf, strlen(buf), r->pool); + AP_BRIGADE_INSERT_TAIL(bb, e); if (destportstr != NULL && destport != DEFAULT_HTTP_PORT) { buf = apr_pstrcat(r->pool, "Host: ", desthost, ":", destportstr, CRLF, NULL); - rbb = strlen(buf); - apr_send(sock, buf, &rbb); + e = ap_bucket_create_pool(buf, strlen(buf), r->pool); + AP_BRIGADE_INSERT_TAIL(bb, e); } else { buf = apr_pstrcat(r->pool, "Host: ", desthost, CRLF, NULL); - rbb = strlen(buf); - apr_send(sock, buf, &rbb); + e = ap_bucket_create_pool(buf, strlen(buf), r->pool); + AP_BRIGADE_INSERT_TAIL(bb, e); } if (conf->viaopt == via_block) { @@ -333,67 +337,80 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, || !strcasecmp(reqhdrs[i].key, "Proxy-Authorization")) continue; buf = apr_pstrcat(r->pool, reqhdrs[i].key, ": ", reqhdrs[i].val, CRLF, NULL); - rbb = strlen(buf); - apr_send(sock, buf, &rbb); + e = ap_bucket_create_pool(buf, strlen(buf), r->pool); + AP_BRIGADE_INSERT_TAIL(bb, e); } - rbb = strlen(CRLF); - apr_send(sock, CRLF, &rbb); + e = ap_bucket_create_pool(CRLF, strlen(CRLF), r->pool); + AP_BRIGADE_INSERT_TAIL(bb, e); + e = ap_bucket_create_flush(); + AP_BRIGADE_INSERT_TAIL(bb, e); + + ap_pass_brigade(origin->output_filters, bb); /* send the request data, if any. */ if (ap_should_client_block(r)) { while ((i = ap_get_client_block(r, buffer, sizeof buffer)) > 0) { - cntr = i; - apr_send(sock, buffer, &cntr); + e = ap_bucket_create_pool(buffer, i, r->pool); + AP_BRIGADE_INSERT_TAIL(bb, e); } } -#if 0 /* This doesn't make any sense until we convert the raw socket calls - * to filters. - */ - ap_bflush(f); -#endif - - len = ap_bgets(buffer, sizeof buffer - 1, f); + /* Flush the data to the origin server */ + e = ap_bucket_create_flush(); + AP_BRIGADE_INSERT_TAIL(bb, e); + ap_pass_brigade(origin->output_filters, bb); + + ap_add_input_filter("HTTP", NULL, NULL, origin); + ap_add_input_filter("CORE_IN", NULL, NULL, origin); + + ap_brigade_destroy(bb); + bb = ap_brigade_create(r->pool); + + /* Tell http_filter to grab the data one line at a time. */ + origin->remain = 0; + + ap_get_brigade(origin->input_filters, bb, AP_MODE_BLOCKING); + ap_bucket_read(AP_BRIGADE_FIRST(bb), (const char **)&buffer2, &len, AP_BLOCK_READ); if (len == -1) { - ap_bclose(f); + apr_close_socket(sock); ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, - "ap_bgets() - proxy receive - Error reading from remote server %s (length %d)", + "ap_get_brigade() - proxy receive - Error reading from remote server %s (length %d)", proxyhost ? proxyhost : desthost, len); return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Error reading from remote server"); } else if (len == 0) { - ap_bclose(f); + apr_close_socket(sock); return ap_proxyerror(r, HTTP_BAD_GATEWAY, "Document contains no data"); } /* Is it an HTTP/1 response? This is buggy if we ever see an HTTP/1.10 */ - if (ap_checkmask(buffer, "HTTP/#.# ###*")) { + if (ap_checkmask(buffer2, "HTTP/#.# ###*")) { int major, minor; - if (2 != sscanf(buffer, "HTTP/%u.%u", &major, &minor)) { + if (2 != sscanf(buffer2, "HTTP/%u.%u", &major, &minor)) { major = 1; minor = 0; } /* If not an HTTP/1 message or if the status line was > 8192 bytes */ - if (buffer[5] != '1' || buffer[len - 1] != '\n') { - ap_bclose(f); + if (buffer2[5] != '1' || buffer2[len - 1] != '\n') { + apr_close_socket(sock); return HTTP_BAD_GATEWAY; } backasswards = 0; - buffer[--len] = '\0'; + buffer2[--len] = '\0'; - buffer[12] = '\0'; - r->status = atoi(&buffer[9]); - buffer[12] = ' '; - r->status_line = apr_pstrdup(p, &buffer[9]); + buffer2[12] = '\0'; + r->status = atoi(&buffer2[9]); + buffer2[12] = ' '; + r->status_line = apr_pstrdup(p, &buffer2[9]); /* read the headers. */ /* N.B. for HTTP/1.0 clients, we have to fold line-wrapped headers */ /* Also, take care with headers with multiple occurences. */ - resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, f); + resp_hdrs = ap_proxy_read_headers(r, buffer, HUGE_STRING_LEN, origin); if (resp_hdrs == NULL) { ap_log_error(APLOG_MARK, APLOG_WARNING|APLOG_NOERRNO, 0, r->server, "proxy: Bad HTTP/%d.%d header returned by %s (%s)", @@ -475,21 +492,17 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, /* send headers */ ap_cache_el_header_walk(c, ap_proxy_send_hdr_line, r, NULL); -#if 0 if (!r->assbackwards) ap_rputs(CRLF, r); -#endif -/* We don't set byte count this way anymore. I think this can be removed - * cleanly now. - ap_bsetopt(r->connection->client, BO_BYTECT, &zero); -*/ r->sent_bodyct = 1; /* Is it an HTTP/0.9 response? If so, send the extra data */ if (backasswards) { cntr = len; apr_send(r->connection->client_socket, buffer, &cntr); cntr = len; + e = ap_bucket_create_heap(buffer, cntr, 0, NULL); + AP_BRIGADE_INSERT_TAIL(bb, e); if (cachefp && apr_write(cachefp, buffer, &cntr) != APR_SUCCESS) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "proxy: error writing extra data to cache"); @@ -497,25 +510,25 @@ int ap_proxy_http_handler(request_rec *r, ap_cache_el *c, char *url, } } -#ifdef CHARSET_EBCDIC - /* What we read/write after the header should not be modified - * (i.e., the cache copy is ASCII, not EBCDIC, even for text/html) - */ - ap_bsetflag(f, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0); - ap_bsetflag(r->connection->client, B_ASCII2EBCDIC|B_EBCDIC2ASCII, 0); -#endif - - /* send body */ - /* if header only, then cache will be NULL */ - /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */ + /* send body */ + /* if header only, then cache will be NULL */ + /* HTTP/1.0 tells us to read to EOF, rather than content-length bytes */ if (!r->header_only) { - proxy_completion pc; - pc.content_length = content_length; - pc.cache_completion = conf->cache_completion; - ap_proxy_send_fb(&pc, f, r, c); + proxy_completion pc; + pc.content_length = content_length; + pc.cache_completion = conf->cache_completion; + + origin->remain = content_length; + while (ap_get_brigade(origin->input_filters, bb, AP_MODE_BLOCKING) == APR_SUCCESS) { + if (AP_BUCKET_IS_EOS(AP_BRIGADE_LAST(bb))) { + ap_pass_brigade(r->output_filters, bb); + break; + } + ap_pass_brigade(r->output_filters, bb); + } } - ap_bclose(f); + apr_close_socket(sock); if(c) ap_proxy_cache_update(c); return OK; } diff --git a/modules/proxy/proxy_util.c b/modules/proxy/proxy_util.c index 8466251605..f29fbc0c1c 100644 --- a/modules/proxy/proxy_util.c +++ b/modules/proxy/proxy_util.c @@ -56,13 +56,17 @@ * University of Illinois, Urbana-Champaign. */ +#define CORE_PRIVATE + /* Utility routines for Apache proxy */ #include "mod_proxy.h" +#include "http_core.h" #include "http_main.h" #include "http_log.h" #include "util_uri.h" #include "util_date.h" /* get ap_checkmask() decl. */ #include "apr_md5.h" +#include "apr_pools.h" static int proxy_match_ipaddr(struct dirconn_entry *This, request_rec *r); static int proxy_match_domainname(struct dirconn_entry *This, request_rec *r); @@ -364,64 +368,33 @@ const char * return q; } - -/* NOTE: This routine is taken from http_protocol::getline() - * because the old code found in the proxy module was too - * difficult to understand and maintain. - */ -/* Get a line of protocol input, including any continuation lines - * caused by MIME folding (or broken clients) if fold != 0, and place it - * in the buffer s, of size n bytes, without the ending newline. - * - * Returns -1 on error, or the length of s. - * - * Note: Because bgets uses 1 char for newline and 1 char for NUL, - * the most we can get is (n - 2) actual characters if it - * was ended by a newline, or (n - 1) characters if the line - * length exceeded (n - 1). So, if the result == (n - 1), - * then the actual input line exceeded the buffer length, - * and it would be a good idea for the caller to puke 400 or 414. - */ -static int proxy_getline(char *s, int n, BUFF *in, int fold) +static request_rec *make_fake_req(conn_rec *c) { - char *pos, next; - int retval; - int total = 0; - - pos = s; + request_rec *r = apr_pcalloc(c->pool, sizeof(*r)); + core_request_config *req_cfg; - do { - retval = ap_bgets(pos, n, in); /* retval == -1 if error, 0 if EOF */ + r->pool = c->pool; + r->status = HTTP_OK; - if (retval <= 0) - return ((retval < 0) && (total == 0)) ? -1 : total; + r->headers_in = apr_make_table(r->pool, 50); + r->subprocess_env = apr_make_table(r->pool, 50); + r->headers_out = apr_make_table(r->pool, 12); + r->err_headers_out = apr_make_table(r->pool, 5); + r->notes = apr_make_table(r->pool, 5); - /* retval is the number of characters read, not including NUL */ + r->read_body = REQUEST_NO_BODY; + r->connection = c; + r->output_filters = c->output_filters; + r->input_filters = c->input_filters; - n -= retval; /* Keep track of how much of s is full */ - pos += (retval - 1); /* and where s ends */ - total += retval; /* and how long s has become */ + r->request_config = ap_create_request_config(r->pool); + req_cfg = apr_pcalloc(r->pool, sizeof(core_request_config)); + req_cfg->bb = ap_brigade_create(r->pool); + ap_set_module_config(r->request_config, &core_module, req_cfg); - if (*pos == '\n') { /* Did we get a full line of input? */ - *pos = '\0'; - --total; - ++n; - } - else - return total; /* if not, input line exceeded buffer size */ - - /* Continue appending if line folding is desired and - * the last line was not empty and we have room in the buffer and - * the next line begins with a continuation character. - */ - } while (fold && (retval != 1) && (n > 1) - && (next = ap_blookc(in)) - && ((next == ' ') || (next == '\t'))); - - return total; + return r; } - /* * Reads headers from a buffer and returns an array of headers. * Returns NULL on file error @@ -429,12 +402,13 @@ static int proxy_getline(char *s, int n, BUFF *in, int fold) * @@@: XXX: FIXME: currently the headers are passed thru un-merged. * Is that okay, or should they be collapsed where possible? */ -apr_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF *f) +apr_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, conn_rec *c) { apr_table_t *resp_hdrs; int len; char *value, *end; char field[MAX_STRING_LEN]; + request_rec *rr = make_fake_req(c); resp_hdrs = ap_make_table(r->pool, 20); @@ -442,7 +416,7 @@ apr_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF * Read header lines until we get the empty separator line, a read error, * the connection closes (EOF), or we timeout. */ - while ((len = proxy_getline(buffer, size, f, 1)) > 0) { + while ((len = ap_getline(buffer, size, rr, 1)) > 0) { if (!(value = strchr(buffer, ':'))) { /* Find the colon separator */ @@ -479,7 +453,7 @@ apr_table_t *ap_proxy_read_headers(request_rec *r, char *buffer, int size, BUFF /* the header was too long; at the least we should skip extra data */ if (len >= size - 1) { - while ((len = proxy_getline(field, MAX_STRING_LEN, f, 1)) + while ((len = ap_getline(field, MAX_STRING_LEN, r, 1)) >= MAX_STRING_LEN - 1) { /* soak up the extra data */ }