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