]> granicus.if.org Git - apache/blob - modules/http/http_core.c
Extend the socket callbacks in event to allow a timeout on the I/O callback.
[apache] / modules / http / http_core.c
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2  * contributor license agreements.  See the NOTICE file distributed with
3  * this work for additional information regarding copyright ownership.
4  * The ASF licenses this file to You under the Apache License, Version 2.0
5  * (the "License"); you may not use this file except in compliance with
6  * the License.  You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "apr_strings.h"
18 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
19
20 #define APR_WANT_STRFUNC
21 #include "apr_want.h"
22
23 #include "httpd.h"
24 #include "http_config.h"
25 #include "http_connection.h"
26 #include "http_core.h"
27 #include "http_protocol.h"   /* For index_of_response().  Grump. */
28 #include "http_request.h"
29
30 #include "util_filter.h"
31 #include "util_ebcdic.h"
32 #include "ap_mpm.h"
33 #include "scoreboard.h"
34
35 #include "mod_core.h"
36
37 /* Handles for core filters */
38 AP_DECLARE_DATA ap_filter_rec_t *ap_http_input_filter_handle;
39 AP_DECLARE_DATA ap_filter_rec_t *ap_http_header_filter_handle;
40 AP_DECLARE_DATA ap_filter_rec_t *ap_chunk_filter_handle;
41 AP_DECLARE_DATA ap_filter_rec_t *ap_http_outerror_filter_handle;
42 AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle;
43
44 AP_DECLARE_DATA const char *ap_multipart_boundary;
45
46 /* If we are using an MPM That Supports Async Connections,
47  * use a different processing function
48  */
49 static int async_mpm = 0;
50
51 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
52                                           const char *arg)
53 {
54     apr_interval_time_t timeout;
55     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
56     if (err != NULL) {
57         return err;
58     }
59
60     /* Stolen from mod_proxy.c */
61     if (ap_timeout_parameter_parse(arg, &timeout, "s") != APR_SUCCESS)
62         return "KeepAliveTimeout has wrong format";
63     cmd->server->keep_alive_timeout = timeout;
64     return NULL;
65 }
66
67 static const char *set_keep_alive(cmd_parms *cmd, void *dummy,
68                                   int arg)
69 {
70     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
71     if (err != NULL) {
72         return err;
73     }
74
75     cmd->server->keep_alive = arg;
76     return NULL;
77 }
78
79 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy,
80                                       const char *arg)
81 {
82     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
83     if (err != NULL) {
84         return err;
85     }
86
87     cmd->server->keep_alive_max = atoi(arg);
88     return NULL;
89 }
90
91 static const command_rec http_cmds[] = {
92     AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF,
93                   "Keep-Alive timeout duration (sec)"),
94     AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF,
95                   "Maximum number of Keep-Alive requests per connection, "
96                   "or 0 for infinite"),
97     AP_INIT_FLAG("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
98                   "Whether persistent connections should be On or Off"),
99     { NULL }
100 };
101
102 static const char *http_scheme(const request_rec *r)
103 {
104     /*
105      * The http module shouldn't return anything other than
106      * "http" (the default) or "https".
107      */
108     if (r->server->server_scheme &&
109         (strcmp(r->server->server_scheme, "https") == 0))
110         return "https";
111
112     return "http";
113 }
114
115 static apr_port_t http_port(const request_rec *r)
116 {
117     if (r->server->server_scheme &&
118         (strcmp(r->server->server_scheme, "https") == 0))
119         return DEFAULT_HTTPS_PORT;
120
121     return DEFAULT_HTTP_PORT;
122 }
123
124 static int ap_process_http_async_connection(conn_rec *c)
125 {
126     request_rec *r;
127     conn_state_t *cs = c->cs;
128
129     AP_DEBUG_ASSERT(cs != NULL);
130     AP_DEBUG_ASSERT(cs->state == CONN_STATE_READ_REQUEST_LINE);
131
132     while (cs->state == CONN_STATE_READ_REQUEST_LINE) {
133         ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
134
135         if ((r = ap_read_request(c))) {
136
137             c->keepalive = AP_CONN_UNKNOWN;
138             /* process the request if it was read without error */
139
140             ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
141             if (r->status == HTTP_OK) {
142                 cs->state = CONN_STATE_HANDLER;
143                 ap_process_async_request(r);
144                 /* After the call to ap_process_request, the
145                  * request pool may have been deleted.  We set
146                  * r=NULL here to ensure that any dereference
147                  * of r that might be added later in this function
148                  * will result in a segfault immediately instead
149                  * of nondeterministic failures later.
150                  */
151                 r = NULL;
152             }
153
154             if (cs->state != CONN_STATE_WRITE_COMPLETION &&
155                 cs->state != CONN_STATE_SUSPENDED) {
156                 /* Something went wrong; close the connection */
157                 cs->state = CONN_STATE_LINGER;
158             }
159         }
160         else {   /* ap_read_request failed - client may have closed */
161             cs->state = CONN_STATE_LINGER;
162         }
163     }
164
165     return OK;
166 }
167
168 static int ap_process_http_sync_connection(conn_rec *c)
169 {
170     request_rec *r;
171     conn_state_t *cs = c->cs;
172     apr_socket_t *csd = NULL;
173     int mpm_state = 0;
174
175     /*
176      * Read and process each request found on our connection
177      * until no requests are left or we decide to close.
178      */
179
180     ap_update_child_status_from_conn(c->sbh, SERVER_BUSY_READ, c);
181     while ((r = ap_read_request(c)) != NULL) {
182
183         c->keepalive = AP_CONN_UNKNOWN;
184         /* process the request if it was read without error */
185
186         ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
187         if (r->status == HTTP_OK) {
188             if (cs)
189                 cs->state = CONN_STATE_HANDLER;
190             ap_process_request(r);
191             /* After the call to ap_process_request, the
192              * request pool will have been deleted.  We set
193              * r=NULL here to ensure that any dereference
194              * of r that might be added later in this function
195              * will result in a segfault immediately instead
196              * of nondeterministic failures later.
197              */
198             r = NULL;
199         }
200
201         if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
202             break;
203
204         ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, NULL);
205
206         if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
207             break;
208         }
209
210         if (mpm_state == AP_MPMQ_STOPPING) {
211           break;
212         }
213
214         if (!csd) {
215             csd = ap_get_conn_socket(c);
216         }
217         apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1);
218         apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout);
219         /* Go straight to select() to wait for the next request */
220     }
221
222     return OK;
223 }
224
225 static int ap_process_http_connection(conn_rec *c)
226 {
227     if (async_mpm && !c->clogging_input_filters) {
228         return ap_process_http_async_connection(c);
229     }
230     else {
231         return ap_process_http_sync_connection(c);
232     }
233 }
234
235 static int http_create_request(request_rec *r)
236 {
237     if (!r->main && !r->prev) {
238         ap_add_output_filter_handle(ap_byterange_filter_handle,
239                                     NULL, r, r->connection);
240         ap_add_output_filter_handle(ap_content_length_filter_handle,
241                                     NULL, r, r->connection);
242         ap_add_output_filter_handle(ap_http_header_filter_handle,
243                                     NULL, r, r->connection);
244         ap_add_output_filter_handle(ap_http_outerror_filter_handle,
245                                     NULL, r, r->connection);
246     }
247
248     return OK;
249 }
250
251 static int http_send_options(request_rec *r)
252 {
253     if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
254          (r->uri[1] == '\0')) {
255         return DONE;           /* Send HTTP pong, without Allow header */
256     }
257     return DECLINED;
258 }
259
260 static int http_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s)
261 {
262     apr_uint64_t val;
263     if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) != APR_SUCCESS) {
264         async_mpm = 0;
265     }
266     ap_random_insecure_bytes(&val, sizeof(val));
267     ap_multipart_boundary = apr_psprintf(p, "%0" APR_UINT64_T_HEX_FMT, val);
268
269     return OK;
270 }
271
272 static void register_hooks(apr_pool_t *p)
273 {
274     ap_hook_post_config(http_post_config, NULL, NULL, APR_HOOK_MIDDLE);
275     ap_hook_process_connection(ap_process_http_connection, NULL, NULL,
276                                APR_HOOK_REALLY_LAST);
277     ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
278     ap_hook_map_to_storage(http_send_options,NULL,NULL,APR_HOOK_MIDDLE);
279     ap_hook_http_scheme(http_scheme,NULL,NULL,APR_HOOK_REALLY_LAST);
280     ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
281     ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
282     ap_http_input_filter_handle =
283         ap_register_input_filter("HTTP_IN", ap_http_filter,
284                                  NULL, AP_FTYPE_PROTOCOL);
285     ap_http_header_filter_handle =
286         ap_register_output_filter("HTTP_HEADER", ap_http_header_filter,
287                                   NULL, AP_FTYPE_PROTOCOL);
288     ap_chunk_filter_handle =
289         ap_register_output_filter("CHUNK", ap_http_chunk_filter,
290                                   NULL, AP_FTYPE_TRANSCODE);
291     ap_http_outerror_filter_handle =
292         ap_register_output_filter("HTTP_OUTERROR", ap_http_outerror_filter,
293                                   NULL, AP_FTYPE_PROTOCOL);
294     ap_byterange_filter_handle =
295         ap_register_output_filter("BYTERANGE", ap_byterange_filter,
296                                   NULL, AP_FTYPE_PROTOCOL);
297     ap_method_registry_init(p);
298 }
299
300 AP_DECLARE_MODULE(http) = {
301     STANDARD20_MODULE_STUFF,
302     NULL,              /* create per-directory config structure */
303     NULL,              /* merge per-directory config structures */
304     NULL,              /* create per-server config structure */
305     NULL,              /* merge per-server config structures */
306     http_cmds,         /* command apr_table_t */
307     register_hooks     /* register hooks */
308 };