]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Sync with upstream
authorAki Tuomi <cmouse@desteem.org>
Tue, 23 Dec 2014 09:07:26 +0000 (11:07 +0200)
committerAki Tuomi <cmouse@desteem.org>
Tue, 23 Dec 2014 14:43:24 +0000 (16:43 +0200)
pdns/ext/yahttp/yahttp/cookie.hpp
pdns/ext/yahttp/yahttp/reqresp.cpp
pdns/ext/yahttp/yahttp/reqresp.hpp
pdns/ext/yahttp/yahttp/router.cpp
pdns/ext/yahttp/yahttp/utility.hpp

index 4b285aa760c4459fe2edbebe5d50d0ef28f274c8..b99b21e0104136644c643ccf9fb4c5b9640e3e92 100644 (file)
@@ -46,13 +46,17 @@ namespace YaHTTP {
   /*! Implements a Cookie jar for storing multiple cookies */
   class CookieJar {
     public:
-    std::map<std::string, Cookie> cookies;  //<! cookie container
+    std::map<std::string, Cookie, ASCIICINullSafeComparator> cookies;  //<! cookie container
   
     CookieJar() {}; //<! constructs empty cookie jar
     CookieJar(const CookieJar & rhs) {
       this->cookies = rhs.cookies;
     } //<! copy cookies from another cookie jar
   
+    void clear() {
+      this->cookies.clear();
+    }
+
     void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value) {
       size_t pos;
       pos = keyvalue.find("=");
index 14196b998dcf30e710590a42e3887e272e105304..2d28c0adc303d63136c56016f58488707051a42e 100644 (file)
@@ -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
       }
index 29718806b76a46d3e08e78ab3253d8d7eb749fb2..17ee9f52ebc9628a793c3669d67d284a0c316c88 100644 (file)
@@ -18,6 +18,8 @@ namespace funcptr = boost;
 #include <unistd.h>
 #endif
 
+#include <algorithm>
+
 #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<std::string,std::string> strstr_map_t; //<! String to String map 
-  typedef std::map<std::string,Cookie> strcookie_map_t; //<! String to Cookie map
+  typedef std::map<std::string,Cookie,ASCIICINullSafeComparator> strcookie_map_t; //<! String to Cookie map
 
   typedef enum {
     urlencoded,
@@ -41,14 +42,23 @@ namespace YaHTTP {
   /*! Base class for request and response */
   class HTTPBase {
   public:
-#ifdef HAVE_CPP_FUNC_PTR
     /*! Default renderer for request/response, simply copies body to response */
     class SendBodyRender {
     public:
       SendBodyRender() {};
 
-      size_t operator()(const HTTPBase *doc, std::ostream& os) const {
-        os << doc->body;
+      size_t operator()(const HTTPBase *doc, std::ostream& os, bool chunked) const {
+        if (chunked) {
+          std::string::size_type i,cl;
+          for(i=0;i<doc->body.length();i+=1024) {
+            cl = std::min(static_cast<std::string::size_type>(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();
       }; //<! writes body to ostream and returns length 
     };
@@ -59,7 +69,7 @@ namespace YaHTTP {
         this->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;
       }; //<! writes file to ostream and returns length
 
       std::string path; //<! File to send
     };
-#endif
+
     HTTPBase() {
+      initialize();
+    };
+
+    virtual void initialize() {
       kind = 0;
       status = 0;
 #ifdef HAVE_CPP_FUNC_PTR
@@ -89,7 +106,17 @@ namespace YaHTTP {
 #endif
       max_request_size = YAHTTP_MAX_REQUEST_SIZE;
       max_response_size = YAHTTP_MAX_RESPONSE_SIZE;
-    };
+      url = "";
+      method = "";
+      statusText = "";
+      jar.clear();
+      headers.clear();
+      parameters.clear();
+      getvars.clear();
+      postvars.clear();
+      body = "";
+      routeName = "";
+    }
 protected:
     HTTPBase(const HTTPBase& rhs) {
       this->url = rhs.url; this->kind = rhs.kind;
@@ -136,7 +163,7 @@ public:
     ssize_t max_response_size;  //<! maximum size of response
  
 #ifdef HAVE_CPP_FUNC_PTR
-    funcptr::function<size_t(const HTTPBase*,std::ostream&)> renderer; //<! rendering function
+    funcptr::function<size_t(const HTTPBase*,std::ostream&,bool)> renderer; //<! rendering function
 #endif
     void write(std::ostream& os) const; //<! writes request to the given output stream
 
@@ -154,7 +181,7 @@ public:
   /*! Response class, represents a HTTP Response document */
   class Response: public HTTPBase { 
   public:
-    Response() { this->kind = YAHTTP_TYPE_RESPONSE; };
+    Response() { initialize(); };
     Response(const HTTPBase& rhs): HTTPBase(rhs) {
       this->kind = YAHTTP_TYPE_RESPONSE;
     };
@@ -163,6 +190,10 @@ public:
       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 @@ public:
   /* 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 @@ public:
       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 @@ public:
       bodybuf.str(""); maxbody = 0;
       pos = 0; state = 0; this->target = target; 
       hasBody = false;
+      buffer = "";
+      this->target->initialize();
     }; //<! Initialize the parser for target and clear state
     int feed(const std::string& somedata); //<! Feed data to the parser
     bool ready() {
index 26cd774f5170a34c8a6c581762578ff694a3ac8d..3678000eaea84edd1f103b52c840d18f1f2fcb04 100644 (file)
@@ -155,7 +155,6 @@ namespace YaHTTP {
         continue;
       }
     }
-    std::cout << mask.substr(k3) << std::endl;
     path << mask.substr(k3);
     result = path.str();
     return std::make_pair(method, result);
index c6be7c6333c638e420b0c01088d4323dad80b816..03fc4833b5d5ec665fc88b4dd2b2930d71ea83a9 100644 (file)
@@ -5,6 +5,20 @@ namespace YaHTTP {
   static const char *MONTHS[] = {0,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",0}; //<! List of months 
   static const char *DAYS[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat",0}; //<! List of days
 
+  /*! Case-Insensitive NULL safe comparator for string maps */
+  struct ASCIICINullSafeComparator {
+    bool operator() (const std::string& lhs, const std::string& rhs) const {
+      char v;
+      std::string::const_iterator lhi = lhs.begin();
+      std::string::const_iterator rhi = rhs.begin();
+      for(;lhi != lhs.end() && rhi != rhs.end(); lhi++, rhi++)
+        if ((v = ::tolower(*lhi) - ::tolower(*rhi)) != 0) return v<0;
+      return (::tolower(*lhi) - ::tolower(*rhi))<0;
+    }
+  };
+
+  typedef std::map<std::string,std::string,ASCIICINullSafeComparator> strstr_map_t; //<! String to String map
+
   /*! Represents a date/time with utc offset */
   class DateTime {
   public:
@@ -158,7 +172,6 @@ namespace YaHTTP {
        const char *ptr;
        if ( (ptr = strptime(cookie_date.c_str(), "%d-%b-%Y %T", &tm)) != NULL) {
           while(*ptr && ( ::isspace(*ptr) || ::isalnum(*ptr) )) ptr++;
-          std::cerr << ptr << std::endl;
           if (*ptr) throw "Unparseable date (non-final)"; // must be final.
           fromTm(&tm);
           this->utc_offset = 0;
@@ -331,9 +344,9 @@ namespace YaHTTP {
        }
     }; //<! static HTTP codes to text mappings
 
-    static std::map<std::string,std::string> parseUrlParameters(std::string parameters) {
+    static strstr_map_t parseUrlParameters(std::string parameters) {
       std::string::size_type pos = 0;
-      std::map<std::string,std::string> 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());
     }; //<! case-insensitive comparison
 
+    static void trimLeft(std::string &str) {
+       const std::locale &loc = std::locale::classic();
+       std::string::iterator iter = str.begin();
+       while(iter != str.end() && std::isspace(*iter, loc)) iter++;
+       str.erase(str.begin(), iter);
+    }; //<! removes whitespace from left
+
     static void trimRight(std::string &str) {
        const std::locale &loc = std::locale::classic();
        std::string::reverse_iterator iter = str.rbegin();
@@ -396,6 +416,11 @@ namespace YaHTTP {
        str.erase(iter.base(), str.end());
     }; //<! removes whitespace from right
 
+    static void trim(std::string &str) {
+       trimLeft(str);
+       trimRight(str);
+    }; //<! removes whitespace from left and right
+
     static std::string camelizeHeader(const std::string &str) {
        std::string::const_iterator iter = str.begin();
        std::string result;