Skip to content

Commit

Permalink
Sync with upstream
Browse files Browse the repository at this point in the history
  • Loading branch information
cmouse committed Dec 23, 2014
1 parent dcf0e97 commit c290975
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 27 deletions.
6 changes: 5 additions & 1 deletion pdns/ext/yahttp/yahttp/cookie.hpp
Expand Up @@ -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("=");
Expand Down
48 changes: 40 additions & 8 deletions pdns/ext/yahttp/yahttp/reqresp.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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: ";
Expand All @@ -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
};

Expand All @@ -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
}
Expand Down
64 changes: 50 additions & 14 deletions pdns/ext/yahttp/yahttp/reqresp.hpp
Expand Up @@ -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
Expand All @@ -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,
Expand All @@ -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
};
Expand All @@ -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
Expand All @@ -71,25 +81,42 @@ 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
renderer = SendBodyRender();
#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;
Expand Down Expand Up @@ -136,7 +163,7 @@ namespace YaHTTP {
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

Expand All @@ -154,7 +181,7 @@ namespace YaHTTP {
/*! 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;
};
Expand All @@ -163,14 +190,18 @@ 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);
};

/* 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;
};
Expand All @@ -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;
Expand Down Expand Up @@ -242,6 +276,8 @@ namespace YaHTTP {
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() {
Expand Down
1 change: 0 additions & 1 deletion pdns/ext/yahttp/yahttp/router.cpp
Expand Up @@ -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);
Expand Down
31 changes: 28 additions & 3 deletions pdns/ext/yahttp/yahttp/utility.hpp
Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -389,13 +402,25 @@ 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();
while(iter != str.rend() && std::isspace(*iter, loc)) iter++;
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;
Expand Down

0 comments on commit c290975

Please sign in to comment.