std::shared_ptr<Response> request_read() { std::shared_ptr<Response> response(new Response()); try { size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n\r\n"); size_t num_additional_bytes = response->content_buffer.size() - bytes_transferred; parse_response_header(response, response->content); auto header_it = response->header.find("Content-Length"); if (header_it != response->header.end()) { auto content_length = stoull(header_it->second); if (content_length>num_additional_bytes) { boost::asio::read(*socket, response->content_buffer, boost::asio::transfer_exactly(content_length - num_additional_bytes)); } } else if ((header_it = response->header.find("Transfer-Encoding")) != response->header.end() && header_it->second == "chunked") { boost::asio::streambuf streambuf; std::ostream content(&streambuf); std::streamsize length; std::string buffer; do { size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n"); std::string line; getline(response->content, line); bytes_transferred -= line.size() + 1; line.pop_back(); length = stol(line, 0, 16); auto num_additional_bytes = static_cast<std::streamsize>(response->content_buffer.size() - bytes_transferred); if ((2 + length)>num_additional_bytes) { boost::asio::read(*socket, response->content_buffer, boost::asio::transfer_exactly(2 + length - num_additional_bytes)); } buffer.resize(static_cast<size_t>(length)); response->content.read(&buffer[0], length); content.write(&buffer[0], length); //Remove "\r\n" response->content.get(); response->content.get(); } while (length>0); std::ostream response_content_output_stream(&response->content_buffer); response_content_output_stream << content.rdbuf(); } } catch (const std::exception& e) { socket_error = true; throw std::invalid_argument(e.what()); } return response; }
std::shared_ptr<Response> request(const std::string& request_type, const std::string& path, std::ostream& content, const std::map<std::string, std::string>& header=std::map<std::string, std::string>()) { std::string corrected_path=path; if(corrected_path=="") corrected_path="/"; content.seekp(0, std::ios::end); size_t content_length=content.tellp(); content.seekp(0, std::ios::beg); boost::asio::streambuf write_buffer; std::ostream write_stream(&write_buffer); write_stream << request_type << " " << corrected_path << " HTTP/1.1\r\n"; write_stream << "Host: " << host << "\r\n"; for(auto& h: header) { write_stream << h.first << ": " << h.second << "\r\n"; } if(content_length>0) write_stream << "Content-Length: " << std::to_string(content_length) << "\r\n"; write_stream << "\r\n"; if(content_length>0) write_stream << content.rdbuf(); std::shared_ptr<Response> response(new Response()); try { connect(); boost::asio::write(*socket, write_buffer); size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n\r\n"); size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred; parse_response_header(response, response->content); if(response->header.count("Content-Length")>0) { boost::asio::read(*socket, response->content_buffer, boost::asio::transfer_exactly(stoull(response->header["Content-Length"])-num_additional_bytes)); } else if(response->header.count("Transfer-Encoding")>0 && response->header["Transfer-Encoding"]=="chunked") { boost::asio::streambuf streambuf; std::ostream content(&streambuf); size_t length; std::string buffer; do { size_t bytes_transferred = boost::asio::read_until(*socket, response->content_buffer, "\r\n"); std::string line; getline(response->content, line); bytes_transferred-=line.size()+1; line.pop_back(); length=stoull(line, 0, 16); size_t num_additional_bytes=response->content_buffer.size()-bytes_transferred; if((2+length)>num_additional_bytes) { boost::asio::read(*socket, response->content_buffer, boost::asio::transfer_exactly(2+length-num_additional_bytes)); } buffer.resize(length); response->content.read(&buffer[0], length); content.write(&buffer[0], length); //Remove "\r\n" response->content.get(); response->content.get(); } while(length>0); std::ostream response_content_output_stream(&response->content_buffer); response_content_output_stream << content.rdbuf(); } } catch(const std::exception& e) { socket_error=true; throw std::invalid_argument(e.what()); } return response; }