diff --git a/ChangeLog b/ChangeLog index 46b2c45..2cf6b9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,20 @@ Version 1.6.7 ******************************************************************************* +2010-09-07 Marcelo Jimenez + Using UpnpReadHttpGet to download large files causes the application to + crash. This happens when the file being downloaded exceeds the device + memory - entirely possible when transferring video files. + The programmatic cause is that the logic implemented in the function + http_ReadHttpGet (which UpnpReadHttpGet calls) reads the entire file + into memory. The fix modifies the existing logic to discard data after + it's been read; there's no reason to keep it around since the caller + of UpnpReadHttpGet already has a copy of it. + + This issue exists in 1.6.6 as well as the latest sources. + + Patch submitted by Chandra (inactiveneurons). + 2010-09-07 Marcelo Jimenez In the latest sources, http_RequestAndResponse and other methods that use connect() are broken. More specifically, connect() in these methods diff --git a/upnp/src/genlib/net/http/httpparser.c b/upnp/src/genlib/net/http/httpparser.c index 1e41080..898d4d9 100644 --- a/upnp/src/genlib/net/http/httpparser.c +++ b/upnp/src/genlib/net/http/httpparser.c @@ -1909,9 +1909,9 @@ parser_parse_entity_using_clen( INOUT http_parser_t * parser ) assert( parser->ent_position == ENTREAD_USING_CLEN ); // determine entity (i.e. body) length so far - //entity_length = parser->msg.msg.length - parser->entity_start_position; parser->msg.entity.length = - parser->msg.msg.length - parser->entity_start_position; + parser->msg.msg.length - parser->entity_start_position + + parser->msg.entity_offset; if( parser->msg.entity.length < parser->content_length ) { // more data to be read @@ -1919,7 +1919,8 @@ parser_parse_entity_using_clen( INOUT http_parser_t * parser ) } else { if( parser->msg.entity.length > parser->content_length ) { // silently discard extra data - parser->msg.msg.buf[parser->entity_start_position + + parser->msg.msg.buf[parser->entity_start_position - + parser->msg.entity_offset + parser->content_length] = '\0'; } // save entity length @@ -2304,6 +2305,7 @@ parser_response_init( OUT http_parser_t * parser, parser_init( parser ); parser->msg.is_request = FALSE; parser->msg.request_method = request_method; + parser->msg.entity_offset = 0; parser->position = POS_RESPONSE_LINE; } diff --git a/upnp/src/genlib/net/http/httpreadwrite.c b/upnp/src/genlib/net/http/httpreadwrite.c index 36aefbe..7473658 100644 --- a/upnp/src/genlib/net/http/httpreadwrite.c +++ b/upnp/src/genlib/net/http/httpreadwrite.c @@ -256,7 +256,7 @@ int http_RecvMessage( "<<< (RECVD) <<<\n%s\n-----------------\n", parser->msg.msg.buf ); print_http_headers( &parser->msg ); - if (parser->content_length > (unsigned int)g_maxContentLength) { + if (g_maxContentLength > 0 && parser->content_length > (unsigned int)g_maxContentLength) { *http_error_code = HTTP_REQ_ENTITY_TOO_LARGE; line = __LINE__; ret = UPNP_E_OUTOF_BOUNDS; @@ -1070,10 +1070,10 @@ errorHandler: } typedef struct HTTPGETHANDLE { - http_parser_t response; - SOCKINFO sock_info; - int entity_offset; - int cancel; + http_parser_t response; + SOCKINFO sock_info; + int entity_offset; + int cancel; } http_get_handle_t; /************************************************************************ @@ -1327,9 +1327,10 @@ http_ReadHttpGet( IN void *Handle, int ret_code = 0; - if( ( !handle ) || ( !size ) || ( ( ( *size ) > 0 ) && !buf ) - || ( ( *size ) < 0 ) ) { - if(size) ( *size ) = 0; + if( !handle || !size || (*size > 0 && !buf) || *size < 0) { + if(size) { + *size = 0; + } return UPNP_E_INVALID_PARAM; } //first parse what has already been gotten @@ -1346,11 +1347,11 @@ http_ReadHttpGet( IN void *Handle, && ( status != PARSE_CONTINUE_1 ) && ( status != PARSE_INCOMPLETE ) ) { //error - ( *size ) = 0; + *size = 0; return UPNP_E_BAD_RESPONSE; } //read more if necessary entity - while( ( ( handle->entity_offset + ( *size ) ) > + while( ( ( handle->response.msg.entity_offset + *size ) > handle->response.msg.entity.length ) && ( ! handle->cancel ) && ( handle->response.position != POS_COMPLETE ) ) { @@ -1365,7 +1366,7 @@ http_ReadHttpGet( IN void *Handle, // set failure status handle->response.http_error_code = HTTP_INTERNAL_SERVER_ERROR; - ( *size ) = 0; + *size = 0; return PARSE_FAILURE; } status = parser_parse_entity( &handle->response ); @@ -1376,7 +1377,7 @@ http_ReadHttpGet( IN void *Handle, && ( status != PARSE_CONTINUE_1 ) && ( status != PARSE_INCOMPLETE ) ) { //error - ( *size ) = 0; + *size = 0; return UPNP_E_BAD_RESPONSE; } } else if( num_read == 0 ) { @@ -1387,31 +1388,33 @@ http_ReadHttpGet( IN void *Handle, handle->response.position = POS_COMPLETE; } else { // partial msg - ( *size ) = 0; + *size = 0; handle->response.http_error_code = HTTP_BAD_REQUEST; // or response return UPNP_E_BAD_HTTPMSG; } } else { - ( *size ) = 0; + *size = 0; return num_read; } } - if( ( handle->entity_offset + ( *size ) ) > - handle->response.msg.entity.length ) { - ( *size ) = - handle->response.msg.entity.length - handle->entity_offset; + if ((handle->response.msg.entity_offset + *size) > handle->response.msg.entity.length) { + *size = handle->response.msg.entity.length - handle->response.msg.entity_offset; } - memcpy( buf, - &handle->response.msg.msg.buf[handle-> - response.entity_start_position + - handle->entity_offset], - ( *size ) ); - handle->entity_offset += ( *size ); + memcpy(buf, + &handle->response.msg.msg.buf[handle->response.entity_start_position], + *size); + if (*size > 0) { + membuffer_delete(&handle->response.msg.msg, + handle->response.entity_start_position, + *size); + } - if ( handle->cancel ) + handle->response.msg.entity_offset += *size; + if (handle->cancel) { return UPNP_E_CANCELED; + } return UPNP_E_SUCCESS; } @@ -1498,7 +1501,6 @@ http_CloseHttpGet( IN void *Handle ) sock_destroy( &handle->sock_info, SD_BOTH ); //should shutdown completely httpmsg_destroy( &handle->response.msg ); - handle->entity_offset = 0; free( handle ); return UPNP_E_SUCCESS; } @@ -1609,7 +1611,6 @@ int http_OpenHttpGetProxy( if (!handle) { return UPNP_E_OUTOF_MEMORY; } - handle->entity_offset = 0; handle->cancel = 0; parser_response_init(&handle->response, HTTPMETHOD_GET); tcp_connection = socket(peer->hostport.IPaddress.ss_family, SOCK_STREAM, 0); @@ -2240,7 +2241,6 @@ int http_OpenHttpGetEx( break; } memset(handle, 0, sizeof(*handle)); - handle->entity_offset = 0; parser_response_init(&handle->response, HTTPMETHOD_GET); tcp_connection = socket(url.hostport.IPaddress.ss_family, SOCK_STREAM, 0); if (tcp_connection == -1) { diff --git a/upnp/src/inc/httpparser.h b/upnp/src/inc/httpparser.h index 821862b..a1bdb86 100644 --- a/upnp/src/inc/httpparser.h +++ b/upnp/src/inc/httpparser.h @@ -193,7 +193,8 @@ typedef struct // http_message_t // private fields membuffer msg; // entire raw message - char *urlbuf; // storage for url string + char *urlbuf; // storage for url string + size_t entity_offset; } http_message_t; typedef struct // http_parser_t