Changeset 1502
- Timestamp:
- 01/05/2007 04:43:40 AM (22 months ago)
- Location:
- trunk
- Files:
-
- 3 added
- 13 modified
-
configure.in (modified) (1 diff)
-
src/Makefile.am (modified) (3 diffs)
-
src/base.h (modified) (2 diffs)
-
src/chunk.c (modified) (1 diff)
-
src/chunk.h (modified) (1 diff)
-
src/configfile.c (modified) (2 diffs)
-
src/connections.c (modified) (15 diffs)
-
src/filter.c (added)
-
src/filter.h (added)
-
src/mod_chunked.c (added)
-
src/mod_compress.c (modified) (2 diffs)
-
src/mod_proxy_core.c (modified) (2 diffs)
-
src/mod_proxy_core.h (modified) (1 diff)
-
src/mod_proxy_core_protocol.h (modified) (1 diff)
-
src/plugin.c (modified) (5 diffs)
-
src/plugin.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/configure.in
r1481 r1502 569 569 570 570 571 do_build="mod_proxy_core mod_proxy_backend_http mod_proxy_backend_fastcgi mod_proxy_backend_scgi mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_ flv_streaming"571 do_build="mod_proxy_core mod_proxy_backend_http mod_proxy_backend_fastcgi mod_proxy_backend_scgi mod_evhost mod_simple_vhost mod_access mod_alias mod_setenv mod_usertrack mod_auth mod_status mod_accesslog mod_rrdtool mod_secdownload mod_expire mod_compress mod_dirlisting mod_indexfiles mod_userdir mod_webdav mod_staticfile mod_chunked mod_flv_streaming" 572 572 573 573 plugins="mod_rewrite mod_redirect mod_ssi mod_trigger_b4_dl" -
trunk/src/Makefile.am
r1477 r1502 49 49 50 50 common_src=buffer.c log.c \ 51 keyvalue.c chunk.c \51 keyvalue.c chunk.c filter.c \ 52 52 stream.c fdevent.c \ 53 53 stat_cache.c plugin.c joblist.c etag.c array.c \ … … 142 142 mod_staticfile_la_LIBADD = $(common_libadd) 143 143 144 lib_LTLIBRARIES += mod_chunked.la 145 mod_chunked_la_SOURCES = mod_chunked.c 146 mod_chunked_la_LDFLAGS = -module -export-dynamic -avoid-version -no-undefined 147 mod_chunked_la_LIBADD = $(common_libadd) 148 144 149 lib_LTLIBRARIES += mod_dirlisting.la 145 150 mod_dirlisting_la_SOURCES = mod_dirlisting.c … … 273 278 274 279 hdr = server.h buffer.h network.h log.h keyvalue.h \ 275 response.h request.h fastcgi.h chunk.h \280 response.h request.h fastcgi.h chunk.h filter.h \ 276 281 settings.h http_auth_digest.h \ 277 282 md5.h http_auth.h stream.h \ -
trunk/src/base.h
r1496 r1502 20 20 #include "array.h" 21 21 #include "chunk.h" 22 #include "filter.h" 22 23 #include "keyvalue.h" 23 24 #include "settings.h" … … 331 332 int file_started; 332 333 333 chunkqueue *send; /* the response-content without encoding*/334 chunkqueue *send; /* the response-content before filters are applied */ 334 335 chunkqueue *recv; /* the request-content, without encoding */ 335 336 337 filter_chain *send_filters; /* the chain of filters to apply to response-content. */ 336 338 chunkqueue *send_raw; /* the full response (HTTP-Header + compression + chunking ) */ 337 339 chunkqueue *recv_raw; /* the full request (HTTP-Header + chunking ) */ -
trunk/src/chunk.c
r1496 r1502 242 242 243 243 /* 244 * copy/steal all chunks from in chunkqueue. return total bytes copied/stolen. 245 * 246 */ 247 int chunkqueue_steal_all_chunks(chunkqueue *cq, chunkqueue *in) { 248 size_t total = 0; 249 off_t we_have = 0; 250 chunk *c; 251 252 if (!cq || !in) return 0; 253 254 for (c = in->first; c; c = c->next) { 255 switch (c->type) { 256 case MEM_CHUNK: 257 if (c->mem->used == 0) continue; 258 259 we_have = c->mem->used - c->offset - 1; 260 if(we_have == 0) continue; 261 if (c->offset == 0) { 262 chunkqueue_steal_chunk(cq, c); 263 } else { 264 chunkqueue_append_buffer(cq, c->mem); 265 c->offset = c->mem->used - 1; 266 } 267 break; 268 case FILE_CHUNK: 269 if (c->file.length == 0) continue; 270 271 we_have = c->file.length; 272 if(c->file.is_temp) { 273 chunkqueue_steal_tempfile(cq, c); 274 } else { 275 chunkqueue_append_file(cq, c->file.name, c->file.start, c->file.length); 276 } 277 278 c->offset = c->file.length; 279 break; 280 case UNUSED_CHUNK: 281 break; 282 } 283 total += we_have; 284 } 285 286 return total; 287 } 288 289 /* 244 290 * copy/steal max_len bytes from chunk chain. return total bytes copied/stolen. 245 291 * -
trunk/src/chunk.h
r1496 r1502 68 68 int chunkqueue_steal_chunk(chunkqueue *cq, chunk *c); 69 69 int chunkqueue_steal_chunks_len(chunkqueue *cq, chunk *c, size_t max_len); 70 int chunkqueue_steal_all_chunks(chunkqueue *cq, chunkqueue *in); 70 71 int chunkqueue_skip(chunkqueue *cq, off_t skip); 71 72 void chunkqueue_remove_empty_last_chunk(chunkqueue *cq); -
trunk/src/configfile.c
r1443 r1502 1020 1020 array_insert_unique(modules->value, (data_unset *)ds); 1021 1021 } 1022 1023 if (NULL == array_get_element(modules->value, "mod_chunked")) { 1024 ds = data_string_init(); 1025 buffer_copy_string(ds->value, "mod_chunked"); 1026 array_insert_unique(modules->value, (data_unset *)ds); 1027 } 1022 1028 } else { 1023 1029 data_string *ds; … … 1036 1042 ds = data_string_init(); 1037 1043 buffer_copy_string(ds->value, "mod_staticfile"); 1044 array_insert_unique(modules->value, (data_unset *)ds); 1045 1046 ds = data_string_init(); 1047 buffer_copy_string(ds->value, "mod_chunked"); 1038 1048 array_insert_unique(modules->value, (data_unset *)ds); 1039 1049 -
trunk/src/connections.c
r1496 r1502 184 184 185 185 static int connection_handle_response_header(server *srv, connection *con) { 186 data_string *cl;186 int no_response_body = 0; 187 187 188 188 if (con->mode == DIRECT) { … … 214 214 215 215 /* trash the content */ 216 chunkqueue_reset(con->send);216 no_response_body = 1; 217 217 218 218 con->http_status = 200; 219 con->send->is_closed = 1;220 221 219 } 222 220 break; … … 331 329 case 304: 332 330 default: 331 no_response_body = 1; 332 break; 333 } 334 335 if (con->request.http_method == HTTP_METHOD_HEAD) { 336 no_response_body = 1; 337 } 338 339 if (no_response_body) { 333 340 /* disable chunked encoding again as we have no body */ 334 341 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; … … 336 343 337 344 con->send->is_closed = 1; 338 339 break; 340 } 341 342 343 if (con->send->is_closed) { 344 /* we have all the content and chunked encoding is not used, set a content-length */ 345 346 if ((con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED) == 0 && 347 NULL == (cl = (data_string *)array_get_element(con->response.headers, "Content-Length"))) { 348 buffer_copy_off_t(srv->tmp_buf, chunkqueue_length(con->send)); 349 350 response_header_overwrite(srv, con, CONST_STR_LEN("Content-Length"), CONST_BUF_LEN(srv->tmp_buf)); 351 } 352 } else { 353 if (NULL == (cl = (data_string *)array_get_element(con->response.headers, "Content-Length"))) { 354 /* we don't know the size of the content yet 355 * - either enable chunking 356 * - or disable keep-alive */ 357 358 if (con->request.http_version == HTTP_VERSION_1_1) { 359 /* enable chunk-encoding */ 360 con->response.transfer_encoding |= HTTP_TRANSFER_ENCODING_CHUNKED; 361 } else { 362 con->keep_alive = 0; 363 } 364 } 365 } 366 367 if (con->request.http_method == HTTP_METHOD_HEAD) { 368 con->response.transfer_encoding &= ~HTTP_TRANSFER_ENCODING_CHUNKED; 369 chunkqueue_reset(con->send); 370 371 con->send->is_closed = 1; 372 } 373 374 http_response_write_header(srv, con, con->send_raw); 345 } 375 346 376 347 return 0; … … 420 391 421 392 #undef CLEAN 422 con->send = chunkqueue_init(); 393 con->send_filters = filter_chain_init(); 394 /* send is the chunkqueue of the first send filter */ 395 con->send = con->send_filters->first->cq; 423 396 con->recv = chunkqueue_init(); 424 397 … … 453 426 iosocket_free(con->sock); 454 427 455 chunkqueue_free(con->send); 428 filter_chain_free(con->send_filters); 429 con->send = NULL; 456 430 chunkqueue_free(con->recv); 457 431 chunkqueue_free(con->send_raw); … … 566 540 array_reset(con->environment); 567 541 568 chunkqueue_reset(con->send); 542 filter_chain_reset(con->send_filters); 543 con->send = con->send_filters->first->cq; 569 544 chunkqueue_reset(con->recv); 570 545 chunkqueue_reset(con->send_raw); … … 939 914 } 940 915 941 static int http_chunk_append_len(chunkqueue *cq, size_t len) {942 size_t i, olen = len, j;943 buffer *b;944 945 b = buffer_init();946 947 if (len == 0) {948 buffer_copy_string(b, "0");949 } else {950 for (i = 0; i < 8 && len; i++) {951 len >>= 4;952 }953 954 /* i is the number of hex digits we have */955 buffer_prepare_copy(b, i + 1);956 957 for (j = i-1, len = olen; j+1 > 0; j--) {958 b->ptr[j] = (len & 0xf) + (((len & 0xf) <= 9) ? '0' : 'a' - 10);959 len >>= 4;960 }961 b->used = i;962 b->ptr[b->used++] = '\0';963 }964 965 buffer_append_string(b, "\r\n");966 chunkqueue_append_buffer(cq, b);967 len = b->used - 1;968 969 buffer_free(b);970 971 return len;972 }973 974 975 /**976 * apply chunk encoding if necessary977 */978 int http_stream_encoder(server *srv, connection *con, chunkqueue *in, chunkqueue *out) {979 chunk *c;980 int is_chunked;981 int we_have = 0;982 983 UNUSED(srv);984 985 /* no more data to encode. */986 if (out->is_closed) return 0;987 /**/988 989 is_chunked = (con->response.transfer_encoding & HTTP_TRANSFER_ENCODING_CHUNKED);990 991 if (is_chunked) {992 for (c = in->first; c; c = c->next) {993 switch (c->type) {994 case MEM_CHUNK:995 if (c->mem->used == 0) continue;996 997 we_have = c->mem->used - c->offset - 1;998 in->bytes_out += we_have;999 if(we_have == 0) continue;1000 we_have += http_chunk_append_len(out, we_have);1001 chunkqueue_append_buffer(out, c->mem);1002 c->offset = c->mem->used - 1;1003 break;1004 case FILE_CHUNK:1005 if (c->file.length == 0) continue;1006 1007 we_have = c->file.length;1008 in->bytes_out += we_have;1009 we_have += http_chunk_append_len(out, c->file.length);1010 if(c->file.is_temp) {1011 chunkqueue_steal_tempfile(out, c);1012 } else {1013 chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);1014 }1015 1016 c->offset = c->file.length;1017 break;1018 case UNUSED_CHUNK:1019 break;1020 }1021 chunkqueue_append_mem(out, "\r\n", 2 + 1);1022 we_have += 2;1023 out->bytes_in += we_have;1024 }1025 if (in->is_closed) {1026 chunkqueue_append_mem(out, "0\r\n\r\n", 5 + 1);1027 out->bytes_in += 5;1028 }1029 } else {1030 for (c = in->first; c; c = c->next) {1031 switch (c->type) {1032 case MEM_CHUNK:1033 if (c->mem->used == 0) continue;1034 1035 we_have = c->mem->used - c->offset - 1;1036 in->bytes_out += we_have;1037 if(we_have == 0) continue;1038 if (c->offset == 0) {1039 chunkqueue_steal_chunk(out, c);1040 } else {1041 chunkqueue_append_buffer(out, c->mem);1042 c->offset = c->mem->used - 1;1043 }1044 break;1045 case FILE_CHUNK:1046 if (c->file.length == 0) continue;1047 1048 we_have = c->file.length;1049 in->bytes_out += we_have;1050 if(c->file.is_temp) {1051 chunkqueue_steal_tempfile(out, c);1052 } else {1053 chunkqueue_append_file(out, c->file.name, c->file.start, c->file.length);1054 }1055 1056 c->offset = c->file.length;1057 break;1058 case UNUSED_CHUNK:1059 break;1060 }1061 in->bytes_out += we_have;1062 out->bytes_in += we_have;1063 }1064 }1065 1066 chunkqueue_remove_finished_chunks(in);1067 1068 if (in->is_closed) {1069 /* mark the output queue as finished. */1070 out->is_closed = 1;1071 }1072 return 0;1073 }1074 1075 916 int connection_state_machine(server *srv, connection *con) { 1076 917 int done = 0, r; … … 1296 1137 con->request.content_length == 0) { 1297 1138 con->recv->is_closed = 1; 1298 }1139 } 1299 1140 1300 1141 if (!con->recv->is_closed && … … 1356 1197 break; 1357 1198 case CON_STATE_HANDLE_RESPONSE_HEADER: 1199 /* handle the HTTP response headers, or generate error-page */ 1200 connection_handle_response_header(srv, con); 1201 1358 1202 /* we got a response header from the backend 1359 1203 * call all plugins who want to modify the response header … … 1362 1206 * 1363 1207 */ 1208 switch (plugins_call_handle_response_header(srv, con)) { 1209 case HANDLER_GO_ON: 1210 default: 1211 break; 1212 } 1364 1213 1365 1214 connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_HEADER); … … 1367 1216 break; 1368 1217 case CON_STATE_WRITE_RESPONSE_HEADER: 1369 /* create the HTTP response header*/1370 connection_handle_response_header(srv, con);1218 /* write response headers */ 1219 http_response_write_header(srv, con, con->send_raw); 1371 1220 1372 1221 connection_set_state(srv, con, CON_STATE_WRITE_RESPONSE_CONTENT); … … 1375 1224 case CON_STATE_WRITE_RESPONSE_CONTENT: 1376 1225 fdevent_event_del(srv->ev, con->sock); 1226 1227 /* looks like we shall read some content from the backend */ 1228 switch (plugins_call_handle_read_response_content(srv, con)) { 1229 case HANDLER_WAIT_FOR_EVENT: 1230 if (!con->send->is_closed && con->send->bytes_in == con->send->bytes_out) { 1231 /* need to wait for more data */ 1232 return HANDLER_WAIT_FOR_EVENT; 1233 } 1234 break; 1235 case HANDLER_GO_ON: 1236 default: 1237 break; 1238 } 1377 1239 1378 1240 /* we might have new content in the con->send buffer … … 1381 1243 * - compression 1382 1244 */ 1383 1384 /* looks like we shall read some content from the backend */ 1385 1386 switch (plugins_call_handle_read_response_content(srv, con)) { 1245 switch (plugins_call_handle_filter_response_content(srv, con)) { 1387 1246 case HANDLER_GO_ON: 1388 1247 default: … … 1390 1249 } 1391 1250 1392 http_stream_encoder(srv, con, con->send, con->send_raw); 1393 1251 /* copy output from filters into send_raw. */ 1252 r = filter_chain_copy_output(con->send_filters, con->send_raw); 1253 1254 if (!con->send_raw->is_closed && con->send_raw->bytes_in == con->send_raw->bytes_out) { 1255 return HANDLER_WAIT_FOR_EVENT; 1256 } 1394 1257 switch(network_write_chunkqueue(srv, con, con->send_raw)) { 1395 1258 case NETWORK_STATUS_SUCCESS: -
trunk/src/mod_compress.c
r1499 r1502 424 424 /* file exists */ 425 425 426 chunkqueue_append_file(con->send _raw, p->ofn, 0, compressed_sce->st.st_size);426 chunkqueue_append_file(con->send, p->ofn, 0, compressed_sce->st.st_size); 427 427 con->send->is_closed = 1; 428 428 … … 500 500 if (ret != 0) return -1; 501 501 502 chunkqueue_append_file(con->send _raw, p->ofn, 0, r);502 chunkqueue_append_file(con->send, p->ofn, 0, r); 503 503 con->send->is_closed = 1; 504 504 -
trunk/src/mod_proxy_core.c
r1496 r1502 698 698 } 699 699 700 /* we are finished decoding the response content. */ 701 if(out->is_closed) { 702 proxy_copy_response(srv, con, sess); 703 } else { 700 /* we are finished decoding the response headers. */ 701 if(!out->is_closed) { 704 702 /* We don't have all the response content try to enable chunked encoding. */ 705 703 /* does the client allow us to send chunked encoding ? */ … … 709 707 } 710 708 } 709 710 /* we might have part of the response content too */ 711 proxy_copy_response(srv, con, sess); 711 712 712 713 return PARSE_SUCCESS; /* we have a full header */ -
trunk/src/mod_proxy_core.h
r1496 r1502 67 67 } proxy_state_t; 68 68 69 typedef struct {69 typedef struct proxy_session { 70 70 proxy_connection *proxy_con; 71 71 proxy_backend *proxy_backend; -
trunk/src/mod_proxy_core_protocol.h
r1465 r1502 12 12 static int x(server *srv, proxy_session *sess, chunkqueue *in, chunkqueue *out) 13 13 14 typedef struct {14 typedef struct proxy_protocol { 15 15 buffer *name; 16 16 -
trunk/src/plugin.c
r1496 r1502 41 41 PLUGIN_FUNC_HANDLE_START_BACKEND, 42 42 PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, 43 PLUGIN_FUNC_HANDLE_RESPONSE_HEADER, 43 44 PLUGIN_FUNC_HANDLE_READ_RESPONSE_CONTENT, 45 PLUGIN_FUNC_HANDLE_FILTER_RESPONSE_CONTENT, 44 46 PLUGIN_FUNC_HANDLE_JOBLIST, 45 47 PLUGIN_FUNC_HANDLE_DOCROOT, … … 122 124 PLUGIN_STATIC(mod_evhost); 123 125 PLUGIN_STATIC(mod_expire); 126 PLUGIN_STATIC(mod_chunked); 124 127 PLUGIN_STATIC(mod_indexfile); 125 128 PLUGIN_STATIC(mod_mysql_vhost); … … 157 160 PLUGIN_STATIC(mod_evhost), 158 161 PLUGIN_STATIC(mod_expire), 162 PLUGIN_STATIC(mod_chunked), 159 163 PLUGIN_STATIC(mod_indexfile), 160 164 PLUGIN_STATIC(mod_mysql_vhost), … … 366 370 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend) 367 371 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content) 372 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_HEADER, handle_response_header) 368 373 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_READ_RESPONSE_CONTENT, handle_read_response_content) 374 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_FILTER_RESPONSE_CONTENT, handle_filter_response_content) 369 375 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close) 370 376 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_DONE, handle_response_done) … … 494 500 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_START_BACKEND, handle_start_backend); 495 501 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SEND_REQUEST_CONTENT, handle_send_request_content); 502 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_RESPONSE_HEADER, handle_response_header); 496 503 PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_READ_RESPONSE_CONTENT, handle_read_res
