/share/dexatek/Service/HTTPd.c
C | 772 lines | 616 code | 131 blank | 25 comment | 181 complexity | c0da8c5175eb4113a0abf0affe954e6f MD5 | raw file
Possible License(s): 0BSD
- /*!
- * @file HTTPd.c
- * @version 0.01
- * @author Sam Tsai
- */
- //==========================================================================
- // Include Files
- //==========================================================================
- #include "HTTPd.h"
- #include "Socket.h"
- #include "HTTP.h"
- //==========================================================================
- // Type Definition
- //==========================================================================
- typedef struct {
- Httpd_CGIContext context;
- void *next;
- } httpd_cgi_t;
- typedef struct {
- u32 status;
- int http_fd;
- int https_fd;
- int p_id;
- struct sockaddr_in client_addr;
- http_info_t http;
- char username[ 64 ];
- u32 last_keep_alive;
- struct timeval start_time;
- httpd_cgi_t *cgi_handle;
- void *next;
- } httpd_service_t;
- typedef struct httpd_location httpd_location;
- struct httpd_location{
- char *location;
- int len;
- httpd_location *next;
- };
- //==========================================================================
- // Public Param
- //==========================================================================
- //==========================================================================
- // Static Param
- //==========================================================================
- static struct {
- int ready;
- int p_id;
- int http_fd;
- int https_fd;
- int stream_num;
- char root[ 128 ];
- char homepage[ 128 ];
- char server_name[ 128 ];
- u32 auth_type;
- u16 http_port;
- u16 https_port;
- } httpd_server = { 0, };
- static httpd_service_t *httpd_services = NULL;
- static pthread_mutex_t httpd_server_mutex = PTHREAD_MUTEX_INITIALIZER;
- static httpd_cgi_t *httpd_cgis = NULL;
- static pthread_mutex_t httpd_cgi_mutex = PTHREAD_MUTEX_INITIALIZER;
- static httpd_location *httpd_locations = NULL;
- static pthread_mutex_t httpd_location_mutex = PTHREAD_MUTEX_INITIALIZER;
- //==========================================================================
- // Static Functions
- //==========================================================================
- static int
- montoi( const char *s )
- {
- static const char *ar[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
- size_t i;
- for ( i = 0; i < 12; i ++ ) {
- if ( strcmp( s, ar[ i ] ) == 0 ) {
- return i;
- }
- }
- return -1;
- }
- static time_t
- datetosec( const char *s )
- {
- struct tm stm;
- char mon[ 32 ];
- int sec, min, hour, mday, month, year;
- memset( &stm, 0, sizeof( stm ) );
- sec = min = hour = mday = month = year = 0;
- if ( ( ( sscanf( s, "%d/%3s/%d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) &&
- ( sscanf( s, "%d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) &&
- ( sscanf( s, "%*3s, %d %3s %d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) &&
- ( sscanf( s, "%d-%3s-%d %d:%d:%d", &mday, mon, &year, &hour, &min, &sec ) == 6 ) ) &&
- ( month = montoi( mon ) ) != -1 ) {
- stm.tm_mday = mday;
- stm.tm_mon = month;
- stm.tm_year = year;
- stm.tm_hour = hour;
- stm.tm_min = min;
- stm.tm_sec = sec;
- }
- if ( stm.tm_year > 1900 ) {
- stm.tm_year -= 1900;
- } else if ( stm.tm_year < 70 ) {
- stm.tm_year += 100;
- }
- return ( mktime( &stm ) );
- }
- static int
- httpd_service_remove( httpd_service_t *service )
- {
- int res = FAILURE;
- pthread_mutex_lock( &httpd_server_mutex );
- if ( httpd_services == service ) {
- httpd_services = service->next;
- res = SUCCESS;
- } else if ( httpd_services ) {
- httpd_service_t *s = httpd_services;
- while ( s->next ) {
- if ( s->next == service ) {
- s->next = service->next;
- res = SUCCESS;
- break;
- }
- s = s->next;
- }
- }
- pthread_mutex_unlock( &httpd_server_mutex );
- return res;
- }
- static int
- httpd_service_insert( httpd_service_t *service )
- {
- int res = FAILURE;
- pthread_mutex_lock( &httpd_server_mutex );
- if ( httpd_services == NULL ) {
- httpd_services = service;
- res = SUCCESS;
- } else {
- httpd_service_t *s = httpd_services;
- while ( s->next ) {
- s = s->next;
- }
- s->next = service;
- service->next = NULL;
- res = SUCCESS;
- }
- pthread_mutex_unlock( &httpd_server_mutex );
- return res;
- }
- static BOOL
- httpd_service_exist( httpd_service_t *service )
- {
- BOOL res = FALSE;
- pthread_mutex_lock( &httpd_server_mutex );
- httpd_service_t *s = httpd_services;
- while ( s ) {
- if ( s == service ) {
- res = TRUE;
- break;
- }
- s = s->next;
- }
- pthread_mutex_unlock( &httpd_server_mutex );
- return res;
- }
- static httpd_cgi_t *
- httpd_cgi_find_handle( char *url )
- {
- httpd_cgi_t *u;
- char *pos;
- pthread_mutex_lock( &httpd_cgi_mutex );
- u = httpd_cgis;
- while ( u ) {
- pos = strstr( url, u->context.url );
- if ( pos && ( pos[ strlen( u->context.url ) ] == 0 ) ) {
- pthread_mutex_unlock( &httpd_cgi_mutex );
- return u;
- }
- u = u->next;
- }
- pthread_mutex_unlock( &httpd_cgi_mutex );
- return NULL;
- }
- static int
- httpd_cgi_insert( httpd_cgi_t *cgi )
- {
- int res = FAILURE;
- pthread_mutex_lock( &httpd_cgi_mutex );
- if ( httpd_cgis == NULL ) {
- httpd_cgis = cgi;
- res = SUCCESS;
- } else {
- httpd_cgi_t *u = httpd_cgis;
- while ( u->next ) {
- u = u->next;
- }
- u->next = cgi;
- cgi->next = NULL;
- res = SUCCESS;
- }
- pthread_mutex_unlock( &httpd_cgi_mutex );
- return res;
- }
- static void
- httpd_send_system_error( int client_fd, int code, char *reason )
- {
- char dst[ 256 ], size = 0;
- size = sprintf( dst, "HTTP/1.0 %d %s\r\n\r\n", code, reason );
- Socket_Send( client_fd, dst, size );
- }
- static int
- web_send_result( httpd_service_t *httpd, int code )
- {
- httpd->http.status = code;
- if ( http_build_reply_header( httpd_server.server_name, httpd->http.uri, &httpd->http ) > 0 ) {
- int res = Socket_Send( httpd->http_fd, httpd->http.rw.buf, httpd->http.rw.size );
- httpd->http.rw.size = 0;
- if ( res <= 0 ) {
- return FAILURE;
- } else {
- return SUCCESS;
- }
- } else {
- return FAILURE;
- }
- }
- static int
- httpd_do_get( httpd_service_t *httpd )
- {
- int send_len;
- web_send_result( httpd, 200 );
- while ( httpd->http.fd > 0 ) {
- httpd->http.rw.size = read( httpd->http.fd, httpd->http.rw.buf, IO_MAX );
- if ( httpd->http.rw.size <= 0 ) {
- return FAILURE;
- }
- send_len = Socket_Send( httpd->http_fd, httpd->http.rw.buf, httpd->http.rw.size );
- if ( send_len < 0 ) {
- return FAILURE;
- }
- }
- return FAILURE;
- }
- static int
- httpd_do_post( httpd_service_t *httpd )
- {
- // Not Support
- return FAILURE;
- }
- static int
- httpd_do_request( httpd_service_t *httpd )
- {
- if ( httpd->cgi_handle ) {
- if ( httpd->http.http_method == METHOD_GET ) {
- if ( httpd->cgi_handle->context.cgi_get ) {
- return httpd->cgi_handle->context.cgi_get( httpd, httpd->http_fd );
- }
- } else if ( httpd->http.http_method == METHOD_POST ) {
- if ( httpd->cgi_handle->context.cgi_post ) {
- return httpd->cgi_handle->context.cgi_post( httpd, httpd->http_fd );
- }
- }
- } else {
- if ( httpd->http.http_method == METHOD_GET ) {
- return httpd_do_get( httpd );
- } else if ( httpd->http.http_method == METHOD_POST ) {
- return httpd_do_post( httpd );
- }
- }
- return FAILURE;
- }
- static int
- httpd_parse_request( httpd_service_t *httpd )
- {
- char *temp;
- int res = SUCCESS;
- if ( httpd->http.uri[ 1 ] == 0 ) {
- sprintf( httpd->http.uri, "%s", httpd_server.homepage );
- } else {
- char *uri = strdup( httpd->http.uri );
- if ( httpd->http.uri[ 1 ] == '?' ) {
- sprintf( httpd->http.uri, "%s%s", httpd_server.homepage, uri + 1 );
- } else {
- char *path = httpd_server.root;
- httpd_location *loc = httpd_locations;
- while ( loc ) {
- if ( strncmp( loc->location, uri, loc->len ) == 0 ) {
- path = NULL;
- break;
- }
- loc = loc->next;
- }
- if ( path ) {
- sprintf( httpd->http.uri, "%s%s", path, uri );
- }
- }
- if ( ( temp = strchr( httpd->http.uri, '?' ) ) ) {
- http_parser_cgi( temp, httpd->http.env, MAX_HTTP_PARAM );
- temp[ 0 ] = 0;
- }
- free( uri );
- }
- if ( ( temp = http_get_field( httpd->http.http_env, "If-Modified-Since", MAX_HTTP_TAG ) ) ) {
- httpd->http.ims = datetosec( temp );
- }
- httpd->http.keep_alive = 0;
- if ( ( temp = http_get_field( httpd->http.http_env, "Connection", MAX_HTTP_TAG ) ) ) {
- if ( strstr( temp, "keep-alive" ) ) {
- httpd->http.keep_alive = 1;
- }
- }
- if ( ( temp = http_get_field( httpd->http.http_env, "Content-Length", MAX_HTTP_TAG ) ) ) {
- httpd->http.cclength = atoi( temp );
- } else {
- httpd->http.cclength = 0;
- }
- if ( ( httpd_server.auth_type != WEB_AUTH_TYPE_NONE ) &&
- ( http_check_auth( &httpd->http, httpd->http.method, httpd->username ) < 0 ) ) {
- web_send_result( httpd, 401 );
- return SUCCESS;
- } else if ( !strcasecmp( httpd->http.method, "GET" ) ) {
- httpd->http.http_method = METHOD_GET;
- } else if ( !strcasecmp( httpd->http.method, "POST" ) ) {
- httpd->http.http_method = METHOD_POST;
- } else if ( !strcasecmp( httpd->http.method, "HEAD" ) ) {
- httpd->http.http_method = METHOD_GET;
- } else {
- dbg_line( "UN-Know Method %s\n", httpd->http.method );
- web_send_result( httpd, 501 );
- return FAILURE;
- }
- if ( stat( httpd->http.uri, &httpd->http.st ) == 0 ) {
- if ( S_ISREG( httpd->http.st.st_mode ) ) {
- httpd->http.cclength = httpd->http.st.st_size;
- if ( ( httpd->http.fd = open( httpd->http.uri, O_RDONLY, 0644 ) ) < 0 ) {
- web_send_result( httpd, 500 );
- return FAILURE;
- }
- } else {
- web_send_result( httpd, 403 );
- return FAILURE;
- }
- } else {
- httpd->cgi_handle = httpd_cgi_find_handle( httpd->http.uri );
- if ( httpd->cgi_handle == NULL ) {
- web_send_result( httpd, 404 );
- return FAILURE;
- }
- }
- return res;
- }
- static int
- httpd_read_header( httpd_service_t *httpd )
- {
- int res;
- u32 start_clock = seconds();
- u32 curr_clock;
- Socket_SetBlockMode( httpd->http_fd, 0 );
- while ( TRUE ) {
- if ( Socket_isReadable( httpd->http_fd ) ) {
- int recv_size = IO_MAX - httpd->http.header.size;
- if ( httpd->http.header.size < 32 ) {
- if ( recv_size > 64 ) {
- recv_size = 64;
- }
- } else {
- if ( recv_size > 12 ) {
- recv_size = 12;
- }
- }
- if ( ( res = Socket_Recv( httpd->http_fd, &httpd->http.header.buf[ httpd->http.header.size ], recv_size ) ) < 0 ) {
- return NET_ERR_CONNECT_FAIL;
- } else if ( res == 0 ) {
- return NET_ERR_DISCONNECT;
- }
- httpd->http.header.size += res;
- httpd->http.header.buf[ httpd->http.header.size ] = 0;
- res = http_parser_request( &httpd->http );
- if ( res < 0 ) {
- dbg_line();
- return res;
- } else if ( res > 0 ) {
- break;
- }
- }
- curr_clock = seconds();
- if ( ( start_clock + 10 ) < curr_clock ) {
- return NET_ERR_RECV_TIMEOUT;
- }
- }
- Socket_SetBlockMode( httpd->http_fd, 1 );
- return SUCCESS;
- }
- static void
- httpd_free( httpd_service_t *httpd )
- {
- httpd_service_remove( httpd );
- if ( httpd->http_fd > 0 ) {
- Socket_Disconnect( httpd->http_fd );
- }
- if ( httpd->https_fd > 0 ) {
- Socket_Disconnect( httpd->https_fd );
- }
- if ( httpd->http.fd > 0 ) {
- close( httpd->http.fd );
- }
- http_release( &httpd->http );
- my_free( httpd );
- }
- static void *
- httpd_service_proccess( void *arg )
- {
- httpd_service_t *httpd = ( httpd_service_t * )arg;
- while ( httpd->http.http_method == METHOD_NONE ) {
- if ( httpd_read_header( httpd ) != SUCCESS ) {
- break;
- } else if ( httpd_parse_request( httpd ) != SUCCESS ) {
- break;
- } else if ( httpd->http.http_method ) {
- if ( httpd_do_request( httpd ) != SUCCESS ) {
- break;
- }
- }
- }
- MSleep( 50 );
- httpd_free( httpd );
- return NULL;
- }
- static void *
- httpd_accept( void *arg )
- {
- int client_fd;
- struct sockaddr_in client_addr;
- // Receiving Streaming
- while ( 1 ) {
- if ( Socket_isReadable( httpd_server.http_fd ) > 0 ) {
- client_fd = Socket_Accept( httpd_server.http_fd, &client_addr, 1 );
- if ( client_fd > 0 ) {
- httpd_service_t *httpd = ( httpd_service_t * )my_malloc( sizeof( httpd_service_t ) );
- if ( httpd ) {
- httpd->http_fd = client_fd;
- httpd->client_addr = client_addr;
- httpd_service_insert( httpd );
- httpd->p_id = create_norm_thread( httpd_service_proccess, httpd, 0 );
- } else {
- dbg_line( "Do my_malloc Failed!!!" );
- httpd_send_system_error( client_fd, 503, "Service Unavailable" );
- }
- }
- }
- }
- return NULL;
- }
- //==========================================================================
- // APIs
- //==========================================================================
- const char *
- Httpd_GetHeaderField( HttpdHandle handle, char *field )
- {
- if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
- httpd_service_t *httpd = ( httpd_service_t * )handle;
- return http_get_field( httpd->http.http_env, field, MAX_HTTP_TAG );
- } else {
- return NULL;
- }
- }
- const char *
- Httpd_GetCGIField( HttpdHandle handle, char *field )
- {
- if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
- httpd_service_t *httpd = ( httpd_service_t * )handle;
- return http_get_field( httpd->http.env, field, MAX_HTTP_TAG );
- } else {
- return NULL;
- }
- }
- int
- Httpd_SendHttpHeader( HttpdHandle handle, char *url, int code )
- {
- if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
- httpd_service_t *httpd = ( httpd_service_t * )handle;
- if ( url ) {
- sprintf( httpd->http.uri, "%s", url );
- }
- return web_send_result( httpd, code );
- } else {
- return FAILURE;
- }
- }
- int
- Httpd_SendResponse( HttpdHandle handle, char *url, char *data, int size )
- {
- if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
- httpd_service_t *httpd = ( httpd_service_t * )handle;
- if ( url ) {
- sprintf( httpd->http.uri, "%s", url );
- }
- httpd->http.st.st_size = size;
- if ( web_send_result( httpd, 200 ) == SUCCESS ) {
- return Socket_Send( httpd->http_fd, data, size );
- } else {
- return FAILURE;
- }
- } else {
- return FAILURE;
- }
- }
- int
- Httpd_RecvHttpHeader( HttpdHandle handle )
- {
- if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
- httpd_service_t *httpd = ( httpd_service_t * )handle;
- httpd->http.header.size = 0;
- if ( httpd_read_header( httpd ) != SUCCESS ) {
- return FAILURE;
- } else if ( httpd_parse_request( httpd ) != SUCCESS ) {
- return FAILURE;
- } else {
- return SUCCESS;
- }
- } else {
- return FAILURE;
- }
- }
- int
- Httpd_RecvData( HttpdHandle handle, u8 **data )
- {
- if ( handle && ( httpd_service_exist( ( httpd_service_t * )handle ) == TRUE ) ) {
- httpd_service_t *httpd = ( httpd_service_t * )handle;
- if ( httpd->http.cclength ) {
- *data = ( u8 * )my_malloc( ( httpd->http.cclength + 4 ) );
- if ( *data ) {
- int size = 0, res;
- char *dst = ( char * )*data;
- if ( httpd->http.rw.size ) {
- if ( httpd->http.rw.size > httpd->http.cclength ) {
- memcpy( *data, httpd->http.rw.buf, httpd->http.cclength );
- httpd->http.rw.size -= httpd->http.cclength;
- memcpy( httpd->http.rw.buf, &httpd->http.rw.buf[ httpd->http.cclength ], httpd->http.rw.size );
- return httpd->http.cclength;
- } else {
- memcpy( *data, httpd->http.rw.buf, httpd->http.rw.size );
- size = httpd->http.rw.size;
- dst += size;
- }
- }
- while ( size < httpd->http.cclength ) {
- if ( Socket_isWritable( httpd->http_fd ) ) {
- res = Socket_Recv( httpd->http_fd, dst, ( httpd->http.cclength - size ) );
- if ( res <= 0 ) {
- my_free( *data );
- return FAILURE;
- }
- size += res;
- } else {
- MSleep( 50 );
- }
- }
- return httpd->http.cclength;
- } else {
- return 0;
- }
- } else {
- return 0;
- }
- } else {
- return FAILURE;
- }
- }
- int
- Httpd_RegCGIService( Httpd_CGIContext *context )
- {
- if ( context ) {
- httpd_cgi_t *cgi = ( httpd_cgi_t * )my_malloc( sizeof( httpd_cgi_t ) );
- if ( cgi ) {
- memcpy( &cgi->context, context, sizeof( Httpd_CGIContext ) );
- httpd_cgi_insert( cgi );
- return SUCCESS;
- }
- }
- return FAILURE;
- }
- int
- Httpd_SetContext( Httpd_ServerContext *context )
- {
- return SUCCESS;
- }
- int
- Httpd_AddLocation( char *location )
- {
- int res = FAILURE;
- if ( location ) {
- httpd_location *loc = ( httpd_location * )my_malloc( sizeof( httpd_location ) );
- if ( loc ) {
- loc->location = my_strdup( location );
- loc->len = strlen( location );
- pthread_mutex_lock( &httpd_location_mutex );
- if ( httpd_locations == NULL ) {
- httpd_locations = loc;
- res = SUCCESS;
- } else {
- httpd_location *l = httpd_locations;
- while ( l->next ) {
- l = l->next;
- }
- loc->next = NULL;
- l->next = loc;
- res = SUCCESS;
- }
- pthread_mutex_unlock( &httpd_location_mutex );
- }
- }
- return res;
- }
- int
- Httpd_ServerStart( Httpd_ServerContext *context )
- {
- if ( context ) {
- sprintf( httpd_server.server_name, ( context->server_name[ 0 ] )? context->server_name: "SigmaCam Web Server" );
- sprintf( httpd_server.root, ( context->root[ 0 ] )? context->root: "/var/www/" );
- sprintf( httpd_server.homepage, ( context->homepage[ 0 ] )? context->homepage: "/var/www/index.html" );
- if ( httpd_server.root[ strlen( httpd_server.root ) - 1 ] == '/' ) {
- httpd_server.root[ strlen( httpd_server.root ) - 1 ] = 0;
- }
- httpd_server.http_port = ( context->http_port )? context->http_port: 80;
- httpd_server.https_port = ( context->https_port )? context->https_port: 443;
- httpd_server.http_fd = Socket_CreateServer( httpd_server.http_port );
- if ( httpd_server.http_fd < 0 ) {
- dbg_line( "Do Socket_CreateServer Failed!!!" );
- return FAILURE;
- }
- httpd_server.p_id = create_norm_thread( httpd_accept, NULL, 0 );
- if ( httpd_server.p_id < 0 ) {
- dbg_line( "Do create_norm_thread Failed!!!" );
- Socket_Disconnect( httpd_server.http_fd );
- return FAILURE;
- }
- httpd_server.ready = TRUE;
- dbg_warm( "Httpd Start" );
- return SUCCESS;
- } else {
- return FAILURE;
- }
- }