📄 httpd.c
字号:
p = strchr( p, '\n' ); } if( p ) { while( *p == '\n' || *p == '\r' ) { p++; } while( p && *p != '\0' ) { char *line = p; char *eol = p = strchr( p, '\n' ); char *colon; while( eol && eol >= line && ( *eol == '\n' || *eol == '\r' ) ) { *eol-- = '\0'; } if( ( colon = strchr( line, ':' ) ) ) { char *name; char *value; *colon++ = '\0'; while( *colon == ' ' ) { colon++; } name = strdup( line ); value = strdup( colon ); TAB_APPEND( cl->query.i_name, cl->query.name, name ); TAB_APPEND( cl->query.i_value,cl->query.value,value); if( !strcasecmp( name, "Content-Length" ) ) { cl->query.i_body = atol( value ); } } if( p ) { p++; while( *p == '\n' || *p == '\r' ) { p++; } } } } if( cl->query.i_body > 0 ) { /* TODO Mhh, handle the case client will only send a * request and close the connection * to mark and of body (probably only RTSP) */ cl->query.p_body = malloc( cl->query.i_body ); cl->i_buffer = 0; } else { cl->i_state = HTTPD_CLIENT_RECEIVE_DONE; } } } } /* check if the client is to be set to dead */#if defined( WIN32 ) || defined( UNDER_CE ) if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )#else if( ( i_len < 0 && errno != EAGAIN ) || ( i_len == 0 ) )#endif { if( cl->query.i_proto != HTTPD_PROTO_NONE && cl->query.i_type != HTTPD_MSG_NONE ) { /* connection closed -> end of data */ if( cl->query.i_body > 0 ) { cl->query.i_body = cl->i_buffer; } cl->i_state = HTTPD_CLIENT_RECEIVE_DONE; } else { cl->i_state = HTTPD_CLIENT_DEAD; } } /* XXX: for QT I have to disable timeout. Try to find why */ if( cl->query.i_proto == HTTPD_PROTO_RTSP ) cl->i_activity_timeout = 0;#if 0 /* Debugging only */ if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) { int i; fprintf( stderr, "received new request\n" ); fprintf( stderr, " - proto=%s\n", cl->query.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP" ); fprintf( stderr, " - version=%d\n", cl->query.i_version ); fprintf( stderr, " - msg=%d\n", cl->query.i_type ); if( cl->query.i_type == HTTPD_MSG_ANSWER ) { fprintf( stderr, " - answer=%d '%s'\n", cl->query.i_status, cl->query.psz_status ); } else if( cl->query.i_type != HTTPD_MSG_NONE ) { fprintf( stderr, " - url=%s\n", cl->query.psz_url ); } for( i = 0; i < cl->query.i_name; i++ ) { fprintf( stderr, " - option name='%s' value='%s'\n", cl->query.name[i], cl->query.value[i] ); } }#endif}static void httpd_ClientSend( httpd_client_t *cl ){ int i; int i_len; if( cl->i_buffer < 0 ) { /* We need to create the header */ int i_size = 0; char *p; const char *psz_status = httpd_ReasonFromCode( cl->answer.i_status ); i_size = strlen( "HTTP/1.") + 10 + 10 + strlen( psz_status ) + 5; for( i = 0; i < cl->answer.i_name; i++ ) { i_size += strlen( cl->answer.name[i] ) + 2 + strlen( cl->answer.value[i] ) + 2; } if( cl->i_buffer_size < i_size ) { cl->i_buffer_size = i_size; free( cl->p_buffer ); cl->p_buffer = malloc( i_size ); } p = (char *)cl->p_buffer; p += sprintf( p, "%s.%u %d %s\r\n", cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP/1" : "RTSP/1", cl->answer.i_version, cl->answer.i_status, psz_status ); for( i = 0; i < cl->answer.i_name; i++ ) { p += sprintf( p, "%s: %s\r\n", cl->answer.name[i], cl->answer.value[i] ); } p += sprintf( p, "\r\n" ); cl->i_buffer = 0; cl->i_buffer_size = (uint8_t*)p - cl->p_buffer; /*fprintf( stderr, "sending answer\n" ); fprintf( stderr, "%s", cl->p_buffer );*/ } i_len = httpd_NetSend( cl, &cl->p_buffer[cl->i_buffer], cl->i_buffer_size - cl->i_buffer ); if( i_len >= 0 ) { cl->i_buffer += i_len; if( cl->i_buffer >= cl->i_buffer_size ) { if( cl->answer.i_body == 0 && cl->answer.i_body_offset > 0 && !cl->b_read_waiting ) { /* catch more body data */ int i_msg = cl->query.i_type; int64_t i_offset = cl->answer.i_body_offset; httpd_MsgClean( &cl->answer ); cl->answer.i_body_offset = i_offset; cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl, &cl->answer, &cl->query ); } if( cl->answer.i_body > 0 ) { /* send the body data */ free( cl->p_buffer ); cl->p_buffer = cl->answer.p_body; cl->i_buffer_size = cl->answer.i_body; cl->i_buffer = 0; cl->answer.i_body = 0; cl->answer.p_body = NULL; } else { /* send finished */ cl->i_state = HTTPD_CLIENT_SEND_DONE; } } } else {#if defined( WIN32 ) || defined( UNDER_CE ) if( ( i_len < 0 && WSAGetLastError() != WSAEWOULDBLOCK ) || ( i_len == 0 ) )#else if( ( i_len < 0 && errno != EAGAIN ) || ( i_len == 0 ) )#endif { /* error */ cl->i_state = HTTPD_CLIENT_DEAD; } }}static void httpd_ClientTlsHsIn( httpd_client_t *cl ){ switch( tls_SessionContinueHandshake( cl->p_tls ) ) { case 0: cl->i_state = HTTPD_CLIENT_RECEIVING; break; case -1: cl->i_state = HTTPD_CLIENT_DEAD; cl->p_tls = NULL; break; case 2: cl->i_state = HTTPD_CLIENT_TLS_HS_OUT; }}static void httpd_ClientTlsHsOut( httpd_client_t *cl ){ switch( tls_SessionContinueHandshake( cl->p_tls ) ) { case 0: cl->i_state = HTTPD_CLIENT_RECEIVING; break; case -1: cl->i_state = HTTPD_CLIENT_DEAD; cl->p_tls = NULL; break; case 1: cl->i_state = HTTPD_CLIENT_TLS_HS_IN; break; }}static void* httpd_HostThread( vlc_object_t *p_this ){ httpd_host_t *host = (httpd_host_t *)p_this; tls_session_t *p_tls = NULL; counter_t *p_total_counter = stats_CounterCreate( host, VLC_VAR_INTEGER, STATS_COUNTER ); counter_t *p_active_counter = stats_CounterCreate( host, VLC_VAR_INTEGER, STATS_COUNTER ); int evfd; bool b_die;retry: vlc_object_lock( host ); evfd = vlc_object_waitpipe( VLC_OBJECT( host ) ); b_die = !vlc_object_alive( host ); vlc_object_unlock( host ); while( !b_die ) { if( host->i_url <= 0 ) { /* 0.2s (FIXME: use a condition variable) */ msleep( 200000 ); goto retry; } /* prepare a new TLS session */ if( ( p_tls == NULL ) && ( host->p_tls != NULL ) ) p_tls = tls_ServerSessionPrepare( host->p_tls ); struct pollfd ufd[host->nfd + host->i_client + 1]; unsigned nfd; for( nfd = 0; nfd < host->nfd; nfd++ ) { ufd[nfd].fd = host->fds[nfd]; ufd[nfd].events = POLLIN; ufd[nfd].revents = 0; } /* add all socket that should be read/write and close dead connection */ vlc_mutex_lock( &host->lock ); mtime_t now = mdate(); bool b_low_delay = false; for(int i_client = 0; i_client < host->i_client; i_client++ ) { httpd_client_t *cl = host->client[i_client]; if( cl->i_ref < 0 || ( cl->i_ref == 0 && ( cl->i_state == HTTPD_CLIENT_DEAD || ( cl->i_activity_timeout > 0 && cl->i_activity_date+cl->i_activity_timeout < now) ) ) ) { httpd_ClientClean( cl ); stats_UpdateInteger( host, p_active_counter, -1, NULL ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); i_client--; continue; } struct pollfd *pufd = ufd + nfd; assert (pufd < ufd + (sizeof (ufd) / sizeof (ufd[0]))); pufd->fd = cl->fd; pufd->events = pufd->revents = 0; if( ( cl->i_state == HTTPD_CLIENT_RECEIVING ) || ( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) ) { pufd->events = POLLIN; } else if( ( cl->i_state == HTTPD_CLIENT_SENDING ) || ( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) ) { pufd->events = POLLOUT; } else if( cl->i_state == HTTPD_CLIENT_RECEIVE_DONE ) { httpd_message_t *answer = &cl->answer; httpd_message_t *query = &cl->query; int i_msg = query->i_type; httpd_MsgInit( answer ); /* Handle what we received */ if( (cl->i_mode != HTTPD_CLIENT_BIDIR) && (i_msg == HTTPD_MSG_ANSWER || i_msg == HTTPD_MSG_CHANNEL) ) { /* we can only receive request from client when not * in BIDIR mode */ cl->url = NULL; cl->i_state = HTTPD_CLIENT_DEAD; } else if( i_msg == HTTPD_MSG_ANSWER ) { /* We are in BIDIR mode, trigger the callback and then * check for new data */ if( cl->url && cl->url->catch[i_msg].cb ) { cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl, NULL, query ); } cl->i_state = HTTPD_CLIENT_WAITING; } else if( i_msg == HTTPD_MSG_CHANNEL ) { /* We are in BIDIR mode, trigger the callback and then * check for new data */ if( cl->url && cl->url->catch[i_msg].cb ) { cl->url->catch[i_msg].cb( cl->url->catch[i_msg].p_sys, cl, NULL, query ); } cl->i_state = HTTPD_CLIENT_WAITING; } else if( i_msg == HTTPD_MSG_OPTIONS ) { answer->i_type = HTTPD_MSG_ANSWER; answer->i_proto = query->i_proto; answer->i_status = 200; answer->i_body = 0; answer->p_body = NULL; httpd_MsgAdd( answer, "Server", "%s", PACKAGE_STRING ); httpd_MsgAdd( answer, "Content-Length", "0" ); switch( query->i_proto ) { case HTTPD_PROTO_HTTP: answer->i_version = 1; httpd_MsgAdd( answer, "Allow", "GET,HEAD,POST,OPTIONS" ); break; case HTTPD_PROTO_RTSP: { const char *p; answer->i_version = 0; p = httpd_MsgGet( query, "Cseq" ); if( p != NULL ) httpd_MsgAdd( answer, "Cseq", "%s", p ); p = httpd_MsgGet( query, "Timestamp" ); if( p != NULL ) httpd_MsgAdd( answer, "Timestamp", "%s", p ); p = httpd_MsgGet( query, "Require" ); if( p != NULL ) { answer->i_status = 551; httpd_MsgAdd( query, "Unsupported", "%s", p ); } httpd_MsgAdd( answer, "Public", "DESCRIBE,SETUP," "TEARDOWN,PLAY,PAUSE,GET_PARAMETER" ); break; } } cl->i_buffer = -1; /* Force the creation of the answer in * httpd_ClientSend */ cl->i_state = HTTPD_CLIENT_SENDING; } else if( i_msg == HTTPD_MSG_NONE ) { if( query->i_proto == HTTPD_PROTO_NONE ) { cl->url = NULL; cl->i_state = HTTPD_CLIENT_DEAD; } else { char *p; /* unimplemented */ answer->i_proto = query->i_proto ; answer->i_type = HTTPD_MSG_ANSWER; answer->i_version= 0; answer->i_status = 501; answer->i_body = httpd_HtmlError (&p, 501, NULL); answer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -