Added support for chunked http transfers

sf::Http now understands transfers that are sent using Chunked Transfer
Encoding (RFC 2616; section 3.6.1).
This commit is contained in:
Mario Liebisch 2012-12-11 19:08:56 +01:00
parent 08b49cc15c
commit 306b77bfc5
2 changed files with 53 additions and 5 deletions

View File

@ -316,6 +316,18 @@ public :
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
void parse(const std::string& data); void parse(const std::string& data);
////////////////////////////////////////////////////////////
/// \brief Read values passed in the answer header
///
/// This function is used by Http to extract values passed
/// in the response.
///
/// \param in String stream containing the header values
///
////////////////////////////////////////////////////////////
void parseFields(std::istream &in);
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////
// Types // Types
//////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////

View File

@ -31,6 +31,7 @@
#include <algorithm> #include <algorithm>
#include <iterator> #include <iterator>
#include <sstream> #include <sstream>
#include <limits>
namespace namespace
@ -231,9 +232,48 @@ void Http::Response::parse(const std::string& data)
} }
// Ignore the end of the first line // Ignore the end of the first line
in.ignore(10000, '\n'); in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Parse the other lines, which contain fields, one by one // Parse the other lines, which contain fields, one by one
parseFields(in);
m_body.clear();
// Determine whether the transfer is chunked
if (toLower(getField("transfer-encoding")) != "chunked")
{
// Not chunked - just read everything at once
std::copy(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>(), std::back_inserter(m_body));
}
else
{
// Chunked - have to read chunk by chunk
std::size_t length;
// Read all chunks, identified by a chunk-size not being 0
while (in >> std::hex >> length)
{
// Drop the rest of the line (chunk-extension)
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Copy the actual content data
std::istreambuf_iterator<char> it(in);
for (std::size_t i = 0; i < length; i++)
m_body.push_back(*it++);
}
// Drop the rest of the line (chunk-extension)
in.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
// Read all trailers (if present)
parseFields(in);
}
}
////////////////////////////////////////////////////////////
void Http::Response::parseFields(std::istream &in)
{
std::string line; std::string line;
while (std::getline(in, line) && (line.size() > 2)) while (std::getline(in, line) && (line.size() > 2))
{ {
@ -252,10 +292,6 @@ void Http::Response::parse(const std::string& data)
m_fields[toLower(field)] = value; m_fields[toLower(field)] = value;
} }
} }
// Finally extract the body
m_body.clear();
std::copy(std::istreambuf_iterator<char>(in), std::istreambuf_iterator<char>(), std::back_inserter(m_body));
} }