00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "apr_strings.h"
00018 #include "apr_thread_proc.h"
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"
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
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
00065
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
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
00115
00116
00117 char chunk_hdr[20];
00118
00119 APR_BRIGADE_FOREACH(e, b) {
00120 if (APR_BUCKET_IS_EOS(e)) {
00121
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
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
00140
00141
00142
00143 bytes += len;
00144 more = apr_brigade_split(b, APR_BUCKET_NEXT(e));
00145 break;
00146 }
00147 else {
00148
00149
00150
00151
00152 continue;
00153 }
00154 }
00155 else {
00156 bytes += e->length;
00157 }
00158 }
00159
00160
00161
00162
00163
00164
00165
00166 if (bytes > 0) {
00167 apr_size_t hdr_len;
00168
00169
00170
00171
00172
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
00182
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
00197
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209 if (eos != NULL) {
00210
00211 e = apr_bucket_immortal_create(ASCII_ZERO ASCII_CRLF
00212
00213 ASCII_CRLF, 5, c->bucket_alloc);
00214 APR_BUCKET_INSERT_BEFORE(eos, e);
00215 }
00216
00217
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
00240
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
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
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,
00315 NULL,
00316 NULL,
00317 NULL,
00318 http_cmds,
00319 register_hooks
00320 };