diff --git a/engine/common/http/net_http_xash.c b/engine/common/http/net_http_xash.c index b0f98bb3..eb18b92e 100644 --- a/engine/common/http/net_http_xash.c +++ b/engine/common/http/net_http_xash.c @@ -70,6 +70,8 @@ typedef struct httpfile_s http_process_fn_t pfn_process; struct sockaddr_storage addr; int redirects_followed; + qboolean url_in_server; + tlsctx_t *tls; // in-memory response mode (set by HTTP_GetToMemory) qboolean to_memory; @@ -115,6 +117,7 @@ static int HTTP_FileProcessStream( httpfile_t *file ); static int HTTP_FileQueue( httpfile_t *file ); static int HTTP_FileResolveNS( httpfile_t *file ); static int HTTP_FileSendRequest( httpfile_t *file ); +static int HTTP_FileTlsHandshake( httpfile_t *file ); static int HTTP_FileDecompress( httpfile_t *file ); static httpserver_t *HTTP_ParseURLEx( const char *url_, qboolean full_path ); static qboolean HTTP_FileRedirect( httpfile_t *file, const char *location ); @@ -149,6 +152,12 @@ static void HTTP_FreeFile( httpfile_t *file, qboolean error ) file->file = NULL; + if( file->tls ) + { + HTTP_TlsFree( file->tls ); + file->tls = NULL; + } + if( file->socket != -1 ) { closesocket( file->socket ); @@ -370,6 +379,8 @@ static int HTTP_FileConnect( httpfile_t *file ) } else Q_strncpy( useragent, http_useragent.string, sizeof( useragent )); + const char *path_suffix = file->url_in_server ? "" : file->path; + if( file->to_memory ) { file->query_length = Q_snprintf( file->buf, sizeof( file->buf ), @@ -377,7 +388,7 @@ static int HTTP_FileConnect( httpfile_t *file ) "Host: %s:%d\r\n" "User-Agent: %s\r\n" "Accept: */*\r\n\r\n", - file->server->path, file->path, + file->server->path, path_suffix, file->server->host, file->server->port, useragent ); } @@ -389,20 +400,60 @@ static int HTTP_FileConnect( httpfile_t *file ) "User-Agent: %s\r\n" "Accept-Encoding: gzip, deflate\r\n" "Accept: */*\r\n\r\n", - file->server->path, file->path, + file->server->path, path_suffix, file->server->host, file->server->port, useragent ); } Q_strncpy( file->query_backup, file->buf, sizeof( file->query_backup )); file->bytes_sent = 0; file->header_size = 0; - file->pfn_process = HTTP_FileSendRequest; + + if( file->server->secure ) + { + file->tls = HTTP_TlsNew( file->socket, file->server->host ); + if( !file->tls ) + { + Con_Printf( S_ERROR "TLS context allocation failed for %s\n", file->server->host ); + HTTP_FreeFile( file, true ); + return 0; + } + file->pfn_process = HTTP_FileTlsHandshake; + } + else file->pfn_process = HTTP_FileSendRequest; + return 1; } +static int HTTP_FileTlsHandshake( httpfile_t *file ) +{ + int ret = HTTP_TlsHandshake( file->tls ); + + if( ret == HTTP_TLS_OK ) + { + file->blocktime = 0; + file->pfn_process = HTTP_FileSendRequest; + return 1; + } + + if( ret == HTTP_TLS_WANT ) + { + file->blocktime += host.frametime; + file->blockreason = "TLS handshake"; + return 0; + } + + HTTP_FreeFile( file, true ); + return 0; +} + static int HTTP_FileSendRequest( httpfile_t *file ) { - int res = send( file->socket, file->buf + file->bytes_sent, file->query_length - file->bytes_sent, 0 ); + int res; + + if( file->tls ) + res = HTTP_TlsSend( file->tls, file->buf + file->bytes_sent, file->query_length - file->bytes_sent ); + else + res = send( file->socket, file->buf + file->bytes_sent, file->query_length - file->bytes_sent, 0 ); if( res >= 0 ) { @@ -420,6 +471,17 @@ static int HTTP_FileSendRequest( httpfile_t *file ) return 1; } } + else if( file->tls ) + { + if( res != HTTP_TLS_WANT ) + { + HTTP_FreeFile( file, true ); + return 0; + } + + file->blocktime += host.frametime; + file->blockreason = "request send"; + } else { int err = WSAGetLastError(); @@ -792,8 +854,18 @@ static int HTTP_FileProcessStream( httpfile_t *curfile ) int res; // if we got there, we are receiving data - while(( res = recv( curfile->socket, buf, sizeof( buf ) - curfile->header_size - 1, 0 )) > 0 ) + while( 1 ) { + int rlen = sizeof( buf ) - curfile->header_size - 1; + + if( curfile->tls ) + res = HTTP_TlsRecv( curfile->tls, buf, rlen ); + else + res = recv( curfile->socket, buf, rlen, 0 ); + + if( res <= 0 ) + break; + curfile->blocktime = 0; if( !curfile->got_response ) // Response still not received @@ -989,13 +1061,24 @@ static int HTTP_FileProcessStream( httpfile_t *curfile ) if( res < 0 ) { - int err = WSAGetLastError(); - - if( err != WSAEWOULDBLOCK && err != WSAEINPROGRESS ) + if( curfile->tls ) { - Con_Reportf( "problem downloading %s: %s\n", curfile->path, NET_ErrorString( )); - HTTP_FreeFile( curfile, true ); - return 0; + if( res != HTTP_TLS_WANT ) + { + HTTP_FreeFile( curfile, true ); + return 0; + } + } + else + { + int err = WSAGetLastError(); + + if( err != WSAEWOULDBLOCK && err != WSAEINPROGRESS ) + { + Con_Reportf( "problem downloading %s: %s\n", curfile->path, NET_ErrorString( )); + HTTP_FreeFile( curfile, true ); + return 0; + } } curfile->blocktime += host.frametime; @@ -1259,6 +1342,12 @@ static qboolean HTTP_FileRedirect( httpfile_t *file, const char *location ) Con_Reportf( "HTTP: redirect %s -> %s\n", file->to_memory ? file->url : file->path, location ); // tear down current connection but keep file/mem buffers + if( file->tls ) + { + HTTP_TlsFree( file->tls ); + file->tls = NULL; + } + if( file->socket != -1 ) { closesocket( file->socket ); @@ -1287,8 +1376,7 @@ static qboolean HTTP_FileRedirect( httpfile_t *file, const char *location ) file->chunksize = 0; file->size = file->reported_size; - // redirect Location: gave us a full URL, so per-file suffix is empty now - file->path[0] = 0; + file->url_in_server = true; if( file->to_memory ) Q_strncpy( file->url, location, sizeof( file->url )); @@ -1353,6 +1441,9 @@ static void HTTP_Clear_f( void ) if( file->file ) FS_Close( file->file ); + if( file->tls ) + HTTP_TlsFree( file->tls ); + if( file->socket != -1 ) closesocket( file->socket ); @@ -1452,6 +1543,8 @@ void HTTP_Init( void ) http.first_file = NULL; http_mempool = Mem_AllocPool( "HTTP" ); + HTTP_TlsInit(); + Cmd_AddRestrictedCommand( "http_download", HTTP_Download_f, "add file to download queue" ); Cmd_AddRestrictedCommand( "http_skip", HTTP_Skip_f, "skip current download server" ); Cmd_AddRestrictedCommand( "http_cancel", HTTP_Cancel_f, "cancel current download" ); @@ -1484,5 +1577,7 @@ void HTTP_Shutdown( void ) Mem_Free( tmp ); } + HTTP_TlsShutdown(); + Mem_FreePool( &http_mempool ); }