📄 http_request.c
字号:
/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *//* * http_request.c: functions to get and process requests * * Rob McCool 3/21/93 * * Thoroughly revamped by rst for Apache. NB this file reads * best from the bottom up. * */#include "apr_strings.h"#include "apr_file_io.h"#include "apr_fnmatch.h"#define APR_WANT_STRFUNC#include "apr_want.h"#define CORE_PRIVATE#include "ap_config.h"#include "httpd.h"#include "http_config.h"#include "http_request.h"#include "http_core.h"#include "http_protocol.h"#include "http_log.h"#include "http_main.h"#include "util_filter.h"#include "util_charset.h"#include "scoreboard.h"#include "mod_core.h"#if APR_HAVE_STDARG_H#include <stdarg.h>#endif/***************************************************************** * * Mainline request processing... *//* XXX A cleaner and faster way to do this might be to pass the request_rec * down the filter chain as a parameter. It would need to change for * subrequest vs. main request filters; perhaps the subrequest filter could * make the switch. */static void update_r_in_filters(ap_filter_t *f, request_rec *from, request_rec *to){ while (f) { if (f->r == from) { f->r = to; } f = f->next; }}AP_DECLARE(void) ap_die(int type, request_rec *r){ int error_index = ap_index_of_response(type); char *custom_response = ap_response_code_string(r, error_index); int recursive_error = 0; request_rec *r_1st_err = r; if (type == AP_FILTER_ERROR) { ap_filter_t *next; /* * Check if we still have the ap_http_header_filter in place. If * this is the case we should not ignore AP_FILTER_ERROR here because * it means that we have not sent any response at all and never * will. This is bad. Sent an internal server error instead. */ next = r->output_filters; while (next && (next->frec != ap_http_header_filter_handle)) { next = next->next; } /* * If next != NULL then we left the while above because of * next->frec == ap_http_header_filter */ if (next) { ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Custom error page caused AP_FILTER_ERROR"); type = HTTP_INTERNAL_SERVER_ERROR; } else { return; } } if (type == DONE) { ap_finalize_request_protocol(r); return; } /* * The following takes care of Apache redirects to custom response URLs * Note that if we are already dealing with the response to some other * error condition, we just report on the original error, and give up on * any attempt to handle the other thing "intelligently"... */ if (r->status != HTTP_OK) { recursive_error = type; while (r_1st_err->prev && (r_1st_err->prev->status != HTTP_OK)) r_1st_err = r_1st_err->prev; /* Get back to original error */ if (r_1st_err != r) { /* The recursive error was caused by an ErrorDocument specifying * an internal redirect to a bad URI. ap_internal_redirect has * changed the filter chains to point to the ErrorDocument's * request_rec. Back out those changes so we can safely use the * original failing request_rec to send the canned error message. * * ap_send_error_response gets rid of existing resource filters * on the output side, so we can skip those. */ update_r_in_filters(r_1st_err->proto_output_filters, r, r_1st_err); update_r_in_filters(r_1st_err->input_filters, r, r_1st_err); } custom_response = NULL; /* Do NOT retry the custom thing! */ } r->status = type; /* * This test is done here so that none of the auth modules needs to know * about proxy authentication. They treat it like normal auth, and then * we tweak the status. */ if (HTTP_UNAUTHORIZED == r->status && PROXYREQ_PROXY == r->proxyreq) { r->status = HTTP_PROXY_AUTHENTICATION_REQUIRED; } /* If we don't want to keep the connection, make sure we mark that the * connection is not eligible for keepalive. If we want to keep the * connection, be sure that the request body (if any) has been read. */ if (ap_status_drops_connection(r->status)) { r->connection->keepalive = AP_CONN_CLOSE; } /* * Two types of custom redirects --- plain text, and URLs. Plain text has * a leading '"', so the URL code, here, is triggered on its absence */ if (custom_response && custom_response[0] != '"') { if (ap_is_url(custom_response)) { /* * The URL isn't local, so lets drop through the rest of this * apache code, and continue with the usual REDIRECT handler. * But note that the client will ultimately see the wrong * status... */ r->status = HTTP_MOVED_TEMPORARILY; apr_table_setn(r->headers_out, "Location", custom_response); } else if (custom_response[0] == '/') { const char *error_notes; r->no_local_copy = 1; /* Do NOT send HTTP_NOT_MODIFIED for * error documents! */ /* * This redirect needs to be a GET no matter what the original * method was. */ apr_table_setn(r->subprocess_env, "REQUEST_METHOD", r->method); /* * Provide a special method for modules to communicate * more informative (than the plain canned) messages to us. * Propagate them to ErrorDocuments via the ERROR_NOTES variable: */ if ((error_notes = apr_table_get(r->notes, "error-notes")) != NULL) { apr_table_setn(r->subprocess_env, "ERROR_NOTES", error_notes); } r->method = apr_pstrdup(r->pool, "GET"); r->method_number = M_GET; ap_internal_redirect(custom_response, r); return; } else { /* * Dumb user has given us a bad url to redirect to --- fake up * dying with a recursive server error... */ recursive_error = HTTP_INTERNAL_SERVER_ERROR; ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r, "Invalid error redirection directive: %s", custom_response); } } ap_send_error_response(r_1st_err, recursive_error);}static void check_pipeline_flush(request_rec *r){ apr_bucket *e; apr_bucket_brigade *bb; conn_rec *c = r->connection; /* ### if would be nice if we could PEEK without a brigade. that would ### allow us to defer creation of the brigade to when we actually ### need to send a FLUSH. */ bb = apr_brigade_create(r->pool, c->bucket_alloc); /* Flush the filter contents if: * * 1) the connection will be closed * 2) there isn't a request ready to be read */ /* ### shouldn't this read from the connection input filters? */ /* ### is zero correct? that means "read one line" */ if (r->connection->keepalive != AP_CONN_CLOSE) { if (ap_get_brigade(r->input_filters, bb, AP_MODE_EATCRLF, APR_NONBLOCK_READ, 0) != APR_SUCCESS) { c->data_in_input_filters = 0; /* we got APR_EOF or an error */ } else { c->data_in_input_filters = 1; return; /* don't flush */ } } e = apr_bucket_flush_create(c->bucket_alloc); /* We just send directly to the connection based filters. At * this point, we know that we have seen all of the data * (request finalization sent an EOS bucket, which empties all * of the request filters). We just want to flush the buckets * if something hasn't been sent to the network yet. */ APR_BRIGADE_INSERT_HEAD(bb, e); ap_pass_brigade(r->connection->output_filters, bb);}void ap_process_request(request_rec *r){ int access_status; /* Give quick handlers a shot at serving the request on the fast * path, bypassing all of the other Apache hooks. * * This hook was added to enable serving files out of a URI keyed * content cache ( e.g., Mike Abbott's Quick Shortcut Cache, * described here: http://oss.sgi.com/projects/apache/mod_qsc.html ) * * It may have other uses as well, such as routing requests directly to * content handlers that have the ability to grok HTTP and do their * own access checking, etc (e.g. servlet engines). * * Use this hook with extreme care and only if you know what you are * doing. */ if (ap_extended_status) ap_time_process_request(r->connection->sbh, START_PREQUEST); access_status = ap_run_quick_handler(r, 0); /* Not a look-up request */ if (access_status == DECLINED) { access_status = ap_process_request_internal(r); if (access_status == OK) { access_status = ap_invoke_handler(r); } } if (access_status == DONE) { /* e.g., something not in storage like TRACE */ access_status = OK; } if (access_status == OK) { ap_finalize_request_protocol(r);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -