WEBBY - the embedded web server with many faces / objects in plain C Snapshot
webby.c
Go to the documentation of this file.
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