📄 http_filters.c
字号:
/* no such thing as a response protocol */ return; } validate_status_line(r); if (!r->status_line) { r->status_line = ap_get_status_line(r->status); } /* Note that we must downgrade before checking for force responses. */ if (r->proto_num > HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "downgrade-1.0")) { r->proto_num = HTTP_VERSION(1,0); } /* kludge around broken browsers when indicated by force-response-1.0 */ if (r->proto_num == HTTP_VERSION(1,0) && apr_table_get(r->subprocess_env, "force-response-1.0")) { *protocol = "HTTP/1.0"; r->connection->keepalive = AP_CONN_CLOSE; } else { *protocol = AP_SERVER_PROTOCOL; }}/* fill "bb" with a barebones/initial HTTP response header */static void basic_http_header(request_rec *r, apr_bucket_brigade *bb, const char *protocol){ char *date; const char *server; header_struct h; struct iovec vec[4]; if (r->assbackwards) { /* there are no headers to send */ return; } /* Output the HTTP/1.x Status-Line and the Date and Server fields */ vec[0].iov_base = (void *)protocol; vec[0].iov_len = strlen(protocol); vec[1].iov_base = (void *)" "; vec[1].iov_len = sizeof(" ") - 1; vec[2].iov_base = (void *)(r->status_line); vec[2].iov_len = strlen(r->status_line); vec[3].iov_base = (void *)CRLF; vec[3].iov_len = sizeof(CRLF) - 1;#if APR_CHARSET_EBCDIC { char *tmp; apr_size_t len; tmp = apr_pstrcatv(r->pool, vec, 4, &len); ap_xlate_proto_to_ascii(tmp, len); apr_brigade_write(bb, NULL, NULL, tmp, len); }#else apr_brigade_writev(bb, NULL, NULL, vec, 4);#endif h.pool = r->pool; h.bb = bb; /* * keep the set-by-proxy server and date headers, otherwise * generate a new server header / date header */ if (r->proxyreq != PROXYREQ_NONE) { const char *proxy_date; proxy_date = apr_table_get(r->headers_out, "Date"); if (!proxy_date) { /* * proxy_date needs to be const. So use date for the creation of * our own Date header and pass it over to proxy_date later to * avoid a compiler warning. */ date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); proxy_date = date; } form_header_field(&h, "Date", proxy_date); server = apr_table_get(r->headers_out, "Server"); if (server) { form_header_field(&h, "Server", server); } } else { date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); form_header_field(&h, "Date", date); form_header_field(&h, "Server", ap_get_server_banner()); } /* unset so we don't send them again */ apr_table_unset(r->headers_out, "Date"); /* Avoid bogosity */ apr_table_unset(r->headers_out, "Server");}AP_DECLARE(void) ap_basic_http_header(request_rec *r, apr_bucket_brigade *bb){ const char *protocol; basic_http_header_check(r, &protocol); basic_http_header(r, bb, protocol);}/* Navigator versions 2.x, 3.x and 4.0 betas up to and including 4.0b2 * have a header parsing bug. If the terminating \r\n occur starting * at offset 256, 257 or 258 of output then it will not properly parse * the headers. Curiously it doesn't exhibit this problem at 512, 513. * We are guessing that this is because their initial read of a new request * uses a 256 byte buffer, and subsequent reads use a larger buffer. * So the problem might exist at different offsets as well. * * This should also work on keepalive connections assuming they use the * same small buffer for the first read of each new request. * * At any rate, we check the bytes written so far and, if we are about to * tickle the bug, we instead insert a bogus padding header. Since the bug * manifests as a broken image in Navigator, users blame the server. :( * It is more expensive to check the User-Agent than it is to just add the * bytes, so we haven't used the BrowserMatch feature here. */static void terminate_header(apr_bucket_brigade *bb){ char tmp[] = "X-Pad: avoid browser bug" CRLF; char crlf[] = CRLF; apr_off_t len; apr_size_t buflen; (void) apr_brigade_length(bb, 1, &len); if (len >= 255 && len <= 257) { buflen = strlen(tmp); ap_xlate_proto_to_ascii(tmp, buflen); apr_brigade_write(bb, NULL, NULL, tmp, buflen); } buflen = strlen(crlf); ap_xlate_proto_to_ascii(crlf, buflen); apr_brigade_write(bb, NULL, NULL, crlf, buflen);}AP_DECLARE_NONSTD(int) ap_send_http_trace(request_rec *r){ core_server_config *conf; int rv; apr_bucket_brigade *bb; header_struct h; apr_bucket *b; int body; char *bodyread = NULL, *bodyoff; apr_size_t bodylen = 0; apr_size_t bodybuf; long res = -1; /* init to avoid gcc -Wall warning */ if (r->method_number != M_TRACE) { return DECLINED; } /* Get the original request */ while (r->prev) { r = r->prev; } conf = (core_server_config *)ap_get_module_config(r->server->module_config, &core_module); if (conf->trace_enable == AP_TRACE_DISABLE) { apr_table_setn(r->notes, "error-notes", "TRACE denied by server configuration"); return HTTP_METHOD_NOT_ALLOWED; } if (conf->trace_enable == AP_TRACE_EXTENDED) /* XX should be = REQUEST_CHUNKED_PASS */ body = REQUEST_CHUNKED_DECHUNK; else body = REQUEST_NO_BODY; if ((rv = ap_setup_client_block(r, body))) { if (rv == HTTP_REQUEST_ENTITY_TOO_LARGE) apr_table_setn(r->notes, "error-notes", "TRACE with a request body is not allowed"); return rv; } if (ap_should_client_block(r)) { if (r->remaining > 0) { if (r->remaining > 65536) { apr_table_setn(r->notes, "error-notes", "Extended TRACE request bodies cannot exceed 64k\n"); return HTTP_REQUEST_ENTITY_TOO_LARGE; } /* always 32 extra bytes to catch chunk header exceptions */ bodybuf = (apr_size_t)r->remaining + 32; } else { /* Add an extra 8192 for chunk headers */ bodybuf = 73730; } bodyoff = bodyread = apr_palloc(r->pool, bodybuf); /* only while we have enough for a chunked header */ while ((!bodylen || bodybuf >= 32) && (res = ap_get_client_block(r, bodyoff, bodybuf)) > 0) { bodylen += res; bodybuf -= res; bodyoff += res; } if (res > 0 && bodybuf < 32) { /* discard_rest_of_request_body into our buffer */ while (ap_get_client_block(r, bodyread, bodylen) > 0) ; apr_table_setn(r->notes, "error-notes", "Extended TRACE request bodies cannot exceed 64k\n"); return HTTP_REQUEST_ENTITY_TOO_LARGE; } if (res < 0) { return HTTP_BAD_REQUEST; } } ap_set_content_type(r, "message/http"); /* Now we recreate the request, and echo it back */ bb = apr_brigade_create(r->pool, r->connection->bucket_alloc);#if APR_CHARSET_EBCDIC { char *tmp; apr_size_t len; len = strlen(r->the_request); tmp = apr_pmemdup(r->pool, r->the_request, len); ap_xlate_proto_to_ascii(tmp, len); apr_brigade_putstrs(bb, NULL, NULL, tmp, CRLF_ASCII, NULL); }#else apr_brigade_putstrs(bb, NULL, NULL, r->the_request, CRLF, NULL);#endif h.pool = r->pool; h.bb = bb; apr_table_do((int (*) (void *, const char *, const char *)) form_header_field, (void *) &h, r->headers_in, NULL); apr_brigade_puts(bb, NULL, NULL, CRLF_ASCII); /* If configured to accept a body, echo the body */ if (bodylen) { b = apr_bucket_pool_create(bodyread, bodylen, r->pool, bb->bucket_alloc); APR_BRIGADE_INSERT_TAIL(bb, b); } ap_pass_brigade(r->output_filters, bb); return DONE;}typedef struct header_filter_ctx { int headers_sent;} header_filter_ctx;AP_CORE_DECLARE_NONSTD(apr_status_t) ap_http_header_filter(ap_filter_t *f, apr_bucket_brigade *b){ request_rec *r = f->r; conn_rec *c = r->connection; const char *clheader; const char *protocol; apr_bucket *e; apr_bucket_brigade *b2; header_struct h; header_filter_ctx *ctx = f->ctx; const char *ctype; ap_bucket_error *eb = NULL; AP_DEBUG_ASSERT(!r->main); if (r->header_only) { if (!ctx) { ctx = f->ctx = apr_pcalloc(r->pool, sizeof(header_filter_ctx)); } else if (ctx->headers_sent) { apr_brigade_destroy(b); return OK; } } for (e = APR_BRIGADE_FIRST(b); e != APR_BRIGADE_SENTINEL(b); e = APR_BUCKET_NEXT(e)) { if (AP_BUCKET_IS_ERROR(e) && !eb) { eb = e->data; continue; } /* * If we see an EOC bucket it is a signal that we should get out * of the way doing nothing. */ if (AP_BUCKET_IS_EOC(e)) { ap_remove_output_filter(f); return ap_pass_brigade(f->next, b); } } if (eb) { int status; status = eb->status; apr_brigade_cleanup(b); ap_die(status, r); return AP_FILTER_ERROR; } if (r->assbackwards) { r->sent_bodyct = 1; ap_remove_output_filter(f); return ap_pass_brigade(f->next, b); } /* * Now that we are ready to send a response, we need to combine the two * header field tables into a single table. If we don't do this, our * later attempts to set or unset a given fieldname might be bypassed. */ if (!apr_is_empty_table(r->err_headers_out)) { r->headers_out = apr_table_overlay(r->pool, r->err_headers_out, r->headers_out); } /* * Remove the 'Vary' header field if the client can't handle it. * Since this will have nasty effects on HTTP/1.1 caches, force * the response into HTTP/1.0 mode. * * Note: the force-response-1.0 should come before the call to * basic_http_header_check() */ if (apr_table_get(r->subprocess_env, "force-no-vary") != NULL) { apr_table_unset(r->headers_out, "Vary"); r->proto_num = HTTP_VERSION(1,0); apr_table_set(r->subprocess_env, "force-response-1.0", "1"); } else { fixup_vary(r); } /* * Now remove any ETag response header field if earlier processing * says so (such as a 'FileETag None' directive). */ if (apr_table_get(r->notes, "no-etag") != NULL) { apr_table_unset(r->headers_out, "ETag"); } /* determine the protocol and whether we should use keepalives. */ basic_http_header_check(r, &protocol); ap_set_keepalive(r); if (r->chunked) { apr_table_mergen(r->headers_out, "Transfer-Encoding", "chunked"); apr_table_unset(r->headers_out, "Content-Length"); } ctype = ap_make_content_type(r, r->content_type); if (strcasecmp(ctype, NO_CONTENT_TYPE)) { apr_table_setn(r->headers_out, "Content-Type", ctype); } if (r->content_encoding) { apr_table_setn(r->headers_out, "Content-Encoding", r->content_encoding); } if (!apr_is_empty_array(r->content_languages)) { int i; char *token; char **languages = (char **)(r->content_languages->elts); const char *field = apr_table_get(r->headers_out, "Content-Language"); while (field && (token = ap_get_list_item(r->pool, &field)) != NULL) { for (i = 0; i < r->content_languages->nelts; ++i) { if (!strcasecmp(token, languages[i])) break; } if (i == r->content_languages->nelts) { *((char **) apr_array_push(r->content_languages)) = token; } } field = apr_array_pstrcat(r->pool, r->content_languages, ','); apr_table_setn(r->headers_out, "Content-Language", field); } /* * Control cachability for non-cachable responses if not already set by * some other part of the server configuration. */ if (r->no_cache && !apr_table_get(r->headers_out, "Expires")) { char *date = apr_palloc(r->pool, APR_RFC822_DATE_LEN); ap_recent_rfc822_date(date, r->request_time); apr_table_addn(r->headers_out, "Expires", date); } /* This is a hack, but I can't find anyway around it. The idea is that
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -