mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-05-30 18:16:31 +03:00
Fixed chunked transfer encoding (for real?).
--HG-- branch : dev
This commit is contained in:
@@ -589,8 +589,8 @@ Http::Response Http::downloadRequest(const Http::Request& request, IOStream& wri
|
||||
std::size_t currentTotalBytes = 0;
|
||||
std::size_t len = 0;
|
||||
std::size_t readed = 0;
|
||||
char * eol; // end of line
|
||||
char * bol; // beginning of line
|
||||
char * eol = NULL; // end of line
|
||||
char * bol = NULL; // beginning of line
|
||||
char buffer[PACKET_BUFFER_SIZE+1];
|
||||
std::string headerBuffer;
|
||||
std::string chunkBuffer;
|
||||
@@ -605,35 +605,18 @@ Http::Response Http::downloadRequest(const Http::Request& request, IOStream& wri
|
||||
std::size_t contentLength = 0;
|
||||
|
||||
while (!request.isCancelled() && ( status = mConnection->getSocket()->receive(buffer, PACKET_BUFFER_SIZE, readed) ) == Socket::Done) {
|
||||
char * readBuffer = buffer;
|
||||
|
||||
// If we didn't receive the header yet, we will try to find the end of the header
|
||||
if ( !isnheader ) {
|
||||
// calculate combined length of unprocessed data and new data
|
||||
len += readed;
|
||||
|
||||
// NULL terminate buffer for string functions
|
||||
buffer[len] = '\0';
|
||||
|
||||
// checks if the header break happened to be the first line of the buffer
|
||||
if ( 0 == strncmp( buffer, "\r\n", 2 ) ) {
|
||||
if (len > 2) {
|
||||
currentTotalBytes += (len-2);
|
||||
chunkBuffer.append(buffer, buffer + (len-2));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 0 == strncmp( buffer, "\n", 1 ) ) {
|
||||
if ( len > 1 ) {
|
||||
currentTotalBytes += (len-1);
|
||||
chunkBuffer.append(buffer, buffer + (len-1));
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
readBuffer[len] = '\0';
|
||||
|
||||
// process each line in buffer looking for header break
|
||||
bol = buffer;
|
||||
bol = readBuffer;
|
||||
|
||||
while( !isnheader && ( eol = strchr( bol, '\n') ) != NULL ) {
|
||||
// update bol based upon the value of eol
|
||||
@@ -652,26 +635,15 @@ Http::Response Http::downloadRequest(const Http::Request& request, IOStream& wri
|
||||
bol += 1;
|
||||
|
||||
// calculate the amount of data remaining in the buffer
|
||||
len = readed - ( bol - buffer );
|
||||
len = readed - ( bol - readBuffer );
|
||||
|
||||
// write remaining data to FILE stream
|
||||
if ( len > 0 ) {
|
||||
currentTotalBytes += len;
|
||||
chunkBuffer.append(bol, bol + len);
|
||||
}
|
||||
|
||||
headerBuffer.append( buffer, ( bol - buffer ) );
|
||||
|
||||
// reset length of left over data to zero and continue processing
|
||||
// non-header information
|
||||
len = 0;
|
||||
// Fill the header buffer
|
||||
headerBuffer.append( readBuffer, ( bol - readBuffer ) );
|
||||
|
||||
if ( !headerBuffer.empty() ) {
|
||||
// Build the Response object from the received data
|
||||
received.parse(headerBuffer);
|
||||
|
||||
headerBuffer.clear();
|
||||
|
||||
// Check if the response is chunked
|
||||
chunked = received.getField("transfer-encoding") == "chunked";
|
||||
|
||||
@@ -721,87 +693,124 @@ Http::Response Http::downloadRequest(const Http::Request& request, IOStream& wri
|
||||
}
|
||||
}
|
||||
|
||||
// If is not chunked just save the file buffer and clear it
|
||||
if ( !chunked && !chunkBuffer.empty() ) {
|
||||
fileBuffer.write( &chunkBuffer[0], chunkBuffer.size() );
|
||||
chunkBuffer.clear();
|
||||
// Move the readBuffer to the starting point
|
||||
// of the file buffer
|
||||
if ( len > 0 ) {
|
||||
readBuffer = bol;
|
||||
readed = len;
|
||||
} else {
|
||||
readed = 0;
|
||||
}
|
||||
|
||||
if ( chunked )
|
||||
readed = 0;
|
||||
headerBuffer.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( !isnheader ) {
|
||||
headerBuffer.append( buffer, ( bol - buffer ) );
|
||||
headerBuffer.append( readBuffer, ( bol - readBuffer ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isnheader ) {
|
||||
currentTotalBytes += readed;
|
||||
|
||||
if ( chunked && readed ) {
|
||||
// If the chunk reading ended we just add the buffer received as a header
|
||||
// Otherwise we process the buffer data as chunk
|
||||
if ( !chunkEnded ) {
|
||||
// Keep a chunk buffer until the end of chunk is found
|
||||
chunkBuffer.append( buffer, buffer + readed );
|
||||
if ( chunked ) {
|
||||
if ( readed > 0 ) {
|
||||
// If the chunk reading ended we just add the buffer received as a header
|
||||
// Otherwise we process the buffer data as chunk
|
||||
if ( !chunkEnded ) {
|
||||
// Keep a chunk buffer until the end of chunk is found
|
||||
chunkBuffer.append( readBuffer, readBuffer + readed );
|
||||
|
||||
// If the new chunk starts with \r\n and the last removed chunk
|
||||
// did not contain the trailing \r\n, we remove it to detect
|
||||
// correctly the next length data
|
||||
if ( chunkNewBuffer ) {
|
||||
if ( chunkBuffer.substr( 0, 2 ) == "\r\n" ) {
|
||||
chunkBuffer = chunkBuffer.substr( 2 );
|
||||
// If the new chunk starts with \r\n and the last removed chunk
|
||||
// did not contain the trailing \r\n, we remove it to detect
|
||||
// correctly the next length data
|
||||
if ( chunkNewBuffer ) {
|
||||
if ( chunkBuffer.substr( 0, 2 ) == "\r\n" ) {
|
||||
chunkBuffer = chunkBuffer.substr( 2 );
|
||||
}
|
||||
|
||||
chunkNewBuffer = false;
|
||||
}
|
||||
|
||||
chunkNewBuffer = false;
|
||||
}
|
||||
bool retry;
|
||||
|
||||
// Check for the first \r\n to find the end of the length definition
|
||||
std::string::size_type lenEnd = chunkBuffer.find_first_of("\r\n");
|
||||
do {
|
||||
retry = false;
|
||||
|
||||
if ( lenEnd != std::string::npos ) {
|
||||
std::string::size_type firstCharPos = lenEnd + 2;
|
||||
unsigned long length;
|
||||
// Check for the first \r\n to find the end of the length definition
|
||||
std::string::size_type lenEnd = chunkBuffer.find_first_of("\r\n");
|
||||
|
||||
// Get the length of the chunk
|
||||
bool res = String::fromString( length, chunkBuffer.substr(0, lenEnd), std::hex );
|
||||
if ( lenEnd != std::string::npos ) {
|
||||
std::string::size_type firstCharPos = lenEnd + 2;
|
||||
unsigned long length;
|
||||
|
||||
// If the length is solved...
|
||||
if ( res ) {
|
||||
// And it's bigger than 0, means that there are more chunks
|
||||
if ( length > 0 ) {
|
||||
// Check if the chunk buffer size at least equals to the length reported
|
||||
if ( chunkBuffer.size() - firstCharPos >= length ) {
|
||||
// In that case write the chunk to the file buffer
|
||||
fileBuffer.write( &chunkBuffer[firstCharPos], length );
|
||||
// Get the length of the chunk
|
||||
bool res = String::fromString( length, chunkBuffer.substr(0, lenEnd), std::hex );
|
||||
|
||||
// And keep the remaining not completed chunk
|
||||
chunkBuffer = chunkBuffer.substr( firstCharPos + length );
|
||||
chunkNewBuffer = true;
|
||||
// If the length is solved...
|
||||
if ( res ) {
|
||||
// And it's bigger than 0, means that there are more chunks
|
||||
if ( length > 0 ) {
|
||||
// Check if the chunk buffer size at least equals to the length reported
|
||||
if ( chunkBuffer.size() - firstCharPos >= length ) {
|
||||
// In that case write the chunk to the file buffer
|
||||
fileBuffer.write( &chunkBuffer[firstCharPos], length );
|
||||
|
||||
// Check if already have the \r\n of the next length in the buffer
|
||||
if ( !chunkBuffer.empty() && chunkBuffer.substr( 0, 2 ) == "\r\n" ) {
|
||||
// Remove it to be able to read the next length
|
||||
chunkBuffer = chunkBuffer.substr( 2 );
|
||||
chunkNewBuffer = false;
|
||||
// And keep the remaining not completed chunk
|
||||
chunkBuffer = chunkBuffer.substr( firstCharPos + length );
|
||||
|
||||
// Check if already have the \r\n of the next length in the buffer
|
||||
if ( !chunkBuffer.empty() ) {
|
||||
std::size_t pos = 0;
|
||||
|
||||
// Remove al the \r\n remaining
|
||||
while ( pos < chunkBuffer.size() && 0 == strncmp( &chunkBuffer[pos], "\r\n", 2 ) ) {
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
if ( pos > 0 ) {
|
||||
// Remove it to be able to read the next length
|
||||
chunkBuffer = chunkBuffer.substr( pos );
|
||||
}
|
||||
|
||||
// If still the chunk is not empty it could be another chunk
|
||||
// already received, so we check that retrying
|
||||
if ( !chunkBuffer.empty() ) {
|
||||
std::string::size_type lenEnd = chunkBuffer.find_first_of("\r\n");
|
||||
|
||||
if ( lenEnd != std::string::npos ) {
|
||||
bool res = String::fromString( length, chunkBuffer.substr(0, lenEnd), std::hex );
|
||||
|
||||
if ( res && length > 0 ) {
|
||||
retry = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If the next chunk received starts with \r\n it's because
|
||||
// it's part of the chunk size information, so we need to flag it
|
||||
// to remove it
|
||||
chunkNewBuffer = true;
|
||||
}
|
||||
} else {
|
||||
// If the value is 0 means that the data ended
|
||||
// But after this we can receive extra headers
|
||||
chunkEnded = true;
|
||||
chunkBuffer.clear();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If the value is 0 means that the data ended
|
||||
// But after this we can receive extra headers
|
||||
chunkEnded = true;
|
||||
}
|
||||
}
|
||||
} while ( retry );
|
||||
} else {
|
||||
headerBuffer.append( readBuffer, readBuffer + readed );
|
||||
}
|
||||
} else {
|
||||
headerBuffer.append( buffer, buffer + readed );
|
||||
}
|
||||
} else {
|
||||
} else if ( readed > 0 ) {
|
||||
// If not chunked just write into the file buffer
|
||||
fileBuffer.write( buffer, readed );
|
||||
fileBuffer.write( readBuffer, readed );
|
||||
}
|
||||
|
||||
if ( compressed ) {
|
||||
|
||||
Reference in New Issue
Block a user