upload http
[bottlenecks.git] / rubbos / app / httpd-2.0.64 / 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_http_header_filter_handle;
41 AP_DECLARE_DATA ap_filter_rec_t *ap_chunk_filter_handle;
42 AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle;
43
44 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
45                                           const char *arg)
46 {
47     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
48     if (err != NULL) {
49         return err;
50     }
51
52     cmd->server->keep_alive_timeout = apr_time_from_sec(atoi(arg));
53     return NULL;
54 }
55
56 static const char *set_keep_alive(cmd_parms *cmd, void *dummy,
57                                   const char *arg) 
58 {
59     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
60     if (err != NULL) {
61         return err;
62     }
63
64     /* We've changed it to On/Off, but used to use numbers
65      * so we accept anything but "Off" or "0" as "On"
66      */
67     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
68         cmd->server->keep_alive = 0;
69     }
70     else {
71         cmd->server->keep_alive = 1;
72     }
73     return NULL;
74 }
75
76 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy,
77                                       const char *arg)
78 {
79     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
80     if (err != NULL) {
81         return err;
82     }
83
84     cmd->server->keep_alive_max = atoi(arg);
85     return NULL;
86 }
87
88 static const command_rec http_cmds[] = {
89     AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF,
90                   "Keep-Alive timeout duration (sec)"),
91     AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF,
92      "Maximum number of Keep-Alive requests per connection, or 0 for infinite"),
93     AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
94                   "Whether persistent connections should be On or Off"),
95     { NULL }
96 };
97
98 /*
99  * HTTP/1.1 chunked transfer encoding filter.
100  */
101 static apr_status_t chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
102 {
103 #define ASCII_CRLF  "\015\012"
104 #define ASCII_ZERO  "\060"
105     conn_rec *c = f->r->connection;
106     apr_bucket_brigade *more;
107     apr_bucket *e;
108     apr_status_t rv;
109
110     for (more = NULL; b; b = more, more = NULL) {
111         apr_off_t bytes = 0;
112         apr_bucket *eos = NULL;
113         apr_bucket *flush = NULL;
114         /* XXX: chunk_hdr must remain at this scope since it is used in a 
115          *      transient bucket.
116          */
117         char chunk_hdr[20]; /* enough space for the snprintf below */
118
119         APR_BRIGADE_FOREACH(e, b) {
120             if (APR_BUCKET_IS_EOS(e)) {
121                 /* there shouldn't be anything after the eos */
122                 eos = e;
123                 break;
124             }
125             if (APR_BUCKET_IS_FLUSH(e)) {
126                 flush = e;
127                 more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
128                 break;
129             }
130             else if (e->length == (apr_size_t)-1) {
131                 /* unknown amount of data (e.g. a pipe) */
132                 const char *data;
133                 apr_size_t len;
134
135                 rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
136                 if (rv != APR_SUCCESS) {
137                     return rv;
138                 }
139                 if (len > 0) {
140                     /*
141                      * There may be a new next bucket representing the
142                      * rest of the data stream on which a read() may
143                      * block so we pass down what we have so far.
144                      */
145                     bytes += len;
146                     more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
147                     break;
148                 }
149                 else {
150                     /* If there was nothing in this bucket then we can
151                      * safely move on to the next one without pausing
152                      * to pass down what we have counted up so far.
153                      */
154                     continue;
155                 }
156             }
157             else {
158                 bytes += e->length;
159             }
160         }
161
162         /*
163          * XXX: if there aren't very many bytes at this point it may
164          * be a good idea to set them aside and return for more,
165          * unless we haven't finished counting this brigade yet.
166          */
167         /* if there are content bytes, then wrap them in a chunk */
168         if (bytes > 0) {
169             apr_size_t hdr_len;
170             /*
171              * Insert the chunk header, specifying the number of bytes in
172              * the chunk.
173              */
174             /* XXX might be nice to have APR_OFF_T_FMT_HEX */
175             hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
176                                    "%qx" CRLF, (apr_uint64_t)bytes);
177             ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
178             e = apr_bucket_transient_create(chunk_hdr, hdr_len,
179                                             c->bucket_alloc);
180             APR_BRIGADE_INSERT_HEAD(b, e);
181
182             /*
183              * Insert the end-of-chunk CRLF before an EOS or
184              * FLUSH bucket, or appended to the brigade
185              */
186             e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
187             if (eos != NULL) {
188                 APR_BUCKET_INSERT_BEFORE(eos, e);
189             }
190             else if (flush != NULL) {
191                 APR_BUCKET_INSERT_BEFORE(flush, e);
192             }
193             else {
194                 APR_BRIGADE_INSERT_TAIL(b, e);
195             }
196         }
197
198         /* RFC 2616, Section 3.6.1
199          *
200          * If there is an EOS bucket, then prefix it with:
201          *   1) the last-chunk marker ("0" CRLF)
202          *   2) the trailer
203          *   3) the end-of-chunked body CRLF
204          *
205          * If there is no EOS bucket, then do nothing.
206          *
207          * XXX: it would be nice to combine this with the end-of-chunk
208          * marker above, but this is a bit more straight-forward for
209          * now.
210          */
211         if (eos != NULL) {
212             /* XXX: (2) trailers ... does not yet exist */
213             e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
214                                            /* <trailers> */
215                                            ASCII_CRLF, 5, c->bucket_alloc);
216             APR_BUCKET_INSERT_BEFORE(eos, e);
217         }
218
219         /* pass the brigade to the next filter. */
220         rv = ap_pass_brigade(f->next, b);
221         if (rv != APR_SUCCESS || eos != NULL) {
222             return rv;
223         }
224     }
225     return APR_SUCCESS;
226 }
227
228 static const char *http_method(const request_rec *r)
229     { return "http"; }
230
231 static apr_port_t http_port(const request_rec *r)
232     { return DEFAULT_HTTP_PORT; }
233
234 static int ap_process_http_connection(conn_rec *c)
235 {
236     request_rec *r;
237     int csd_set = 0;
238     apr_socket_t *csd = NULL;
239
240     /*
241      * Read and process each request found on our connection
242      * until no requests are left or we decide to close.
243      */
244  
245     ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);
246     while ((r = ap_read_request(c)) != NULL) {
247
248         c->keepalive = AP_CONN_UNKNOWN;
249         /* process the request if it was read without error */
250  
251         ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
252         if (r->status == HTTP_OK)
253             ap_process_request(r);
254  
255         if (ap_extended_status)
256             ap_increment_counts(c->sbh, r);
257  
258         if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
259             break;
260  
261         ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, r);
262         apr_pool_destroy(r->pool);
263  
264         if (ap_graceful_stop_signalled())
265             break;
266         /* Go straight to select() to wait for the next request */
267         if (!csd_set) {
268             csd = ap_get_module_config(c->conn_config, &core_module);
269             csd_set = 1;
270         }
271         apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1);
272     }
273  
274     return OK;
275 }
276
277 static int http_create_request(request_rec *r)
278 {
279     if (!r->main && !r->prev) {
280         ap_add_output_filter_handle(ap_byterange_filter_handle,
281                                     NULL, r, r->connection);
282         ap_add_output_filter_handle(ap_content_length_filter_handle,
283                                     NULL, r, r->connection);
284         ap_add_output_filter_handle(ap_http_header_filter_handle,
285                                     NULL, r, r->connection);
286     }
287
288     return OK;
289 }
290
291 static void register_hooks(apr_pool_t *p)
292 {
293     ap_hook_process_connection(ap_process_http_connection,NULL,NULL,
294                                APR_HOOK_REALLY_LAST);
295     ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
296     ap_hook_http_method(http_method,NULL,NULL,APR_HOOK_REALLY_LAST);
297     ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
298     ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
299     ap_http_input_filter_handle =
300         ap_register_input_filter("HTTP_IN", ap_http_filter,
301                                  NULL, AP_FTYPE_PROTOCOL);
302     ap_http_header_filter_handle =
303         ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, 
304                                   NULL, AP_FTYPE_PROTOCOL);
305     ap_chunk_filter_handle =
306         ap_register_output_filter("CHUNK", chunk_filter,
307                                   NULL, AP_FTYPE_TRANSCODE);
308     ap_byterange_filter_handle =
309         ap_register_output_filter("BYTERANGE", ap_byterange_filter,
310                                   NULL, AP_FTYPE_PROTOCOL);
311     ap_method_registry_init(p);
312 }
313
314 module AP_MODULE_DECLARE_DATA http_module = {
315     STANDARD20_MODULE_STUFF,
316     NULL,                       /* create per-directory config structure */
317     NULL,                       /* merge per-directory config structures */
318     NULL,                       /* create per-server config structure */
319     NULL,                       /* merge per-server config structures */
320     http_cmds,                  /* command apr_table_t */
321     register_hooks              /* register hooks */
322 };