📄 httpd.c
字号:
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 && errno != EINTR ) || ( 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; } } cl->i_activity_date = mdate(); /* 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; i_size = strlen( "HTTP/1.") + 10 + 10 + strlen( cl->answer.psz_status ? cl->answer.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/1.%d %d %s\r\n", cl->answer.i_proto == HTTPD_PROTO_HTTP ? "HTTP" : "RTSP", cl->answer.i_version, cl->answer.i_status, cl->answer.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_activity_date = mdate(); 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 && errno != EINTR ) || ( 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( httpd_host_t *host ){ tls_session_t *p_tls = NULL; stats_Create( host, "client_connections", STATS_CLIENT_CONNECTIONS, VLC_VAR_INTEGER, STATS_COUNTER ); stats_Create( host, "active_connections", STATS_ACTIVE_CONNECTIONS, VLC_VAR_INTEGER, STATS_COUNTER ); while( !host->b_die ) { struct timeval timeout; fd_set fds_read; fd_set fds_write; /* FIXME: (too) many int variables */ int fd, i_fd; int i_handle_max = 0; int i_ret; int i_client; int b_low_delay = 0; if( host->i_url <= 0 ) { /* 0.2s */ msleep( 200000 ); continue; } /* built a set of handle to select */ FD_ZERO( &fds_read ); FD_ZERO( &fds_write ); i_handle_max = -1; for( i_fd = 0; (fd = host->fd[i_fd]) != -1; i_fd++ ) { FD_SET( fd, &fds_read ); if( fd > i_handle_max ) i_handle_max = fd; } /* prepare a new TLS session */ if( ( p_tls == NULL ) && ( host->p_tls != NULL ) ) p_tls = tls_ServerSessionPrepare( host->p_tls ); /* add all socket that should be read/write and close dead connection */ vlc_mutex_lock( &host->lock ); for( 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 < mdate()) ) ) ) { httpd_ClientClean( cl ); stats_UpdateInteger( host, STATS_ACTIVE_CONNECTIONS, -1, NULL ); TAB_REMOVE( host->i_client, host->client, cl ); free( cl ); i_client--; continue; } else if( ( cl->i_state == HTTPD_CLIENT_RECEIVING ) || ( cl->i_state == HTTPD_CLIENT_TLS_HS_IN ) ) { FD_SET( cl->fd, &fds_read ); i_handle_max = __MAX( i_handle_max, cl->fd ); } else if( ( cl->i_state == HTTPD_CLIENT_SENDING ) || ( cl->i_state == HTTPD_CLIENT_TLS_HS_OUT ) ) { FD_SET( cl->fd, &fds_write ); i_handle_max = __MAX( i_handle_max, cl->fd ); } 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 ) { char *psz_cseq = NULL; int i_cseq; /* unimplemented */ answer->i_proto = query->i_proto ; answer->i_type = HTTPD_MSG_ANSWER; answer->i_version= 0; answer->i_status = 200; answer->psz_status = strdup( "Ok" ); answer->i_body = 0; answer->p_body = NULL; psz_cseq = httpd_MsgGet( query, "Cseq" ); if( psz_cseq ) i_cseq = atoi( psz_cseq ); else i_cseq = 0; httpd_MsgAdd( answer, "Cseq", "%d", i_cseq ); httpd_MsgAdd( answer, "Server", "VLC Server" ); httpd_MsgAdd( answer, "Public", "DESCRIBE, SETUP, " "TEARDOWN, PLAY, PAUSE" ); httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); 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 { uint8_t *p; /* unimplemented */ answer->i_proto = query->i_proto ; answer->i_type = HTTPD_MSG_ANSWER; answer->i_version= 0; answer->i_status = 501; answer->psz_status = strdup( "Unimplemented" ); p = answer->p_body = malloc( 1000 ); p += sprintf( (char *)p, "<?xml version=\"1.0\" encoding=\"ascii\" ?>" "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" " "\"http://www.w3.org/TR/xhtml10/DTD/xhtml10strict.dtd\">\n" "<html>\n" "<head>\n" "<title>Error 501</title>\n" "</head>\n" "<body>\n" "<h1>501 Unimplemented</h1>\n" "<hr />\n" "<a href=\"http://www.videolan.org\">VideoLAN</a>\n" "</body>\n" "</html>\n" ); answer->i_body = p - answer->p_body; httpd_MsgAdd( answer, "Content-Length", "%d", answer->i_body ); cl->i_buffer = -1; /* Force the creation of the answer in httpd_ClientSend */ cl->i_state = HTTPD_CLIENT_SENDING; } } else { vlc_bool_t b_auth_failed = VLC_FALSE; vlc_bool_t b_hosts_failed = VLC_FALSE; int i; /* Search the url and trigger callbacks */ for( i = 0; i < host->i_url; i++ ) { httpd_url_t *url = host->url[i]; if( !strcmp( url->psz_url, query->psz_url ) ) { if( url->catch[i_msg].cb ) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -