]> granicus.if.org Git - apache/blob - modules/http/http_core.c
Enhance KeepAliveTimeout to support a value in milliseconds.
[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 static int ap_process_http_connection(conn_rec *c);
45
46
47 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
48                                           const char *arg)
49 {
50     apr_interval_time_t timeout;
51     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
52     if (err != NULL) {
53         return err;
54     }
55
56     /* Stolen from mod_proxy.c */
57     if (ap_timeout_parameter_parse(arg, &timeout, "s") != APR_SUCCESS)
58         return "KeepAliveTimeout has wrong format";
59     cmd->server->keep_alive_timeout = timeout;
60     return NULL;
61 }
62
63 static const char *set_keep_alive(cmd_parms *cmd, void *dummy,
64                                   const char *arg)
65 {
66     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
67     if (err != NULL) {
68         return err;
69     }
70
71     /* We've changed it to On/Off, but used to use numbers
72      * so we accept anything but "Off" or "0" as "On"
73      */
74     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
75         cmd->server->keep_alive = 0;
76     }
77     else {
78         cmd->server->keep_alive = 1;
79     }
80     return NULL;
81 }
82
83 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy,
84                                       const char *arg)
85 {
86     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE);
87     if (err != NULL) {
88         return err;
89     }
90
91     cmd->server->keep_alive_max = atoi(arg);
92     return NULL;
93 }
94
95 static const command_rec http_cmds[] = {
96     AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF,
97                   "Keep-Alive timeout duration (sec)"),
98     AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF,
99                   "Maximum number of Keep-Alive requests per connection, "
100                   "or 0 for infinite"),
101     AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
102                   "Whether persistent connections should be On or Off"),
103     { NULL }
104 };
105
106 static const char *http_scheme(const request_rec *r)
107 {
108     /* 
109      * The http module shouldn't return anything other than 
110      * "http" (the default) or "https".
111      */
112     if (r->server->server_scheme &&
113         (strcmp(r->server->server_scheme, "https") == 0))
114         return "https";
115     
116     return "http";
117 }
118
119 static apr_port_t http_port(const request_rec *r)
120 {
121     if (r->server->server_scheme &&
122         (strcmp(r->server->server_scheme, "https") == 0))
123         return DEFAULT_HTTPS_PORT;
124     
125     return DEFAULT_HTTP_PORT;
126 }
127
128 static int ap_process_http_async_connection(conn_rec *c)
129 {
130     request_rec *r;
131     conn_state_t *cs = c->cs;
132
133     if (c->clogging_input_filters) {
134         return ap_process_http_connection(c);
135     }
136
137     AP_DEBUG_ASSERT(cs->state == CONN_STATE_READ_REQUEST_LINE);
138
139     while (cs->state == CONN_STATE_READ_REQUEST_LINE) {
140         ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);
141
142         if ((r = ap_read_request(c))) {
143
144             c->keepalive = AP_CONN_UNKNOWN;
145             /* process the request if it was read without error */
146
147             ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
148             if (r->status == HTTP_OK) {
149                 cs->state = CONN_STATE_HANDLER;
150                 ap_process_async_request(r);
151                 /* After the call to ap_process_request, the
152                  * request pool may have been deleted.  We set
153                  * r=NULL here to ensure that any dereference
154                  * of r that might be added later in this function
155                  * will result in a segfault immediately instead
156                  * of nondeterministic failures later.
157                  */
158                 r = NULL;
159             }
160
161             if (cs->state != CONN_STATE_WRITE_COMPLETION && 
162                 cs->state != CONN_STATE_SUSPENDED) {
163                 /* Something went wrong; close the connection */
164                 cs->state = CONN_STATE_LINGER;
165             }
166         }
167         else {   /* ap_read_request failed - client may have closed */
168             cs->state = CONN_STATE_LINGER;
169         }
170     }
171
172     return OK;
173 }
174
175 static int ap_process_http_connection(conn_rec *c)
176 {
177     request_rec *r;
178     conn_state_t *cs = c->cs;
179     apr_socket_t *csd = NULL;
180     int mpm_state = 0;
181
182     /*
183      * Read and process each request found on our connection
184      * until no requests are left or we decide to close.
185      */
186
187     ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);
188     while ((r = ap_read_request(c)) != NULL) {
189
190         c->keepalive = AP_CONN_UNKNOWN;
191         /* process the request if it was read without error */
192
193         ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
194         if (r->status == HTTP_OK) {
195             cs->state = CONN_STATE_HANDLER;
196             ap_process_request(r);
197             /* After the call to ap_process_request, the
198              * request pool will have been deleted.  We set
199              * r=NULL here to ensure that any dereference
200              * of r that might be added later in this function
201              * will result in a segfault immediately instead
202              * of nondeterministic failures later.
203              */
204             r = NULL;
205         }
206
207         if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
208             break;
209
210         ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, NULL);
211
212         if (ap_mpm_query(AP_MPMQ_MPM_STATE, &mpm_state)) {
213             break;
214         }
215
216         if (mpm_state == AP_MPMQ_STOPPING) {
217           break;
218         }
219
220         if (!csd) {
221             csd = ap_get_module_config(c->conn_config, &core_module);
222         }
223         apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1);
224         apr_socket_timeout_set(csd, c->base_server->keep_alive_timeout);
225         /* Go straight to select() to wait for the next request */
226     }
227
228     return OK;
229 }
230
231 static int http_create_request(request_rec *r)
232 {
233     if (!r->main && !r->prev) {
234         ap_add_output_filter_handle(ap_byterange_filter_handle,
235                                     NULL, r, r->connection);
236         ap_add_output_filter_handle(ap_content_length_filter_handle,
237                                     NULL, r, r->connection);
238         ap_add_output_filter_handle(ap_http_header_filter_handle,
239                                     NULL, r, r->connection);
240         ap_add_output_filter_handle(ap_http_outerror_filter_handle,
241                                     NULL, r, r->connection);
242     }
243
244     return OK;
245 }
246
247 static int http_send_options(request_rec *r)
248 {
249     if ((r->method_number == M_OPTIONS) && r->uri && (r->uri[0] == '*') &&
250          (r->uri[1] == '\0')) {
251         return DONE;           /* Send HTTP pong, without Allow header */
252     }
253     return DECLINED;
254 }
255
256 static void register_hooks(apr_pool_t *p)
257 {
258     /**
259      * If we ae using an MPM That Supports Async Connections,
260      * use a different processing function
261      */
262     int async_mpm = 0;
263     if (ap_mpm_query(AP_MPMQ_IS_ASYNC, &async_mpm) == APR_SUCCESS
264         && async_mpm == 1) {
265         ap_hook_process_connection(ap_process_http_async_connection, NULL,
266                                    NULL, APR_HOOK_REALLY_LAST);
267     }
268     else {
269         ap_hook_process_connection(ap_process_http_connection, NULL, NULL,
270                                    APR_HOOK_REALLY_LAST);
271     }
272
273     ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
274     ap_hook_map_to_storage(http_send_options,NULL,NULL,APR_HOOK_MIDDLE);
275     ap_hook_http_scheme(http_scheme,NULL,NULL,APR_HOOK_REALLY_LAST);
276     ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
277     ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
278     ap_http_input_filter_handle =
279         ap_register_input_filter("HTTP_IN", ap_http_filter,
280                                  NULL, AP_FTYPE_PROTOCOL);
281     ap_http_header_filter_handle =
282         ap_register_output_filter("HTTP_HEADER", ap_http_header_filter,
283                                   NULL, AP_FTYPE_PROTOCOL);
284     ap_chunk_filter_handle =
285         ap_register_output_filter("CHUNK", ap_http_chunk_filter,
286                                   NULL, AP_FTYPE_TRANSCODE);
287     ap_http_outerror_filter_handle =
288         ap_register_output_filter("HTTP_OUTERROR", ap_http_outerror_filter,
289                                   NULL, AP_FTYPE_PROTOCOL);
290     ap_byterange_filter_handle =
291         ap_register_output_filter("BYTERANGE", ap_byterange_filter,
292                                   NULL, AP_FTYPE_PROTOCOL);
293     ap_method_registry_init(p);
294 }
295
296 module AP_MODULE_DECLARE_DATA http_module = {
297     STANDARD20_MODULE_STUFF,
298     NULL,              /* create per-directory config structure */
299     NULL,              /* merge per-directory config structures */
300     NULL,              /* create per-server config structure */
301     NULL,              /* merge per-server config structures */
302     http_cmds,         /* command apr_table_t */
303     register_hooks     /* register hooks */
304 };