1 /* ====================================================================
2 * The Apache Software License, Version 1.1
4 * Copyright (c) 2000-2001 The Apache Software Foundation. All rights
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
19 * 3. The end-user documentation included with the redistribution,
20 * if any, must include the following acknowledgment:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowledgment may appear in the software itself,
24 * if and wherever such third-party acknowledgments normally appear.
26 * 4. The names "Apache" and "Apache Software Foundation" must
27 * not be used to endorse or promote products derived from this
28 * software without prior written permission. For written
29 * permission, please contact apache@apache.org.
31 * 5. Products derived from this software may not be called "Apache",
32 * nor may "Apache" appear in their name, without prior written
33 * permission of the Apache Software Foundation.
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
47 * ====================================================================
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
54 * Portions of this software are based upon public domain software
55 * originally written at the National Center for Supercomputing Applications,
56 * University of Illinois, Urbana-Champaign.
59 #include "apr_strings.h"
60 #include "apr_thread_proc.h" /* for RLIMIT stuff */
62 #include "apr_optional.h"
64 #define APR_WANT_STRFUNC
69 #include "http_config.h"
71 #include "http_connection.h"
72 #include "http_protocol.h" /* For index_of_response(). Grump. */
73 #include "http_request.h"
75 #include "util_filter.h"
76 #include "util_ebcdic.h"
78 #include "scoreboard.h"
81 #include "../loggers/mod_log_config.h"
83 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
86 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
91 cmd->server->keep_alive_timeout = atoi(arg);
95 static const char *set_keep_alive(cmd_parms *cmd, void *dummy,
98 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
103 /* We've changed it to On/Off, but used to use numbers
104 * so we accept anything but "Off" or "0" as "On"
106 if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
107 cmd->server->keep_alive = 0;
110 cmd->server->keep_alive = 1;
115 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy,
118 const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
123 cmd->server->keep_alive_max = atoi(arg);
127 static const command_rec http_cmds[] = {
128 AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF,
129 "Keep-Alive timeout duration (sec)"),
130 AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF,
131 "Maximum number of Keep-Alive requests per connection, or 0 for infinite"),
132 AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
133 "Whether persistent connections should be On or Off"),
138 * HTTP/1.1 chunked transfer encoding filter.
140 static apr_status_t chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
142 #define ASCII_CRLF "\015\012"
143 #define ASCII_ZERO "\060"
144 apr_bucket_brigade *more = NULL;
148 for (more = NULL; b; b = more, more = NULL) {
150 apr_bucket *eos = NULL;
151 char chunk_hdr[20]; /* enough space for the snprintf below */
153 APR_BRIGADE_FOREACH(e, b) {
154 if (APR_BUCKET_IS_EOS(e)) {
155 /* there shouldn't be anything after the eos */
159 else if (e->length == -1) {
160 /* unknown amount of data (e.g. a pipe) */
164 rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
165 if (rv != APR_SUCCESS) {
170 * There may be a new next bucket representing the
171 * rest of the data stream on which a read() may
172 * block so we pass down what we have so far.
175 more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
179 /* If there was nothing in this bucket then we can
180 * safely move on to the next one without pausing
181 * to pass down what we have counted up so far.
192 * XXX: if there aren't very many bytes at this point it may
193 * be a good idea to set them aside and return for more,
194 * unless we haven't finished counting this brigade yet.
197 /* if there are content bytes, then wrap them in a chunk */
202 * Insert the chunk header, specifying the number of bytes in
205 /* XXX might be nice to have APR_OFF_T_FMT_HEX */
206 hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
207 "%qx" CRLF, (apr_uint64_t)bytes);
208 ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
209 e = apr_bucket_transient_create(chunk_hdr, hdr_len);
210 APR_BRIGADE_INSERT_HEAD(b, e);
213 * Insert the end-of-chunk CRLF before the EOS bucket, or
214 * appended to the brigade
216 e = apr_bucket_immortal_create(ASCII_CRLF, 2);
218 APR_BUCKET_INSERT_BEFORE(eos, e);
221 APR_BRIGADE_INSERT_TAIL(b, e);
225 /* RFC 2616, Section 3.6.1
227 * If there is an EOS bucket, then prefix it with:
228 * 1) the last-chunk marker ("0" CRLF)
230 * 3) the end-of-chunked body CRLF
232 * If there is no EOS bucket, then do nothing.
234 * XXX: it would be nice to combine this with the end-of-chunk
235 * marker above, but this is a bit more straight-forward for
239 /* XXX: (2) trailers ... does not yet exist */
240 e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF /* <trailers> */ ASCII_CRLF, 5);
241 APR_BUCKET_INSERT_BEFORE(eos, e);
244 /* pass the brigade to the next filter. */
245 rv = ap_pass_brigade(f->next, b);
246 if (rv != APR_SUCCESS || eos != NULL) {
254 static const char *http_method(const request_rec *r)
257 static unsigned short http_port(const request_rec *r)
258 { return DEFAULT_HTTP_PORT; }
260 static int ap_pre_http_connection(conn_rec *c)
262 ap_add_input_filter("HTTP_IN", NULL, NULL, c);
263 ap_add_input_filter("CORE_IN", NULL, NULL, c);
264 ap_add_output_filter("CORE", NULL, NULL, c);
268 static int ap_process_http_connection(conn_rec *c)
273 * Read and process each request found on our connection
274 * until no requests are left or we decide to close.
277 ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_READ, NULL);
278 while ((r = ap_read_request(c)) != NULL) {
280 /* process the request if it was read without error */
282 ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_WRITE, NULL);
283 if (r->status == HTTP_OK)
284 ap_process_request(r);
286 if (ap_extended_status)
287 ap_increment_counts(AP_CHILD_THREAD_FROM_ID(c->id), r);
289 if (!c->keepalive || c->aborted)
292 ap_update_child_status(AP_CHILD_THREAD_FROM_ID(c->id), SERVER_BUSY_KEEPALIVE, NULL);
293 apr_pool_destroy(r->pool);
295 if (ap_graceful_stop_signalled())
302 static int read_request_line(request_rec *r)
304 char l[DEFAULT_LIMIT_REQUEST_LINE + 2]; /* getline's two extra for \n\0 */
309 int major = 1, minor = 0; /* Assume HTTP/1.0 if non-"HTTP" protocol */
312 /* Read past empty lines until we get a real request line,
313 * a read error, the connection closes (EOF), or we timeout.
315 * We skip empty lines because browsers have to tack a CRLF on to the end
316 * of POSTs to support old CERN webservers. But note that we may not
317 * have flushed any previous response completely to the client yet.
318 * We delay the flush as long as possible so that we can improve
319 * performance for clients that are pipelining requests. If a request
320 * is pipelined then we won't block during the (implicit) read() below.
321 * If the requests aren't pipelined, then the client is still waiting
322 * for the final buffer flush from us, and we will block in the implicit
323 * read(). B_SAFEREAD ensures that the BUFF layer flushes if it will
324 * have to block during a read.
327 while ((len = ap_getline(l, sizeof(l), r, 0)) <= 0) {
328 if (len < 0) { /* includes EOF */
329 /* this is a hack to make sure that request time is set,
330 * it's not perfect, but it's better than nothing
332 r->request_time = apr_time_now();
336 /* we've probably got something to do, ignore graceful restart requests */
338 /* XXX - sigwait doesn't work if the signal has been SIG_IGNed (under
339 * linux 2.0 w/ glibc 2.0, anyway), and this step isn't necessary when
340 * we're running a sigwait thread anyway. If/when unthreaded mode is
341 * put back in, we should make sure to ignore this signal iff a sigwait
342 * thread isn't used. - mvsk
345 apr_signal(SIGWINCH, SIG_IGN);
349 r->request_time = apr_time_now();
350 r->the_request = apr_pstrdup(r->pool, l);
351 r->method = ap_getword_white(r->pool, &ll);
354 /* XXX If we want to keep track of the Method, the protocol module should do
355 * it. That support isn't in the scoreboard yet. Hopefully next week
357 ap_update_connection_status(AP_CHILD_THREAD_FROM_ID(conn->id), "Method", r->method);
359 uri = ap_getword_white(r->pool, &ll);
361 /* Provide quick information about the request method as soon as known */
363 r->method_number = ap_method_number_of(r->method);
364 if (r->method_number == M_GET && r->method[0] == 'H') {
368 ap_parse_uri(r, uri);
370 /* ap_getline returns (size of max buffer - 1) if it fills up the
371 * buffer before finding the end-of-line. This is only going to
372 * happen if it exceeds the configured limit for a request-line.
374 if (len > r->server->limit_req_line) {
375 r->status = HTTP_REQUEST_URI_TOO_LARGE;
376 r->proto_num = HTTP_VERSION(1,0);
377 r->protocol = apr_pstrdup(r->pool, "HTTP/1.0");
390 r->protocol = apr_pstrndup(r->pool, pro, len);
392 /* XXX ap_update_connection_status(conn->id, "Protocol", r->protocol); */
394 /* Avoid sscanf in the common case */
396 pro[0] == 'H' && pro[1] == 'T' && pro[2] == 'T' && pro[3] == 'P' &&
397 pro[4] == '/' && apr_isdigit(pro[5]) && pro[6] == '.' &&
398 apr_isdigit(pro[7])) {
399 r->proto_num = HTTP_VERSION(pro[5] - '0', pro[7] - '0');
400 } else if (2 == sscanf(r->protocol, "HTTP/%u.%u", &major, &minor)
401 && minor < HTTP_VERSION(1,0)) /* don't allow HTTP/0.1000 */
402 r->proto_num = HTTP_VERSION(major, minor);
404 r->proto_num = HTTP_VERSION(1,0);
409 static int http_create_request(request_rec *r)
411 ap_http_conn_rec *hconn = ap_get_module_config(r->connection->conn_config, &http_module);
414 hconn = apr_pcalloc(r->pool, sizeof(*hconn));
415 ap_set_module_config(r->connection->conn_config, &http_module, hconn);
417 if (!r->main && !r->prev && !r->next) {
418 keptalive = r->connection->keepalive == 1;
419 r->connection->keepalive = 0;
421 /* XXX can we optimize these timeouts at all? gstein */
422 apr_setsocketopt(r->connection->client_socket, APR_SO_TIMEOUT,
424 ? r->server->keep_alive_timeout * APR_USEC_PER_SEC
425 : r->server->timeout * APR_USEC_PER_SEC));
427 /* Get the request... */
428 if (!read_request_line(r)) {
429 if (r->status == HTTP_REQUEST_URI_TOO_LARGE) {
430 ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, 0, r,
431 "request failed: URI too long");
432 ap_send_error_response(r, 0);
433 ap_run_log_transaction(r);
439 apr_setsocketopt(r->connection->client_socket,
441 (int)(r->server->timeout * APR_USEC_PER_SEC));
447 static const char *log_connection_status(request_rec *r, char *a)
449 ap_http_conn_rec *hconn = ap_get_module_config(r->connection->conn_config,
451 if (r->connection->aborted)
454 if ((r->connection->keepalive) &&
455 ((r->server->keep_alive_max - hconn->keepalives) > 0)) {
462 static void http_pre_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp)
464 static APR_OPTIONAL_FN_TYPE(ap_register_log_handler) *log_pfn_register;
466 log_pfn_register = APR_RETRIEVE_OPTIONAL_FN(ap_register_log_handler);
468 if (log_pfn_register) {
469 log_pfn_register(p, "c", log_connection_status, 0);
473 static void register_hooks(apr_pool_t *p)
475 static const char *const pred[] = { "mod_log_config.c", NULL };
477 ap_hook_pre_config(http_pre_config, pred, NULL, APR_HOOK_MIDDLE);
478 ap_hook_pre_connection(ap_pre_http_connection,NULL,NULL,
479 APR_HOOK_REALLY_LAST);
480 ap_hook_process_connection(ap_process_http_connection,NULL,NULL,
481 APR_HOOK_REALLY_LAST);
482 ap_hook_http_method(http_method,NULL,NULL,APR_HOOK_REALLY_LAST);
483 ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
484 ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_MIDDLE);
486 ap_register_input_filter("HTTP_IN", ap_http_filter, AP_FTYPE_CONNECTION);
487 ap_register_input_filter("DECHUNK", ap_dechunk_filter, AP_FTYPE_TRANSCODE);
488 ap_register_output_filter("HTTP_HEADER", ap_http_header_filter,
489 AP_FTYPE_HTTP_HEADER);
490 ap_register_output_filter("CHUNK", chunk_filter, AP_FTYPE_TRANSCODE);
491 ap_register_output_filter("BYTERANGE", ap_byterange_filter,
492 AP_FTYPE_HTTP_HEADER);
495 AP_DECLARE_DATA module http_module = {
496 STANDARD20_MODULE_STUFF,
497 NULL, /* create per-directory config structure */
498 NULL, /* merge per-directory config structures */
499 NULL, /* create per-server config structure */
500 NULL, /* merge per-server config structures */
501 http_cmds, /* command apr_table_t */
502 register_hooks /* register hooks */