Main Page | Modules | Namespace List | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages | Examples

http_core.c

Go to the documentation of this file.
00001 /* Copyright 1999-2005 The Apache Software Foundation or its licensors, as
00002  * applicable.
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include "apr_strings.h"
00018 #include "apr_thread_proc.h"    /* for RLIMIT stuff */
00019 
00020 #define APR_WANT_STRFUNC
00021 #include "apr_want.h"
00022 
00023 #define CORE_PRIVATE
00024 #include "httpd.h"
00025 #include "http_config.h"
00026 #include "http_connection.h"
00027 #include "http_core.h"
00028 #include "http_protocol.h"      /* For index_of_response().  Grump. */
00029 #include "http_request.h"
00030 
00031 #include "util_filter.h"
00032 #include "util_ebcdic.h"
00033 #include "ap_mpm.h"
00034 #include "scoreboard.h"
00035 
00036 #include "mod_core.h"
00037 
00038 /* Handles for core filters */
00039 AP_DECLARE_DATA ap_filter_rec_t *ap_http_input_filter_handle;
00040 AP_DECLARE_DATA ap_filter_rec_t *ap_http_header_filter_handle;
00041 AP_DECLARE_DATA ap_filter_rec_t *ap_chunk_filter_handle;
00042 AP_DECLARE_DATA ap_filter_rec_t *ap_byterange_filter_handle;
00043 
00044 static const char *set_keep_alive_timeout(cmd_parms *cmd, void *dummy,
00045                                           const char *arg)
00046 {
00047     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
00048     if (err != NULL) {
00049         return err;
00050     }
00051 
00052     cmd->server->keep_alive_timeout = apr_time_from_sec(atoi(arg));
00053     return NULL;
00054 }
00055 
00056 static const char *set_keep_alive(cmd_parms *cmd, void *dummy,
00057                                   const char *arg) 
00058 {
00059     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
00060     if (err != NULL) {
00061         return err;
00062     }
00063 
00064     /* We've changed it to On/Off, but used to use numbers
00065      * so we accept anything but "Off" or "0" as "On"
00066      */
00067     if (!strcasecmp(arg, "off") || !strcmp(arg, "0")) {
00068         cmd->server->keep_alive = 0;
00069     }
00070     else {
00071         cmd->server->keep_alive = 1;
00072     }
00073     return NULL;
00074 }
00075 
00076 static const char *set_keep_alive_max(cmd_parms *cmd, void *dummy,
00077                                       const char *arg)
00078 {
00079     const char *err = ap_check_cmd_context(cmd, NOT_IN_DIR_LOC_FILE|NOT_IN_LIMIT);
00080     if (err != NULL) {
00081         return err;
00082     }
00083 
00084     cmd->server->keep_alive_max = atoi(arg);
00085     return NULL;
00086 }
00087 
00088 static const command_rec http_cmds[] = {
00089     AP_INIT_TAKE1("KeepAliveTimeout", set_keep_alive_timeout, NULL, RSRC_CONF,
00090                   "Keep-Alive timeout duration (sec)"),
00091     AP_INIT_TAKE1("MaxKeepAliveRequests", set_keep_alive_max, NULL, RSRC_CONF,
00092      "Maximum number of Keep-Alive requests per connection, or 0 for infinite"),
00093     AP_INIT_TAKE1("KeepAlive", set_keep_alive, NULL, RSRC_CONF,
00094                   "Whether persistent connections should be On or Off"),
00095     { NULL }
00096 };
00097 
00098 /*
00099  * HTTP/1.1 chunked transfer encoding filter.
00100  */
00101 static apr_status_t chunk_filter(ap_filter_t *f, apr_bucket_brigade *b)
00102 {
00103 #define ASCII_CRLF  "\015\012"
00104 #define ASCII_ZERO  "\060"
00105     conn_rec *c = f->r->connection;
00106     apr_bucket_brigade *more;
00107     apr_bucket *e;
00108     apr_status_t rv;
00109 
00110     for (more = NULL; b; b = more, more = NULL) {
00111         apr_off_t bytes = 0;
00112         apr_bucket *eos = NULL;
00113         apr_bucket *flush = NULL;
00114         /* XXX: chunk_hdr must remain at this scope since it is used in a 
00115          *      transient bucket.
00116          */
00117         char chunk_hdr[20]; /* enough space for the snprintf below */
00118 
00119         APR_BRIGADE_FOREACH(e, b) {
00120             if (APR_BUCKET_IS_EOS(e)) {
00121                 /* there shouldn't be anything after the eos */
00122                 eos = e;
00123                 break;
00124             }
00125             if (APR_BUCKET_IS_FLUSH(e)) {
00126                 flush = e;
00127             }
00128             else if (e->length == (apr_size_t)-1) {
00129                 /* unknown amount of data (e.g. a pipe) */
00130                 const char *data;
00131                 apr_size_t len;
00132 
00133                 rv = apr_bucket_read(e, &data, &len, APR_BLOCK_READ);
00134                 if (rv != APR_SUCCESS) {
00135                     return rv;
00136                 }
00137                 if (len > 0) {
00138                     /*
00139                      * There may be a new next bucket representing the
00140                      * rest of the data stream on which a read() may
00141                      * block so we pass down what we have so far.
00142                      */
00143                     bytes += len;
00144                     more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
00145                     break;
00146                 }
00147                 else {
00148                     /* If there was nothing in this bucket then we can
00149                      * safely move on to the next one without pausing
00150                      * to pass down what we have counted up so far.
00151                      */
00152                     continue;
00153                 }
00154             }
00155             else {
00156                 bytes += e->length;
00157             }
00158         }
00159 
00160         /*
00161          * XXX: if there aren't very many bytes at this point it may
00162          * be a good idea to set them aside and return for more,
00163          * unless we haven't finished counting this brigade yet.
00164          */
00165         /* if there are content bytes, then wrap them in a chunk */
00166         if (bytes > 0) {
00167             apr_size_t hdr_len;
00168             /*
00169              * Insert the chunk header, specifying the number of bytes in
00170              * the chunk.
00171              */
00172             /* XXX might be nice to have APR_OFF_T_FMT_HEX */
00173             hdr_len = apr_snprintf(chunk_hdr, sizeof(chunk_hdr),
00174                                    "%qx" CRLF, (apr_uint64_t)bytes);
00175             ap_xlate_proto_to_ascii(chunk_hdr, hdr_len);
00176             e = apr_bucket_transient_create(chunk_hdr, hdr_len,
00177                                             c->bucket_alloc);
00178             APR_BRIGADE_INSERT_HEAD(b, e);
00179 
00180             /*
00181              * Insert the end-of-chunk CRLF before an EOS or
00182              * FLUSH bucket, or appended to the brigade
00183              */
00184             e = apr_bucket_immortal_create(ASCII_CRLF, 2, c->bucket_alloc);
00185             if (eos != NULL) {
00186                 APR_BUCKET_INSERT_BEFORE(eos, e);
00187             }
00188             else if (flush != NULL) {
00189                 APR_BUCKET_INSERT_BEFORE(flush, e);
00190             }
00191             else {
00192                 APR_BRIGADE_INSERT_TAIL(b, e);
00193             }
00194         }
00195 
00196         /* RFC 2616, Section 3.6.1
00197          *
00198          * If there is an EOS bucket, then prefix it with:
00199          *   1) the last-chunk marker ("0" CRLF)
00200          *   2) the trailer
00201          *   3) the end-of-chunked body CRLF
00202          *
00203          * If there is no EOS bucket, then do nothing.
00204          *
00205          * XXX: it would be nice to combine this with the end-of-chunk
00206          * marker above, but this is a bit more straight-forward for
00207          * now.
00208          */
00209         if (eos != NULL) {
00210             /* XXX: (2) trailers ... does not yet exist */
00211             e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
00212                                            /* <trailers> */
00213                                            ASCII_CRLF, 5, c->bucket_alloc);
00214             APR_BUCKET_INSERT_BEFORE(eos, e);
00215         }
00216 
00217         /* pass the brigade to the next filter. */
00218         rv = ap_pass_brigade(f->next, b);
00219         if (rv != APR_SUCCESS || eos != NULL) {
00220             return rv;
00221         }
00222     }
00223     return APR_SUCCESS;
00224 }
00225 
00226 static const char *http_method(const request_rec *r)
00227     { return "http"; }
00228 
00229 static apr_port_t http_port(const request_rec *r)
00230     { return DEFAULT_HTTP_PORT; }
00231 
00232 static int ap_process_http_connection(conn_rec *c)
00233 {
00234     request_rec *r;
00235     int csd_set = 0;
00236     apr_socket_t *csd = NULL;
00237 
00238     /*
00239      * Read and process each request found on our connection
00240      * until no requests are left or we decide to close.
00241      */
00242  
00243     ap_update_child_status(c->sbh, SERVER_BUSY_READ, NULL);
00244     while ((r = ap_read_request(c)) != NULL) {
00245 
00246         c->keepalive = AP_CONN_UNKNOWN;
00247         /* process the request if it was read without error */
00248  
00249         ap_update_child_status(c->sbh, SERVER_BUSY_WRITE, r);
00250         if (r->status == HTTP_OK)
00251             ap_process_request(r);
00252  
00253         if (ap_extended_status)
00254             ap_increment_counts(c->sbh, r);
00255  
00256         if (c->keepalive != AP_CONN_KEEPALIVE || c->aborted)
00257             break;
00258  
00259         ap_update_child_status(c->sbh, SERVER_BUSY_KEEPALIVE, r);
00260         apr_pool_destroy(r->pool);
00261  
00262         if (ap_graceful_stop_signalled())
00263             break;
00264         /* Go straight to select() to wait for the next request */
00265         if (!csd_set) {
00266             csd = ap_get_module_config(c->conn_config, &core_module);
00267             csd_set = 1;
00268         }
00269         apr_socket_opt_set(csd, APR_INCOMPLETE_READ, 1);
00270     }
00271  
00272     return OK;
00273 }
00274 
00275 static int http_create_request(request_rec *r)
00276 {
00277     if (!r->main && !r->prev) {
00278         ap_add_output_filter_handle(ap_byterange_filter_handle,
00279                                     NULL, r, r->connection);
00280         ap_add_output_filter_handle(ap_content_length_filter_handle,
00281                                     NULL, r, r->connection);
00282         ap_add_output_filter_handle(ap_http_header_filter_handle,
00283                                     NULL, r, r->connection);
00284     }
00285 
00286     return OK;
00287 }
00288 
00289 static void register_hooks(apr_pool_t *p)
00290 {
00291     ap_hook_process_connection(ap_process_http_connection,NULL,NULL,
00292                                APR_HOOK_REALLY_LAST);
00293     ap_hook_map_to_storage(ap_send_http_trace,NULL,NULL,APR_HOOK_MIDDLE);
00294     ap_hook_http_method(http_method,NULL,NULL,APR_HOOK_REALLY_LAST);
00295     ap_hook_default_port(http_port,NULL,NULL,APR_HOOK_REALLY_LAST);
00296     ap_hook_create_request(http_create_request, NULL, NULL, APR_HOOK_REALLY_LAST);
00297     ap_http_input_filter_handle =
00298         ap_register_input_filter("HTTP_IN", ap_http_filter,
00299                                  NULL, AP_FTYPE_PROTOCOL);
00300     ap_http_header_filter_handle =
00301         ap_register_output_filter("HTTP_HEADER", ap_http_header_filter, 
00302                                   NULL, AP_FTYPE_PROTOCOL);
00303     ap_chunk_filter_handle =
00304         ap_register_output_filter("CHUNK", chunk_filter,
00305                                   NULL, AP_FTYPE_TRANSCODE);
00306     ap_byterange_filter_handle =
00307         ap_register_output_filter("BYTERANGE", ap_byterange_filter,
00308                                   NULL, AP_FTYPE_PROTOCOL);
00309     ap_method_registry_init(p);
00310 }
00311 
00312 module AP_MODULE_DECLARE_DATA http_module = {
00313     STANDARD20_MODULE_STUFF,
00314     NULL,                       /* create per-directory config structure */
00315     NULL,                       /* merge per-directory config structures */
00316     NULL,                       /* create per-server config structure */
00317     NULL,                       /* merge per-server config structures */
00318     http_cmds,                  /* command apr_table_t */
00319     register_hooks              /* register hooks */
00320 };