From c290975778942ed1082ca66918695a5bd2d6bac4 Mon Sep 17 00:00:00 2001 From: Aki Tuomi Date: Tue, 23 Dec 2014 11:07:26 +0200 Subject: [PATCH] Sync with upstream --- pdns/ext/yahttp/yahttp/cookie.hpp | 6 ++- pdns/ext/yahttp/yahttp/reqresp.cpp | 48 ++++++++++++++++++---- pdns/ext/yahttp/yahttp/reqresp.hpp | 64 +++++++++++++++++++++++------- pdns/ext/yahttp/yahttp/router.cpp | 1 - pdns/ext/yahttp/yahttp/utility.hpp | 31 +++++++++++++-- 5 files changed, 123 insertions(+), 27 deletions(-) diff --git a/pdns/ext/yahttp/yahttp/cookie.hpp b/pdns/ext/yahttp/yahttp/cookie.hpp index 4b285aa760c4..b99b21e01041 100644 --- a/pdns/ext/yahttp/yahttp/cookie.hpp +++ b/pdns/ext/yahttp/yahttp/cookie.hpp @@ -46,13 +46,17 @@ namespace YaHTTP { /*! Implements a Cookie jar for storing multiple cookies */ class CookieJar { public: - std::map cookies; // cookies; //cookies = rhs.cookies; } //cookies.clear(); + } + void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value) { size_t pos; pos = keyvalue.find("="); diff --git a/pdns/ext/yahttp/yahttp/reqresp.cpp b/pdns/ext/yahttp/yahttp/reqresp.cpp index 14196b998dcf..2d28c0adc303 100644 --- a/pdns/ext/yahttp/yahttp/reqresp.cpp +++ b/pdns/ext/yahttp/yahttp/reqresp.cpp @@ -6,9 +6,10 @@ namespace YaHTTP { buffer.append(somedata); while(state < 2) { int cr=0; + pos = buffer.find_first_of("\n"); // need to find CRLF in buffer - if ((pos = buffer.find_first_of("\n")) == std::string::npos) return false; - if (buffer[pos-1]=='\r') + if (pos == std::string::npos) return false; + if (pos>0 && buffer[pos-1]=='\r') cr=1; std::string line(buffer.begin(), buffer.begin()+pos-cr); // exclude CRLF buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer including CRLF @@ -43,11 +44,15 @@ namespace YaHTTP { break; } // split headers - if ((pos = line.find_first_of(": ")) == std::string::npos) + if ((pos = line.find(": ")) == std::string::npos) throw ParseError("Malformed header line"); key = line.substr(0, pos); value = line.substr(pos+2); - Utility::trimRight(value); + for(std::string::iterator it=key.begin(); it != key.end(); it++) + if (std::isspace(*it)) + throw ParseError("Header key contains whitespace which is not allowed by RFC"); + + Utility::trim(value); std::transform(key.begin(), key.end(), key.begin(), ::tolower); // is it already defined @@ -157,14 +162,40 @@ namespace YaHTTP { } os << "\r\n"; + bool cookieSent = false; + bool sendChunked = false; + + if (headers.find("content-length") == headers.end()) { + // must use chunked on response + sendChunked = (kind == YAHTTP_TYPE_RESPONSE); + if ((headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second != "chunked")) { + throw YaHTTP::Error("Transfer-encoding must be chunked, or Content-Length defined"); + } + if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) { + sendChunked = true; + // write the header now + os << "Transfer-Encoding: chunked" << "\r\n"; + } + } else { + if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) { + sendChunked = true; + // write the header now + os << "Transfer-Encoding: chunked" << "\r\n"; + } else if (headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second == "chunked") { + sendChunked = true; + } + } + // write headers strstr_map_t::const_iterator iter = headers.begin(); while(iter != headers.end()) { if (iter->first == "host" && kind != YAHTTP_TYPE_REQUEST) { iter++; continue; } + std::string header = Utility::camelizeHeader(iter->first); + if (header == "Cookie" || header == "Set-Cookie") cookieSent = true; os << Utility::camelizeHeader(iter->first) << ": " << iter->second << "\r\n"; iter++; } - if (jar.cookies.size() > 0) { // write cookies + if (!cookieSent && jar.cookies.size() > 0) { // write cookies for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) { if (kind == YAHTTP_TYPE_REQUEST) { os << "Cookie: "; @@ -176,9 +207,10 @@ namespace YaHTTP { } os << "\r\n"; #ifdef HAVE_CPP_FUNC_PTR - this->renderer(this, os); + this->renderer(this, os, sendChunked); #else - os << body; + SendbodyRenderer r; + r(this, os, chunked) #endif }; @@ -193,7 +225,7 @@ namespace YaHTTP { while(is.good()) { char buf[1024]; is.read(buf, 1024); - if (is.gcount()) { // did we actually read anything + if (is.gcount()>0) { // did we actually read anything is.clear(); if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed } diff --git a/pdns/ext/yahttp/yahttp/reqresp.hpp b/pdns/ext/yahttp/yahttp/reqresp.hpp index 29718806b76a..17ee9f52ebc9 100644 --- a/pdns/ext/yahttp/yahttp/reqresp.hpp +++ b/pdns/ext/yahttp/yahttp/reqresp.hpp @@ -18,6 +18,8 @@ namespace funcptr = boost; #include #endif +#include + #ifndef YAHTTP_MAX_REQUEST_SIZE #define YAHTTP_MAX_REQUEST_SIZE 2097152 #endif @@ -30,8 +32,7 @@ namespace funcptr = boost; #define YAHTTP_TYPE_RESPONSE 2 namespace YaHTTP { - typedef std::map strstr_map_t; // strcookie_map_t; // strcookie_map_t; //body; + size_t operator()(const HTTPBase *doc, std::ostream& os, bool chunked) const { + if (chunked) { + std::string::size_type i,cl; + for(i=0;ibody.length();i+=1024) { + cl = std::min(static_cast(1024), doc->body.length()-i); // for less than 1k blocks + os << std::hex << cl << "\r\n"; + os << doc->body.substr(i, cl) << "\r\n"; + } + os << 0 << "\r\n\r\n"; // last chunk + } else { + os << doc->body; + } return doc->body.length(); }; //path = path; }; - size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream& os) const { + size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream& os, bool chunked) const { char buf[4096]; size_t n,k; #ifdef HAVE_CXX11 @@ -71,17 +81,24 @@ namespace YaHTTP { while(ifs && ifs.good()) { ifs.read(buf, sizeof buf); n += (k = ifs.gcount()); - if (k) + if (k) { + if (chunked) os << std::hex << k << "\r\n"; os.write(buf, k); + if (chunked) os << "\r\n"; + } } - + if (chunked) os << 0 << "\r\n\r\n"; return n; }; //url = rhs.url; this->kind = rhs.kind; @@ -136,7 +163,7 @@ namespace YaHTTP { ssize_t max_response_size; // renderer; // renderer; //kind = YAHTTP_TYPE_RESPONSE; }; + Response() { initialize(); }; Response(const HTTPBase& rhs): HTTPBase(rhs) { this->kind = YAHTTP_TYPE_RESPONSE; }; @@ -163,6 +190,10 @@ namespace YaHTTP { this->kind = YAHTTP_TYPE_RESPONSE; return *this; }; + void initialize() { + HTTPBase::initialize(); + this->kind = YAHTTP_TYPE_RESPONSE; + } friend std::ostream& operator<<(std::ostream& os, const Response &resp); friend std::istream& operator>>(std::istream& is, Response &resp); }; @@ -170,7 +201,7 @@ namespace YaHTTP { /* Request class, represents a HTTP Request document */ class Request: public HTTPBase { public: - Request() { this->kind = YAHTTP_TYPE_REQUEST; }; + Request() { initialize(); }; Request(const HTTPBase& rhs): HTTPBase(rhs) { this->kind = YAHTTP_TYPE_REQUEST; }; @@ -179,7 +210,10 @@ namespace YaHTTP { this->kind = YAHTTP_TYPE_REQUEST; return *this; }; - + void initialize() { + HTTPBase::initialize(); + this->kind = YAHTTP_TYPE_REQUEST; + } void setup(const std::string& method, const std::string& url) { this->url.parse(url); this->headers["host"] = this->url.host; @@ -242,6 +276,8 @@ namespace YaHTTP { bodybuf.str(""); maxbody = 0; pos = 0; state = 0; this->target = target; hasBody = false; + buffer = ""; + this->target->initialize(); }; // strstr_map_t; //utc_offset = 0; @@ -331,9 +344,9 @@ namespace YaHTTP { } }; // parseUrlParameters(std::string parameters) { + static strstr_map_t parseUrlParameters(std::string parameters) { std::string::size_type pos = 0; - std::map parameter_map; + strstr_map_t parameter_map; while (pos != std::string::npos) { // find next parameter start std::string::size_type nextpos = parameters.find("&", pos); @@ -389,6 +402,13 @@ namespace YaHTTP { return iequals(a,b,a.size()); }; //