WEBBY - the embedded web server with many faces / objects in plain C Snapshot
|
00001 #include "webby.h" 00002 #include "webbyimpl.h" 00003 #include <hutils/http.h> 00004 #include <string.h> 00005 #include <stdio.h> 00006 #include <cutils/properties.h> 00007 #include <butils/logg.h> 00008 00009 00010 // ==================================================================== 00011 #define RESERVED_FOR_CHUNK_HEADER_SIZE 15 00012 00013 #define LAST_CHUNK_NOT_FIRST "\r\n0\r\n\r\n" 00014 #define LAST_CHUNK_NOT_FIRST_SIZE 7 00015 00016 #define LAST_CHUNK_FIRST "0\r\n\r\n" 00017 #define LAST_CHUNK_FIRST_SIZE 5 00018 00019 #define HTTP_100_CONTINUE_RESPONSE "HTTP/1.1 100 Continue\r\n\r\n" 00020 #define HTTP_100_CONTINUE_RESPONSE_LEN 25 00021 00022 #define HTTP_400_BAD_REQUEST "HTTP/1.1 400 Bad Request\r\nContent-Length: 0\r\n\r\n" 00023 #define HTTP_400_BAD_REQUEST_LEN 47 00024 00025 #define HTTP_404_NOT_FOUND "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n" 00026 #define HTTP_404_NOT_FOUND_LEN 45 00027 00028 #define HTTP_500_SERVER_ERROR "HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n" 00029 #define HTTP_500_SERVER_ERROR_LEN 57 00030 00031 00032 // ==================================================================== 00033 typedef struct tagVIRTUAL_HOST_DEFINITION { 00034 char *host; 00035 int host_port; 00036 00037 size_t next_filter_idx; 00038 size_t last_filter_idx; 00039 00040 } VIRTUAL_HOST_DEFINITION; 00041 00042 typedef struct tagDATA_SINK_FILTER { 00043 HTTP_FILTER base; 00044 00045 ARRAY vhosts; 00046 VIRTUAL_HOST_DEFINITION default_vhost; 00047 WEBBY *server; 00048 00049 } DATA_SINK_FILTER; 00050 00051 typedef struct tagDATA_SINK_FILTER_CONNECTION_CONTEXT { 00052 BF *out_buf; 00053 HTTP_RESPONSE_WRITER writer; 00054 void *impl_connection_ctx; 00055 00056 size_t next_request_filter; 00057 00058 } DATA_SINK_FILTER_CONNECTION_CONTEXT; 00059 00060 00061 DATA_SINK_FILTER_CONNECTION_CONTEXT *DATA_SINK_FILTER_CONNECTION_CONTEXT_init(void *impl_connection_ctx, BF *out_buf) 00062 { 00063 DATA_SINK_FILTER_CONNECTION_CONTEXT *ret; 00064 00065 ret = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) malloc( sizeof( DATA_SINK_FILTER_CONNECTION_CONTEXT ) ); 00066 if (!ret) { 00067 return 0; 00068 } 00069 ret->impl_connection_ctx = impl_connection_ctx; 00070 ret->out_buf = out_buf; 00071 ret->next_request_filter = (size_t) -1; 00072 00073 return ret; 00074 } 00075 00076 void DATA_SINK_FILTER_CONNECTION_CONTEXT_free( DATA_SINK_FILTER_CONNECTION_CONTEXT *ctx) 00077 { 00078 free(ctx); 00079 } 00080 00081 static int sink_req_header_parsed(HTTP_REQUEST *request, FILTER_CONTEXT *context ) 00082 { 00083 DATA_SINK_FILTER *sink_filter; 00084 DATA_SINK_FILTER_CONNECTION_CONTEXT *sink; 00085 VIRTUAL_HOST_DEFINITION *vhosts_def; 00086 size_t i, found; 00087 RDATA rd; 00088 00089 00090 // no host header in HTTP 1.0; go to the next filter. 00091 if (request->version == HTTP_VERSION_1_0) { 00092 return call_next_filter_request_header_parsed( request, context ); 00093 } 00094 00095 // presence of Host header is absolutely required with HTTP/1.1 00096 if (!request->has_host_header) { 00097 MLOG_INFO( "HTTP/1.1 no host header" ); 00098 goto bad_request; 00099 } 00100 00101 sink_filter = (DATA_SINK_FILTER *) context->filter; 00102 if (ARRAY_size( &sink_filter->vhosts ) == 0) { 00103 return call_next_filter_request_header_parsed( request, context ); 00104 } 00105 00106 // find which virtua host corresponds to the request host entry 00107 for( found = i = 0, vhosts_def = (VIRTUAL_HOST_DEFINITION *) ARRAY_at( &sink_filter->vhosts, 0 ); 00108 i < ARRAY_size( &sink_filter->vhosts); 00109 ++i, ++vhosts_def ) { 00110 00111 if ( strcmp( request->host_header, vhosts_def->host ) == 0 && request->host_header_port == vhosts_def->host_port) { 00112 found = 1; 00113 break; 00114 } 00115 } 00116 00117 if (!found) { 00118 MLOG_INFO( "Host header %s %d does not correspond to any virtual hosts", request->host_header, request->host_header_port ); 00119 goto bad_request; 00120 } 00121 00122 // now that the virtual host is found - remember the next filter index for the following notifications. 00123 sink = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) context; 00124 sink->next_request_filter = vhosts_def->next_filter_idx; 00125 00126 // call next filter. 00127 context = context + vhosts_def->next_filter_idx; 00128 return context->filter->on_request_header_parsed( request, context ); 00129 00130 bad_request: 00131 rd.no_chunk.data = HTTP_400_BAD_REQUEST; 00132 rd.no_chunk.data_size = HTTP_400_BAD_REQUEST_LEN; 00133 00134 context->filter->on_response_data( 0, 0, rd, context ); 00135 //call_next_filter_response_data( 0, 0, rd, context ); 00136 return -1; 00137 00138 } 00139 00140 00141 00142 static int sink_req_data(HTTP_REQUEST *request, void *data, size_t data_size, FILTER_CONTEXT *context ) 00143 { 00144 DATA_SINK_FILTER_CONNECTION_CONTEXT * sink; 00145 00146 sink = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) context; 00147 if (sink->next_request_filter == (size_t) -1) { 00148 return call_next_filter_request_data( request, data, data_size, context ); 00149 } 00150 00151 context = context + sink->next_request_filter; 00152 return context->filter->on_request_data( request, data, data_size, context ); 00153 } 00154 00155 static int sink_req_completed( HTTP_REQUEST *request, FILTER_CONTEXT *context ) 00156 { 00157 DATA_SINK_FILTER_CONNECTION_CONTEXT * sink; 00158 00159 sink = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) context; 00160 if (sink->next_request_filter == (size_t) -1) { 00161 return call_next_filter_request_completed( request, context ); 00162 } 00163 00164 context = context + sink->next_request_filter; 00165 return context->filter->on_request_completed( request, context ); 00166 } 00167 00168 static int sink_on_response_header (HTTP_RESPONSE *response, FILTER_CONTEXT *context ) 00169 { 00170 DATA_SINK_FILTER_CONNECTION_CONTEXT *sink = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) context->connection_ctx; 00171 BF *bf; 00172 PARSER_STATUS stat; 00173 bf = sink->out_buf; 00174 HTTP_RESPONSE_WRITER_init( &sink->writer, response ); 00175 00176 while(1) { 00177 stat = HTTP_RESPONSE_WRITER_write( &sink->writer, bf ); 00178 switch(stat) { 00179 case PARSER_STATUS_ERROR: 00180 MLOG_INFO( "Failed to format response header" ); 00181 return -1; 00182 case PARSER_STATUS_COMPLETED: 00183 if (WEBBY_impl_send_data( sink->impl_connection_ctx, bf->get_pos, BF_get_size( bf ) ) ) { 00184 MLOG_INFO( "Failed to send response header" ); 00185 return -1; 00186 } 00187 return 0; 00188 00189 case PARSER_STATUS_NEED_MORE_DATA: 00190 if (WEBBY_impl_send_data( sink->impl_connection_ctx, bf->get_pos, BF_get_size( bf ) ) ) { 00191 MLOG_INFO( "Failed to send response header" ); 00192 return -1; 00193 } 00194 break; 00195 } 00196 } while( 1 ); 00197 00198 } 00199 00200 static int sink_on_response_data (HTTP_RESPONSE *response, int is_chunk, RDATA rdata, FILTER_CONTEXT *context ) 00201 { 00202 DATA_SINK_FILTER_CONNECTION_CONTEXT *sink = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) context->connection_ctx; 00203 BF *bf; 00204 void *data; 00205 size_t size; 00206 int len; 00207 char chunk_header[ 20 ]; 00208 00209 M_UNUSED( response ); 00210 00211 if (!is_chunk) { 00212 return WEBBY_impl_send_data( sink->impl_connection_ctx, rdata.no_chunk.data, rdata.no_chunk.data_size ); 00213 } 00214 00215 bf = rdata.chunk.bf; 00216 if (bf) { 00217 if (rdata.chunk.chunk_no) { 00218 len = snprintf( chunk_header, sizeof( chunk_header ), "\r\n%x\r\n", BF_get_size(bf) ); 00219 } else { 00220 len = snprintf( chunk_header, sizeof( chunk_header ), "%x\r\n", BF_get_size(bf) ); 00221 } 00222 if ( (bf->start - bf->bf) < len) { 00223 MLOG_INFO( "Failed to send chunk - buffer did not reserved enough room before start of chunk data" ); 00224 return -1; 00225 } 00226 bf->start -= len; 00227 strncpy( (char *) bf->start, chunk_header, len ); 00228 00229 if (WEBBY_impl_send_data( sink->impl_connection_ctx, bf->start, bf->put_pos - bf->start )) { 00230 MLOG_INFO( "Failed to send chunk data" ); 00231 } 00232 00233 } else { 00234 00235 if (rdata.chunk.chunk_no) { 00236 data = LAST_CHUNK_NOT_FIRST; 00237 size = LAST_CHUNK_NOT_FIRST_SIZE; 00238 } else { 00239 data = LAST_CHUNK_FIRST; 00240 size = LAST_CHUNK_FIRST_SIZE; 00241 } 00242 if (WEBBY_impl_send_data( sink->impl_connection_ctx, data, size )) { 00243 MLOG_INFO( "Failed to send chunk data" ); 00244 } 00245 00246 } 00247 return 0; 00248 } 00249 00250 00251 static int sink_on_response_complete (HTTP_RESPONSE *response, FILTER_CONTEXT *context ) 00252 { 00253 DATA_SINK_FILTER_CONNECTION_CONTEXT *sink = (DATA_SINK_FILTER_CONNECTION_CONTEXT *) context->connection_ctx; 00254 00255 M_UNUSED( response ); 00256 00257 return WEBBY_impl_response_completed( sink->impl_connection_ctx, response->base.flags & HTTP_MESSAGE_FLAG_CONNECTION_CLOSE ); 00258 } 00259 00260 static int sink_connection_close( FILTER_CONTEXT *context ) 00261 { 00262 if (context->connection_ctx) { 00263 free( context->connection_ctx); 00264 } 00265 return 0; 00266 } 00267 00268 DATA_SINK_FILTER *DATA_SINK_FILTER_init(WEBBY *server) 00269 { 00270 DATA_SINK_FILTER * ret; 00271 00272 ret = (DATA_SINK_FILTER *) malloc( sizeof( DATA_SINK_FILTER ) ); 00273 if (!ret) { 00274 return 0; 00275 } 00276 00277 ret->base.on_request_header_parsed = sink_req_header_parsed; 00278 ret->base.on_request_data = sink_req_data; 00279 ret->base.on_request_completed = sink_req_completed; 00280 ret->base.on_response_header = sink_on_response_header; 00281 ret->base.on_response_data = sink_on_response_data; 00282 ret->base.on_response_completed = sink_on_response_complete; 00283 ret->base.on_connection_close = sink_connection_close; 00284 00285 ret->server = server; 00286 00287 memset( &ret->default_vhost, 0, sizeof( VIRTUAL_HOST_DEFINITION ) ); 00288 ret->default_vhost.next_filter_idx = ret->default_vhost.last_filter_idx = (size_t) -1; 00289 00290 if (ARRAY_init( &ret->vhosts, sizeof( VIRTUAL_HOST_DEFINITION ), 10 )) { 00291 return 0; 00292 } 00293 00294 return ret; 00295 } 00296 00297 int DATA_SINK_FILTER_add_vhost( DATA_SINK_FILTER *vhost_filter, const char *host, int port_num, size_t * vhost_idx ) 00298 { 00299 VIRTUAL_HOST_DEFINITION def; 00300 00301 def.host = strdup(host); 00302 def.host_port = port_num; 00303 def.next_filter_idx = def.last_filter_idx = (size_t) -1; 00304 00305 *vhost_idx = ARRAY_size( &vhost_filter->vhosts ) ; 00306 00307 if ( ARRAY_push_back( &vhost_filter->vhosts, &def, sizeof( VIRTUAL_HOST_DEFINITION ) ) ) { 00308 return -1; 00309 } 00310 return 0; 00311 } 00312 00313 int DATA_SINK_FILTER_add_filter_to_vhost( DATA_SINK_FILTER *vhost_filter, size_t vhost_idx, HTTP_FILTER *new_filter ) 00314 { 00315 size_t filter_idx; 00316 VIRTUAL_HOST_DEFINITION *vhost; 00317 HTTP_FILTER *last_filter; 00318 HTTP_FILTER **tmp; 00319 int is_default_vhost; 00320 00321 // get virtual host defnition 00322 if (ARRAY_size( &vhost_filter->vhosts ) == 0) { 00323 vhost = &vhost_filter->default_vhost; 00324 is_default_vhost = 1; 00325 } else { 00326 vhost = (VIRTUAL_HOST_DEFINITION *) ARRAY_at( &vhost_filter->vhosts, vhost_idx ); 00327 is_default_vhost = 0; 00328 } 00329 if (!vhost) { 00330 return -1; 00331 } 00332 00333 // insert the new filter 00334 if (ARRAY_push_back( &vhost_filter->server->filters, &new_filter, sizeof(void *) ) ) { 00335 return -1; 00336 } 00337 filter_idx = ARRAY_size( &vhost_filter->server->filters ) - 1; 00338 00339 00340 // update virtual host filter chain. 00341 if (vhost->next_filter_idx == (size_t) -1) { 00342 vhost->next_filter_idx = filter_idx; 00343 vhost->last_filter_idx = filter_idx; 00344 00345 new_filter->next_request_filter_idx = (size_t) -1; ; 00346 new_filter->next_response_filter_idx = 0; 00347 00348 if (is_default_vhost) { 00349 vhost_filter->base.next_request_filter_idx = filter_idx; 00350 vhost_filter->base.next_response_filter_idx = (size_t) -1; 00351 } 00352 } else { 00353 new_filter->next_response_filter_idx = vhost->last_filter_idx; 00354 new_filter->next_request_filter_idx = (size_t) -1; 00355 00356 tmp = (HTTP_FILTER **) ARRAY_at( &vhost_filter->server->filters, vhost->next_filter_idx ); 00357 last_filter = *tmp; 00358 last_filter->next_request_filter_idx = filter_idx; 00359 00360 vhost->last_filter_idx = filter_idx; 00361 } 00362 return 0; 00363 } 00364 00365 // ==================================================================== 00366 00367 typedef struct tagSERVLET_RUNNER_FILTER 00368 { 00369 HTTP_FILTER base; 00370 ARRAY servlets; 00371 } SERVLET_RUNNER_FILTER; 00372 00373 typedef struct SERVLET_FILTER_CONNECTION_CONTEXT 00374 { 00375 HTTP_servlet_request request; 00376 HTTP_servlet_response response; 00377 DBUF request_data; 00378 DBUF *buff; 00379 00380 SERVLET_CONTEXT *servlet_contexts; 00381 00382 } SERVLET_FILTER_CONNECTION_CONTEXT; 00383 00384 00385 SERVLET_FILTER_CONNECTION_CONTEXT * SERVLET_FILTER_CONNECTION_CONTEXT_init(SERVLET_RUNNER_FILTER *rfilter) 00386 { 00387 size_t nservlets; 00388 SERVLET_FILTER_CONNECTION_CONTEXT *ret; 00389 SERVLET_CONTEXT *cur; 00390 HTTP_SERVLET **tmp; 00391 size_t i; 00392 00393 00394 nservlets = ARRAY_size( &rfilter->servlets ); 00395 00396 ret = malloc( sizeof( SERVLET_FILTER_CONNECTION_CONTEXT ) ); 00397 if (!ret) { 00398 return 0; 00399 } 00400 00401 ret->servlet_contexts = (SERVLET_CONTEXT *) malloc( nservlets * sizeof( SERVLET_CONTEXT ) ); 00402 if (!ret->servlet_contexts) { 00403 return 0; 00404 } 00405 00406 for( i = 0, cur = ret->servlet_contexts; i < nservlets; ++i, ++cur) { 00407 cur->connection_ctx = 0; 00408 00409 tmp = (HTTP_SERVLET **) ARRAY_at( &rfilter->servlets, i ); 00410 cur->servlet = *tmp; 00411 } 00412 00413 DBUF_init( &ret->request_data, 0 ); 00414 HTTP_RESPONSE_init( &ret->response.response, HTTP_VERSION_1_1, 501 ); 00415 00416 return ret; 00417 } 00418 00419 00420 static int servlets_req_header_parsed (HTTP_REQUEST *request, FILTER_CONTEXT *context ) 00421 { 00422 M_UNUSED( request ); 00423 00424 if (!context->connection_ctx) { 00425 context->connection_ctx = SERVLET_FILTER_CONNECTION_CONTEXT_init( (SERVLET_RUNNER_FILTER *) context->filter ); 00426 } 00427 if (! context->connection_ctx) { 00428 return -1; 00429 } 00430 00431 return 0; 00432 } 00433 00434 00435 static int servlets_req_on_message_data (HTTP_REQUEST *request, void *data, size_t data_size, FILTER_CONTEXT *context ) 00436 { 00437 SERVLET_FILTER_CONNECTION_CONTEXT *fcontext = (SERVLET_FILTER_CONNECTION_CONTEXT * ) context->connection_ctx; 00438 00439 M_UNUSED( request ); 00440 return DBUF_add( &fcontext->request_data, data, data_size ); 00441 } 00442 00443 00444 static int servlets_req_finished (HTTP_REQUEST *request, FILTER_CONTEXT *context ) 00445 { 00446 size_t i; 00447 RDATA rd; 00448 00449 SERVLET_FILTER_CONNECTION_CONTEXT *fcontext = (SERVLET_FILTER_CONNECTION_CONTEXT * ) context->connection_ctx; 00450 SERVLET_RUNNER_FILTER *runner = (SERVLET_RUNNER_FILTER *) context->filter; 00451 SERVLET_CONTEXT *scontext; 00452 SERVLET_STATUS status; 00453 00454 if ( request->expect_100_continue) { 00455 00456 rd.no_chunk.data = HTTP_100_CONTINUE_RESPONSE; 00457 rd.no_chunk.data_size = HTTP_100_CONTINUE_RESPONSE_LEN; 00458 00459 if (call_next_filter_response_data ( 0, 0, rd, context ) ) { 00460 return -1; 00461 } 00462 } 00463 00464 fcontext->request.request = request; 00465 fcontext->request.request_data = fcontext->buff; 00466 00467 HTTP_RESPONSE_free( &fcontext->response.response ); 00468 HTTP_RESPONSE_init( &fcontext->response.response, request->version, 501 ); 00469 fcontext->response.request = request; 00470 fcontext->response.filter_context = context; 00471 fcontext->response.data_sent = 0; 00472 fcontext->response.state = 0; 00473 fcontext->response.chunk_buf = 0; 00474 fcontext->response.chunk_buf_size = 0; 00475 fcontext->response.chunk_no = 0; 00476 00477 00478 00479 for(i = 0, scontext = (SERVLET_CONTEXT *) fcontext->servlet_contexts; i < ARRAY_size( &runner->servlets ); ++i, ++scontext) { 00480 status = scontext->servlet->servlet_action( &fcontext->request, &fcontext->response, scontext ); 00481 if (status == SERVLET_REQUEST_HANDLED) { 00482 return 0; 00483 } 00484 if (status == SERVLET_REQUEST_ERROR) { 00485 00486 rd.no_chunk.data = HTTP_500_SERVER_ERROR; 00487 rd.no_chunk.data_size = HTTP_500_SERVER_ERROR_LEN; 00488 00489 call_next_filter_response_data( 0, 0, rd, context ); 00490 return -1; 00491 } 00492 } 00493 00494 rd.no_chunk.data = HTTP_404_NOT_FOUND; 00495 rd.no_chunk.data_size = HTTP_404_NOT_FOUND_LEN; 00496 00497 call_next_filter_response_data( 0, 0, rd, context ); 00498 00499 return 0; 00500 } 00501 00502 static int servlets_connection_close (FILTER_CONTEXT *context) 00503 { 00504 size_t i; 00505 SERVLET_FILTER_CONNECTION_CONTEXT *fcontext = (SERVLET_FILTER_CONNECTION_CONTEXT * ) context->connection_ctx; 00506 SERVLET_RUNNER_FILTER *runner = (SERVLET_RUNNER_FILTER *) context->filter; 00507 SERVLET_CONTEXT *scontext; 00508 00509 if (!fcontext->servlet_contexts) { 00510 return 0; 00511 } 00512 00513 for(i = 0, scontext = (SERVLET_CONTEXT *) fcontext->servlet_contexts; i < ARRAY_size( &runner->servlets ); ++i, ++scontext) { 00514 if (scontext->servlet->free_connection) { 00515 scontext->servlet->free_connection( scontext ); 00516 } 00517 } 00518 return 0; 00519 } 00520 00521 SERVLET_RUNNER_FILTER *SERVLET_RUNNER_FILTER_init() 00522 { 00523 SERVLET_RUNNER_FILTER *ret; 00524 00525 ret = (SERVLET_RUNNER_FILTER *) malloc( sizeof( SERVLET_RUNNER_FILTER ) ); 00526 if (!ret) { 00527 return 0; 00528 } 00529 00530 memset( &ret->base, 0, sizeof( HTTP_FILTER ) ); 00531 ret->base.on_request_header_parsed = servlets_req_header_parsed; 00532 ret->base.on_request_data = servlets_req_on_message_data; 00533 ret->base.on_request_completed = servlets_req_finished; 00534 ret->base.on_connection_close = servlets_connection_close; 00535 00536 if (ARRAY_init( &ret->servlets, sizeof( void * ), 10 ) ) { 00537 free( ret ); 00538 return 0; 00539 } 00540 00541 return ret; 00542 } 00543 00544 void SERVLET_RUNNER_FILTER_free(SERVLET_RUNNER_FILTER *servlets) 00545 { 00546 size_t i; 00547 HTTP_SERVLET *servlet; 00548 00549 for(i = 0; i < ARRAY_size( &servlets->servlets ); i++) { 00550 servlet = (HTTP_SERVLET *) ARRAY_at( &servlets->servlets, i ); 00551 if (servlet->free_servlet) { 00552 servlet->free_servlet( servlet ); 00553 } 00554 } 00555 ARRAY_free( &servlets->servlets ); 00556 free( servlets ); 00557 } 00558 00559 int SERVLET_RUNNER_FILTER_add_servlet( SERVLET_RUNNER_FILTER *servlets, HTTP_SERVLET *servlet ) 00560 { 00561 if (servlet->init_servlet) { 00562 if (servlet->init_servlet( servlet )) { 00563 return -1; 00564 } 00565 } 00566 return ARRAY_push_back( &servlets->servlets, &servlet, sizeof( void * ) ); 00567 } 00568 00569 // ==================================================================== 00570 int WEBBY_CONFIG_load( WEBBY_CONFIG *cfg, const char *file) 00571 { 00572 PROPERTIES props; 00573 const char *tmp; 00574 IPADDRESS addr; 00575 uint16_t port; 00576 00577 if (PROPERTIES_init( &props, 30 )) { 00578 return -1; 00579 } 00580 if (PROPERTIES_load( &props, file )) { 00581 return -1; 00582 } 00583 00584 tmp = PROPERTIES_get( &props, "host" ); 00585 if (!tmp) { 00586 MLOG_ERROR( "Missing configuration parameter: host" ); 00587 return -1; 00588 } 00589 00590 if ( IPADDRESS_parse_string( &addr, tmp ) ) { 00591 MLOG_ERROR( "invalid configuration parameter: host" ); 00592 return -1; 00593 } 00594 00595 if (PROPERTIES_dec_uint16_t( &props, "port", &port)) { 00596 MLOG_ERROR( "Missing/Invalid configuration parameter: port" ); 00597 return -1; 00598 } 00599 00600 if (SOCKADDR_init( &cfg->listening_address, &addr, (uint16_t) port ) ) { 00601 MLOG_ERROR( "Missing/Invalid host/port configuration" ); 00602 return -1; 00603 } 00604 00605 if (PROPERTIES_dec_int32_t( &props, "listen_backlog", &cfg->listen_backlog)) { 00606 MLOG_ERROR( "Missing/Invalid configuration parameter: listen_backlog" ); 00607 return -1; 00608 } 00609 00610 if (PROPERTIES_dec_int32_t( &props, "socket_buffer_size", &cfg->socket_buffer_size)) { 00611 MLOG_ERROR( "Missing/Invalid configuration parameter: listen_backlog" ); 00612 return -1; 00613 } 00614 00615 if (PROPERTIES_dec_int32_t( &props, "max_connections", &cfg->max_connections)) { 00616 MLOG_ERROR( "Missing/Invalid configuration parameter: max_connections" ); 00617 return -1; 00618 } 00619 00620 if (PROPERTIES_dec_int32_t( &props, "io_timeout", &cfg->io_timeout)) { 00621 MLOG_ERROR( "Missing/Invalid configuration parameter: io_timeout" ); 00622 return -1; 00623 } 00624 00625 if (PROPERTIES_dec_int32_t( &props, "idle_timeout", &cfg->idle_timeout)) { 00626 MLOG_ERROR( "Missing/Invalid configuration parameter: idle_timeout" ); 00627 return -1; 00628 } 00629 00630 if (PROPERTIES_dec_int32_t( &props, "stack_pages_per_thread", &cfg->stack_pages_per_thread)) { 00631 MLOG_ERROR( "Missing/Invalid configuration parameter: stack_pages_per_thread"); 00632 return -1; 00633 } 00634 PROPERTIES_free( &props ); 00635 return 0; 00636 } 00637 00638 // ==================================================================== 00639 00640 WEBBY *WEBBY_init( WEBBY_CONFIG * cfg ) 00641 { 00642 WEBBY *ret; 00643 DATA_SINK_FILTER *data_sink; 00644 00645 00646 ret = (WEBBY *) malloc( sizeof( WEBBY ) ); 00647 if (!ret) { 00648 return 0; 00649 } 00650 ret->cfg = cfg; 00651 00652 00653 if ( ARRAY_init( &ret->filters, sizeof( HTTP_FILTER * ), 10 ) ) { 00654 return 0; 00655 } 00656 00657 // first filter is sink filter - receives response data. 00658 data_sink = DATA_SINK_FILTER_init( ret ); 00659 if (!data_sink) { 00660 return 0; 00661 } 00662 ARRAY_push_back( &ret->filters, &data_sink, sizeof( void * ) ); 00663 ret->sink_filter = data_sink; 00664 00665 ret->servlet_runner_filter = SERVLET_RUNNER_FILTER_init(); 00666 if (!ret->servlet_runner_filter) { 00667 return 0; 00668 } 00669 00670 // get the implementation object. 00671 if (WEBBY_impl_new( ret, cfg, &ret->impl ) ) { 00672 return 0; 00673 } 00674 return ret; 00675 } 00676 00677 int WEBBY_add_vhost( WEBBY *server, const char *host, int port_num, size_t * vhost_idx ) 00678 { 00679 return DATA_SINK_FILTER_add_vhost( server->sink_filter, host, port_num, vhost_idx ); 00680 } 00681 00682 int WEBBY_add_filter( WEBBY *server, size_t vhost_idx, HTTP_FILTER *filter ) 00683 { 00684 return DATA_SINK_FILTER_add_filter_to_vhost( server->sink_filter, vhost_idx, filter ); 00685 } 00686 00687 int WEBBY_add_servlet( WEBBY *server, HTTP_SERVLET * servlet ) 00688 { 00689 return SERVLET_RUNNER_FILTER_add_servlet( server->servlet_runner_filter, servlet ); 00690 } 00691 00692 00693 int WEBBY_run( WEBBY *server ) 00694 { 00695 FILTER_CONTEXT *cur,*layout; 00696 HTTP_FILTER **tmp; 00697 size_t i; 00698 00699 if (WEBBY_add_filter( server, 0, &server->servlet_runner_filter->base ) ) { 00700 return -1; 00701 } 00702 00703 server->filter_ctx_layout_size = sizeof( FILTER_CONTEXT ) * ARRAY_size( &server->filters ); 00704 layout = (FILTER_CONTEXT *) malloc( server->filter_ctx_layout_size ); 00705 if (! layout ) { 00706 return -1; 00707 } 00708 server->filter_ctx_layout = layout; 00709 00710 for(i = 0, cur = (FILTER_CONTEXT *) layout; i < ARRAY_size( &server->filters ); cur++, i++ ) { 00711 cur->connection_ctx = 0; 00712 tmp = (HTTP_FILTER **) ARRAY_at( &server->filters, i ); 00713 00714 cur->filter = *tmp; 00715 cur->next_request_filter_idx = cur->filter->next_request_filter_idx - i; 00716 cur->next_response_filter_idx = i - cur->filter->next_response_filter_idx; 00717 } 00718 00719 return WEBBY_impl_run( server->impl ); 00720 } 00721 00722 int WEBBY_shutdown( WEBBY *server ) 00723 { 00724 return WEBBY_impl_shutdown( server->impl ); 00725 } 00726 00727 static int http_header_parsed (HTTP_REQUEST *request, void *ctx) 00728 { 00729 MLOG_TRACE( "webby - http header parsed" ); 00730 00731 FILTER_CONTEXT *filter_data = (FILTER_CONTEXT *) ctx; 00732 00733 return filter_data->filter->on_request_header_parsed(request, filter_data ); 00734 } 00735 00736 static int http_on_message_data (HTTP_REQUEST *request, void *data, size_t data_size, void *ctx) 00737 { 00738 MLOG_TRACE( "webby - request body data parsed. size %u", data_size ); 00739 00740 FILTER_CONTEXT *filter_data = (FILTER_CONTEXT *) ctx; 00741 00742 return filter_data->filter->on_request_data( request, data, data_size, filter_data ); 00743 } 00744 00745 static int http_req_finished (HTTP_REQUEST *request, void *ctx) 00746 { 00747 MLOG_TRACE( "webby - request parsing finished" ); 00748 00749 FILTER_CONTEXT *filter_data = (FILTER_CONTEXT *) ctx; 00750 00751 return filter_data->filter->on_request_completed( request, filter_data ); 00752 } 00753 00754 00755 WEBBY_CONNECTION *WEBBY_new_connection( WEBBY *server, void *implconndata ) 00756 { 00757 WEBBY_CONNECTION *ret = 0; 00758 FILTER_CONTEXT *filter_data = 0; 00759 void *buff = 0; 00760 DATA_SINK_FILTER_CONNECTION_CONTEXT *sink_conn_ctx = 0; 00761 00762 ret = (WEBBY_CONNECTION *) malloc( sizeof(WEBBY_CONNECTION) ); 00763 if (!ret) { 00764 goto err; 00765 } 00766 00767 buff = malloc( HTTP_PARSER_BUFFER_SIZE ); 00768 if (!buff) { 00769 goto err; 00770 } 00771 BF_init( &ret->in_buf, buff, HTTP_PARSER_BUFFER_SIZE); 00772 00773 filter_data = (FILTER_CONTEXT *) malloc( server->filter_ctx_layout_size ); 00774 if (!filter_data) { 00775 goto err; 00776 } 00777 memcpy( filter_data, server->filter_ctx_layout, server->filter_ctx_layout_size ); 00778 ret->num_filters = ARRAY_size( &server->filters ); 00779 ret->filter_data = filter_data; 00780 00781 sink_conn_ctx = DATA_SINK_FILTER_CONNECTION_CONTEXT_init( implconndata, &ret->in_buf ); 00782 if (! sink_conn_ctx) { 00783 goto err; 00784 } 00785 filter_data->connection_ctx = sink_conn_ctx; 00786 00787 00788 HTTP_REQUEST_PARSER_init( &ret->request_parser, 00789 http_header_parsed, 00790 http_on_message_data, 00791 http_req_finished, 00792 filter_data); 00793 00794 00795 HTTP_REQUEST_init( &ret->request ); 00796 00797 return ret; 00798 00799 err: 00800 if (filter_data) { 00801 free(filter_data); 00802 } 00803 if (buff) { 00804 free(buff); 00805 } 00806 if (ret) { 00807 free(ret); 00808 } 00809 if (sink_conn_ctx) { 00810 DATA_SINK_FILTER_CONNECTION_CONTEXT_free( implconndata ); 00811 } 00812 return 0; 00813 } 00814 00815 00816 00817 int WEBBY_connection_data_received( WEBBY_CONNECTION * connection ) 00818 { 00819 PARSER_STATUS st; 00820 00821 st = HTTP_REQUEST_PARSER_process( &connection->request_parser, &connection->request, &connection->in_buf ); 00822 switch( st ) { 00823 case PARSER_STATUS_ERROR: 00824 MLOG_INFO( "Error during parsing of HTTP header" ); 00825 return -1; 00826 case PARSER_STATUS_COMPLETED: 00827 HTTP_REQUEST_init( &connection->request ); 00828 BF_put_mode( &connection->in_buf ); 00829 break; 00830 case PARSER_STATUS_NEED_MORE_DATA: 00831 break; 00832 } 00833 return 0; 00834 } 00835 00836 void WEBBY_connection_close( WEBBY_CONNECTION * connection ) 00837 { 00838 FILTER_CONTEXT *ctx; 00839 size_t i; 00840 00841 if (!connection->filter_data) { 00842 return; 00843 } 00844 00845 for( ctx = connection->filter_data, i = 0; i < connection->num_filters ; ++ctx, ++i ) { 00846 ctx->filter->on_connection_close( ctx ); 00847 } 00848 00849 free( connection->filter_data ); 00850 connection->filter_data = 0; 00851 } 00852 00853 // ==================================================================== 00854 00855 int HTTP_response_start( HTTP_servlet_response *resp, int status, const char *mime_type, HTTP_servlet_response_type rtype, size_t length ) 00856 { 00857 if (resp->state !=0) { 00858 return -1; 00859 } 00860 resp->response.status_code = status; 00861 if (mime_type) { 00862 HTTP_MESSAGE_add_header( &resp->response.base, "Content-Type", mime_type ); 00863 } 00864 00865 if ( ! HTTP_REQUEST_is_persistent( resp->request ) ) { 00866 rtype = RESPONSE_CONNECTION_CLOSE; 00867 } 00868 00869 switch(rtype) { 00870 case RESPONSE_CONNECTION_CLOSE: 00871 resp->response.base.flags = HTTP_MESSAGE_FLAG_CONNECTION_CLOSE; 00872 resp->data_sent = (size_t) -1; 00873 break; 00874 case RESPONSE_CONTENT_LENGTH: 00875 HTTP_MESSAGE_set_content_length( &resp->response.base, length ); 00876 resp->data_sent = length; 00877 break; 00878 case RESPONSE_CHUNKED: 00879 resp->response.base.flags = HTTP_MESSAGE_FLAG_TRANSFER_CHUNKED; 00880 #if 0 00881 if (HTTP_MESSAGE_add_header( &resp->response.base, "Transfer-Encoding" , "chunked" )) { 00882 return -1; 00883 } 00884 #endif 00885 break; 00886 } 00887 00888 resp->state = 1; 00889 return 0; 00890 } 00891 00892 int HTTP_response_send( HTTP_servlet_response *resp, void *data, size_t size) 00893 { 00894 RDATA rdata; 00895 00896 if (resp->state < 1 || resp->state > 2) { 00897 return -1; 00898 } 00899 00900 if (resp->state == 1) { 00901 if (call_next_filter_response_header( &resp->response, resp->filter_context )) { 00902 return -1; 00903 } 00904 resp->state = 2; 00905 } 00906 00907 if (resp->response.base.flags & HTTP_MESSAGE_FLAG_TRANSFER_CHUNKED ) { 00908 return -1; 00909 } 00910 00911 // check that not sending more data than allowed by set value of Content-Length header. 00912 if (resp->data_sent != (size_t) -1) { 00913 if (resp->data_sent < size ) { 00914 return -1; 00915 } 00916 resp->data_sent -= size; 00917 } 00918 00919 rdata.no_chunk.data = data; 00920 rdata.no_chunk.data_size = size; 00921 00922 return call_next_filter_response_data ( &resp->response, 0, rdata, resp->filter_context ); 00923 } 00924 00925 00926 00927 00928 BF *HTTP_response_get_chunk_buffer( HTTP_servlet_response *resp, size_t chunk_size ) 00929 { 00930 size_t sz; 00931 void *tmp; 00932 00933 if (resp->chunk_buf != 0) { 00934 if (resp->chunk_buf_size < chunk_size ) { 00935 sz = chunk_size + RESERVED_FOR_CHUNK_HEADER_SIZE; 00936 tmp = realloc( resp->chunk_buf, sz ); 00937 if (!tmp) { 00938 return 0; 00939 } 00940 resp->chunk_buf = tmp; 00941 resp->chunk_buf_size = chunk_size; 00942 } 00943 } else { 00944 sz = chunk_size + RESERVED_FOR_CHUNK_HEADER_SIZE; 00945 resp->chunk_buf = malloc( sz ); 00946 if (!resp->chunk_buf) { 00947 return 0; 00948 } 00949 BF_init( &resp->bf, resp->chunk_buf, sz ); 00950 resp->chunk_buf_size = chunk_size; 00951 } 00952 00953 BF_put_mode( &resp->bf ); 00954 BF_set_start( &resp->bf, RESERVED_FOR_CHUNK_HEADER_SIZE ); 00955 resp->bf.end = resp->bf.put_pos + chunk_size; 00956 00957 return &resp->bf; 00958 } 00959 00960 int HTTP_response_write_chunk( HTTP_servlet_response *resp, BF *bf) 00961 { 00962 RDATA rdata; 00963 00964 if (resp->state < 1 || resp->state > 2) { 00965 return -1; 00966 } 00967 if ( (resp->response.base.flags & (HTTP_MESSAGE_FLAG_TRANSFER_CHUNKED | HTTP_MESSAGE_FLAG_CONNECTION_CLOSE) ) == 0) { 00968 return -1; 00969 } 00970 00971 if (resp->state == 1) { 00972 if (call_next_filter_response_header( &resp->response, resp->filter_context )) { 00973 return -1; 00974 } 00975 resp->state = 2; 00976 } else { 00977 ++ resp->chunk_no; 00978 } 00979 00980 if ( resp->response.base.flags & HTTP_MESSAGE_FLAG_CONNECTION_CLOSE ) { 00981 rdata.no_chunk.data = bf->get_pos; 00982 rdata.no_chunk.data_size = BF_get_size( bf ); 00983 00984 return call_next_filter_response_data ( &resp->response, 0, rdata, resp->filter_context ); 00985 } 00986 00987 #if 0 00988 if (first_chunk) { 00989 len = snprintf( chunk_header, sizeof( chunk_header ), "%x\r\n", BF_get_size(bf) ); 00990 } else { 00991 len = snprintf( chunk_header, sizeof( chunk_header ), "\r\n%x\r\n", BF_get_size(bf) ); 00992 } 00993 00994 #endif 00995 00996 rdata.chunk.bf = bf; 00997 rdata.chunk.chunk_no = resp->chunk_no; 00998 00999 01000 return call_next_filter_response_data ( &resp->response, 1, rdata, resp->filter_context ); 01001 } 01002 01003 int HTTP_response_finish( HTTP_servlet_response *resp ) 01004 { 01005 RDATA rdata; 01006 01007 if (resp->state < 1 || resp->state > 2) { 01008 return -1; 01009 } 01010 01011 if (resp->state == 1) { 01012 if (call_next_filter_response_header( &resp->response, resp->filter_context )) { 01013 return -1; 01014 } 01015 } 01016 01017 01018 if (resp->response.base.flags & HTTP_MESSAGE_FLAG_TRANSFER_CHUNKED) { 01019 01020 rdata.chunk.bf = 0; 01021 rdata.chunk.chunk_no = ++resp->chunk_no; 01022 01023 if ( call_next_filter_response_data ( &resp->response, 1, rdata, resp->filter_context ) ) { 01024 return -1; 01025 } 01026 01027 #if 0 01028 if (resp->state == 1) { 01029 if (call_next_filter_response_data ( &resp->response, LAST_CHUNK, LAST_CHUNK_SIZE, resp->filter_context )) { 01030 return -1; 01031 } 01032 } else { 01033 if (call_next_filter_response_data ( &resp->response, LAST_CHUNK_NOT_FIRST, LAST_CHUNK_NOT_FIRST_SIZE, resp->filter_context )) { 01034 return -1; 01035 } 01036 } 01037 #endif 01038 } 01039 resp->state = 3; 01040 01041 return call_next_filter_response_completed ( &resp->response, resp->filter_context ); 01042 } 01043 01044