📄 httpd.c
字号:
msg->i_name = 0; msg->name = NULL; msg->i_value = 0; msg->value = NULL; msg->i_body_offset = 0; msg->i_body = 0; msg->p_body = NULL;}void httpd_MsgClean( httpd_message_t *msg ){ int i; free( msg->psz_url ); free( msg->psz_args ); for( i = 0; i < msg->i_name; i++ ) { free( msg->name[i] ); free( msg->value[i] ); } free( msg->name ); free( msg->value ); free( msg->p_body ); httpd_MsgInit( msg );}const char *httpd_MsgGet( const httpd_message_t *msg, const char *name ){ int i; for( i = 0; i < msg->i_name; i++ ) { if( !strcasecmp( msg->name[i], name )) { return msg->value[i]; } } return NULL;}void httpd_MsgAdd( httpd_message_t *msg, const char *name, const char *psz_value, ... ){ va_list args; char *value = NULL; va_start( args, psz_value ); if( vasprintf( &value, psz_value, args ) == -1 ) value = NULL; va_end( args ); if( value == NULL ) return; name = strdup( name ); if( name == NULL ) { free( value ); return; } TAB_APPEND( msg->i_name, msg->name, (char*)name ); TAB_APPEND( msg->i_value, msg->value, value );}static void httpd_ClientInit( httpd_client_t *cl, mtime_t now ){ cl->i_state = HTTPD_CLIENT_RECEIVING; cl->i_activity_date = now; cl->i_activity_timeout = INT64_C(10000000); cl->i_buffer_size = HTTPD_CL_BUFSIZE; cl->i_buffer = 0; cl->p_buffer = malloc( cl->i_buffer_size ); cl->i_mode = HTTPD_CLIENT_FILE; cl->b_read_waiting = false; httpd_MsgInit( &cl->query ); httpd_MsgInit( &cl->answer );}void httpd_ClientModeStream( httpd_client_t *cl ){ cl->i_mode = HTTPD_CLIENT_STREAM;}void httpd_ClientModeBidir( httpd_client_t *cl ){ cl->i_mode = HTTPD_CLIENT_BIDIR;}char* httpd_ClientIP( const httpd_client_t *cl, char *psz_ip ){ return net_GetPeerAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;}char* httpd_ServerIP( const httpd_client_t *cl, char *psz_ip ){ return net_GetSockAddress( cl->fd, psz_ip, NULL ) ? NULL : psz_ip;}static void httpd_ClientClean( httpd_client_t *cl ){ if( cl->fd >= 0 ) { if( cl->p_tls != NULL ) tls_ServerSessionClose( cl->p_tls ); net_Close( cl->fd ); cl->fd = -1; } httpd_MsgClean( &cl->answer ); httpd_MsgClean( &cl->query ); free( cl->p_buffer ); cl->p_buffer = NULL;}static httpd_client_t *httpd_ClientNew( int fd, tls_session_t *p_tls, mtime_t now ){ httpd_client_t *cl = malloc( sizeof( httpd_client_t ) ); if( !cl ) return NULL; cl->i_ref = 0; cl->fd = fd; cl->url = NULL; cl->p_tls = p_tls; httpd_ClientInit( cl, now ); return cl;}staticssize_t httpd_NetRecv (httpd_client_t *cl, uint8_t *p, size_t i_len){ tls_session_t *p_tls; ssize_t val; p_tls = cl->p_tls; do val = p_tls ? tls_Recv (p_tls, p, i_len) : recv (cl->fd, p, i_len, 0); while (val == -1 && errno == EINTR); return val;}staticssize_t httpd_NetSend (httpd_client_t *cl, const uint8_t *p, size_t i_len){ tls_session_t *p_tls; ssize_t val; p_tls = cl->p_tls; do val = p_tls ? tls_Send( p_tls, p, i_len ) : send (cl->fd, p, i_len, 0); while (val == -1 && errno == EINTR); return val;}static const struct{ const char name[16]; int i_type; int i_proto;}msg_type[] ={ { "OPTIONS", HTTPD_MSG_OPTIONS, HTTPD_PROTO_RTSP }, { "DESCRIBE", HTTPD_MSG_DESCRIBE, HTTPD_PROTO_RTSP }, { "SETUP", HTTPD_MSG_SETUP, HTTPD_PROTO_RTSP }, { "PLAY", HTTPD_MSG_PLAY, HTTPD_PROTO_RTSP }, { "PAUSE", HTTPD_MSG_PAUSE, HTTPD_PROTO_RTSP }, { "GET_PARAMETER", HTTPD_MSG_GETPARAMETER, HTTPD_PROTO_RTSP }, { "TEARDOWN", HTTPD_MSG_TEARDOWN, HTTPD_PROTO_RTSP }, { "GET", HTTPD_MSG_GET, HTTPD_PROTO_HTTP }, { "HEAD", HTTPD_MSG_HEAD, HTTPD_PROTO_HTTP }, { "POST", HTTPD_MSG_POST, HTTPD_PROTO_HTTP }, { "", HTTPD_MSG_NONE, HTTPD_PROTO_NONE }};static void httpd_ClientRecv( httpd_client_t *cl ){ int i_len; /* ignore leading whites */ if( ( cl->query.i_proto == HTTPD_PROTO_NONE ) && ( cl->i_buffer == 0 ) ) { unsigned char c; i_len = httpd_NetRecv( cl, &c, 1 ); if( ( i_len > 0 ) && ( strchr( "\r\n\t ", c ) == NULL ) ) { cl->p_buffer[0] = c; cl->i_buffer++; } } else if( cl->query.i_proto == HTTPD_PROTO_NONE ) { /* enough to see if it's Interleaved RTP over RTSP or RTSP/HTTP */ i_len = httpd_NetRecv( cl, &cl->p_buffer[cl->i_buffer], 7 - cl->i_buffer ); if( i_len > 0 ) { cl->i_buffer += i_len; } if( ( cl->i_buffer >= 4 ) && ( cl->p_buffer[0] == '$' ) ) { /* Interleaved RTP over RTSP */ cl->query.i_proto = HTTPD_PROTO_RTSP; cl->query.i_type = HTTPD_MSG_CHANNEL; cl->query.i_channel = cl->p_buffer[1]; cl->query.i_body = (cl->p_buffer[2] << 8)|cl->p_buffer[3]; cl->query.p_body = malloc( cl->query.i_body ); cl->i_buffer -= 4; memcpy( cl->query.p_body, cl->p_buffer + 4, cl->i_buffer ); } else /* The smallest legal request is 7 bytes ("GET /\r\n"), * this is the maximum we can ask at this point. */ if( cl->i_buffer >= 7 ) { if( !memcmp( cl->p_buffer, "HTTP/1.", 7 ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; cl->query.i_type = HTTPD_MSG_ANSWER; } else if( !memcmp( cl->p_buffer, "RTSP/1.", 7 ) ) { cl->query.i_proto = HTTPD_PROTO_RTSP; cl->query.i_type = HTTPD_MSG_ANSWER; } else { /* We need the full request line to determine the protocol. */ cl->query.i_proto = HTTPD_PROTO_HTTP0; cl->query.i_type = HTTPD_MSG_NONE; } } } else if( cl->query.i_body > 0 ) { /* we are reading the body of a request or a channel */ i_len = httpd_NetRecv( cl, &cl->query.p_body[cl->i_buffer], cl->query.i_body - cl->i_buffer ); if( i_len > 0 ) { cl->i_buffer += i_len; } if( cl->i_buffer >= cl->query.i_body ) { cl->i_state = HTTPD_CLIENT_RECEIVE_DONE; } } else { /* we are reading a header -> char by char */ for( ;; ) { if( cl->i_buffer == cl->i_buffer_size ) { uint8_t *newbuf = realloc( cl->p_buffer, cl->i_buffer_size + 1024 ); if( newbuf == NULL ) { i_len = 0; break; } cl->p_buffer = newbuf; cl->i_buffer_size += 1024; } i_len = httpd_NetRecv (cl, &cl->p_buffer[cl->i_buffer], 1 ); if( i_len <= 0 ) { break; } cl->i_buffer++; if( ( cl->query.i_proto == HTTPD_PROTO_HTTP0 ) && ( cl->p_buffer[cl->i_buffer - 1] == '\n' ) ) { /* Request line is now complete */ const char *p = memchr( cl->p_buffer, ' ', cl->i_buffer ); size_t len; assert( cl->query.i_type == HTTPD_MSG_NONE ); if( p == NULL ) /* no URI: evil guy */ { i_len = 0; /* drop connection */ break; } do p++; /* skips extra spaces */ while( *p == ' ' ); p = memchr( p, ' ', ((char *)cl->p_buffer) + cl->i_buffer - p ); if( p == NULL ) /* no explicit protocol: HTTP/0.9 */ { i_len = 0; /* not supported currently -> drop */ break; } do p++; /* skips extra spaces ever again */ while( *p == ' ' ); len = ((char *)cl->p_buffer) + cl->i_buffer - p; if( len < 7 ) /* foreign protocol */ i_len = 0; /* I don't understand -> drop */ else if( memcmp( p, "HTTP/1.", 7 ) == 0 ) { cl->query.i_proto = HTTPD_PROTO_HTTP; cl->query.i_version = atoi( p + 7 ); } else if( memcmp( p, "RTSP/1.", 7 ) == 0 ) { cl->query.i_proto = HTTPD_PROTO_RTSP; cl->query.i_version = atoi( p + 7 ); } else if( memcmp( p, "HTTP/", 5 ) == 0 ) { const uint8_t sorry[] = "HTTP/1.1 505 Unknown HTTP version\r\n\r\n"; httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 ); i_len = 0; /* drop */ } else if( memcmp( p, "RTSP/", 5 ) == 0 ) { const uint8_t sorry[] = "RTSP/1.0 505 Unknown RTSP version\r\n\r\n"; httpd_NetSend( cl, sorry, sizeof( sorry ) - 1 ); i_len = 0; /* drop */ } else /* yet another foreign protocol */ i_len = 0; if( i_len == 0 ) break; } if( ( cl->i_buffer >= 2 && !memcmp( &cl->p_buffer[cl->i_buffer-2], "\n\n", 2 ) )|| ( cl->i_buffer >= 4 && !memcmp( &cl->p_buffer[cl->i_buffer-4], "\r\n\r\n", 4 ) ) ) { char *p; /* we have finished the header so parse it and set i_body */ cl->p_buffer[cl->i_buffer] = '\0'; if( cl->query.i_type == HTTPD_MSG_ANSWER ) { /* FIXME: * assume strlen( "HTTP/1.x" ) = 8 */ cl->query.i_status = strtol( (char *)&cl->p_buffer[8], &p, 0 ); while( *p == ' ' ) p++; } else { unsigned i; p = NULL; cl->query.i_type = HTTPD_MSG_NONE; /*fprintf( stderr, "received new request=%s\n", cl->p_buffer);*/ for( i = 0; msg_type[i].name[0]; i++ ) { if( !strncmp( (char *)cl->p_buffer, msg_type[i].name, strlen( msg_type[i].name ) ) ) { p = (char *)&cl->p_buffer[strlen(msg_type[i].name) + 1 ]; cl->query.i_type = msg_type[i].i_type; if( cl->query.i_proto != msg_type[i].i_proto ) { p = NULL; cl->query.i_proto = HTTPD_PROTO_NONE; cl->query.i_type = HTTPD_MSG_NONE; } break; } } if( p == NULL ) { if( strstr( (char *)cl->p_buffer, "HTTP/1." ) ) { cl->query.i_proto = HTTPD_PROTO_HTTP; } else if( strstr( (char *)cl->p_buffer, "RTSP/1." ) ) { cl->query.i_proto = HTTPD_PROTO_RTSP; } } else { char *p2; char *p3; while( *p == ' ' ) { p++; } p2 = strchr( p, ' ' ); if( p2 ) { *p2++ = '\0'; } if( !strncasecmp( p, "rtsp:", 5 ) ) { /* for rtsp url, you have rtsp://localhost:port/path */ p += 5; while( *p == '/' ) p++; while( *p && *p != '/' ) p++; } cl->query.psz_url = strdup( p ); if( ( p3 = strchr( cl->query.psz_url, '?' ) ) ) { *p3++ = '\0'; cl->query.psz_args = (uint8_t *)strdup( p3 ); } p = p2; } } if( p ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -