diff --git a/include/fc/network/http/connection.hpp b/include/fc/network/http/connection.hpp index 3c8de77..153a47e 100644 --- a/include/fc/network/http/connection.hpp +++ b/include/fc/network/http/connection.hpp @@ -60,7 +60,7 @@ namespace fc { ~connection(); // used for clients void connect_to( const fc::ip::endpoint& ep ); - http::reply request( const fc::string& method, const fc::string& url, const fc::string& body = std::string(), const headers& = headers()); + http::reply request( const fc::string& method, const fc::string& url, const fc::string& body = std::string(), const headers& = headers(), const fc::string& content_type = "application/json"); // used for servers fc::tcp_socket& get_socket()const; diff --git a/src/network/http/http_connection.cpp b/src/network/http/http_connection.cpp index 309866d..b90a469 100644 --- a/src/network/http/http_connection.cpp +++ b/src/network/http/http_connection.cpp @@ -45,6 +45,8 @@ class fc::http::connection::impl rep.status = static_cast(to_int64(fc::string(line.data()))); s = read_until( line.data(), line.data()+line.size(), '\n' ); // DESCRIPTION + fc::optional content_length; + bool is_chunked = false; while( (s = read_until( line.data(), line.data()+line.size(), '\n' )) > 1 ) { fc::http::header h; char* end = line.data(); @@ -56,13 +58,50 @@ class fc::http::connection::impl while( *end != '\r' ) ++end; h.val = fc::string(skey,end); rep.headers.push_back(h); - if( boost::iequals(h.key, "Content-Length") ) { - rep.body.resize( static_cast(to_uint64( fc::string(h.val) ) )); + if( boost::iequals(h.key, "Content-Length") ) + content_length = static_cast(to_uint64( fc::string(h.val) )); + if( boost::iequals(h.key, "Transfer-Encoding") && + boost::iequals(fc::string(h.val), "chunked") ) + is_chunked = true; + } + + if (is_chunked) + { + // Chunked means we get a hexadecimal number of bytes on a line, followed by the content + s = read_until( line.data(), line.data()+line.size(), '\n' ); // DESCRIPTION + if (line[strlen(line.data())] == '\r') + line[strlen(line.data())] = 0; + unsigned length; + if (sscanf(line.data(), "%x", &length) != 1) + FC_THROW("Invalid content length: ${length}", ("length", fc::string(line.data()))); + content_length = length; + } + + if (content_length) + { + if (*content_length) + { + rep.body.resize(*content_length); + sock.read( rep.body.data(), *content_length ); } } - if( rep.body.size() ) { - sock.read( rep.body.data(), rep.body.size() ); + else + { + std::shared_ptr buf(new char); + while (true) + { + try + { + sock.read(buf, sizeof(buf), 0); + rep.body.push_back(*buf); + } + catch (const fc::eof_exception&) + { + break; + } + } } + return rep; } catch ( fc::exception& e ) { elog( "${exception}", ("exception",e.to_detail_string() ) ); @@ -89,8 +128,10 @@ void connection::connect_to( const fc::ip::endpoint& ep ) { } http::reply connection::request( const fc::string& method, - const fc::string& url, - const fc::string& body, const headers& he ) { + const fc::string& url, + const fc::string& body, + const headers& he, + const fc::string& content_type ) { fc::url parsed_url(url); if( !my->sock.is_open() ) { @@ -101,7 +142,7 @@ http::reply connection::request( const fc::string& method, fc::stringstream req; req << method <<" "<generic_string()<<" HTTP/1.1\r\n"; req << "Host: "<<*parsed_url.host()<<"\r\n"; - req << "Content-Type: application/json\r\n"; + req << "Content-Type: " << content_type << "\r\n"; for( auto i = he.begin(); i != he.end(); ++i ) { req << i->key <<": " << i->val<<"\r\n"; diff --git a/vendor/websocketpp b/vendor/websocketpp index c5510d6..13f6da6 160000 --- a/vendor/websocketpp +++ b/vendor/websocketpp @@ -1 +1 @@ -Subproject commit c5510d6de04917812b910a8dd44735c1f17061d9 +Subproject commit 13f6da6f81207ae7e67f0e7d25ed0e3cc2ec2f9c