aboutsummaryrefslogtreecommitdiffstats
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/http_connection.h2
-rw-r--r--include/http_request.h8
-rw-r--r--include/parser.h73
-rw-r--r--include/query_string.h305
-rw-r--r--include/routing.h7
5 files changed, 323 insertions, 72 deletions
diff --git a/include/http_connection.h b/include/http_connection.h
index 016c270..537be89 100644
--- a/include/http_connection.h
+++ b/include/http_connection.h
@@ -232,7 +232,7 @@ namespace crow
void complete_request()
{
- CROW_LOG_INFO << "Response: " << this << ' ' << req_.url << ' ' << res.code << ' ' << close_connection_;
+ CROW_LOG_INFO << "Response: " << this << ' ' << req_.raw_url << ' ' << res.code << ' ' << close_connection_;
if (need_to_call_after_handlers_)
{
diff --git a/include/http_request.h b/include/http_request.h
index 24edb66..1319b2d 100644
--- a/include/http_request.h
+++ b/include/http_request.h
@@ -2,6 +2,7 @@
#include "common.h"
#include "ci_map.h"
+#include "query_string.h"
namespace crow
{
@@ -19,8 +20,9 @@ namespace crow
struct request
{
HTTPMethod method;
+ std::string raw_url;
std::string url;
- ci_map url_params;
+ query_string url_params;
ci_map headers;
std::string body;
@@ -31,8 +33,8 @@ namespace crow
{
}
- request(HTTPMethod method, std::string url, ci_map url_params, ci_map headers, std::string body)
- : method(method), url(std::move(url)), url_params(std::move(url_params)), headers(std::move(headers)), body(std::move(body))
+ request(HTTPMethod method, std::string raw_url, std::string url, query_string url_params, ci_map headers, std::string body)
+ : method(method), raw_url(std::move(raw_url)), url(std::move(url)), url_params(std::move(url_params)), headers(std::move(headers)), body(std::move(body))
{
}
diff --git a/include/parser.h b/include/parser.h
index 00bb155..6ead8fd 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -13,62 +13,6 @@ namespace crow
template <typename Handler>
struct HTTPParser : public http_parser
{
- template<const char delimiter>
- struct tokenize_by_char
- {
- template<typename It>
- bool operator()(It& next, It end, std::string & tok)
- {
- if (next == end)
- return false;
- const char dels = delimiter;
- const char* del = &dels;
- auto pos = std::search(next, end, del, del + 1);
- tok.assign(next, pos);
- next = pos;
- if (next != end)
- std::advance(next, 1);
- return true;
- }
-
- void reset() {}
- };
-
- static ci_map get_url_params(std::string url)
- {
- const char url_delimiter = '&';
- const char param_delimiter = '=';
- ci_map ret;
-
- unsigned int qMarkPos = url.find("?");
- if(!(qMarkPos >=0 && qMarkPos != (url.length()-1))) {
- return ret;
- }
-
- auto params = url.substr(qMarkPos+1);
-
- // substitute ';' for '&' for recommended process of delimintation
- // (http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.2.2)
- std::replace(params.begin(), params.end(), ';', url_delimiter);
-
- // url tokenizer
- for (auto i : boost::tokenizer<tokenize_by_char<url_delimiter>>(params)) {
- std::string key, value;
- auto parts = boost::tokenizer<tokenize_by_char<param_delimiter>>(i);
- int count = 0;
- for(auto p = parts.begin(); p != parts.end(); ++p, ++count) {
- if(count == 0){
- key = *p;
- } else {
- value = *p;
- }
- }
- ret.insert(std::make_pair(key, value));
- }
-
- return ret;
- }
-
static int on_message_begin(http_parser* self_)
{
HTTPParser* self = static_cast<HTTPParser*>(self_);
@@ -78,11 +22,7 @@ namespace crow
static int on_url(http_parser* self_, const char* at, size_t length)
{
HTTPParser* self = static_cast<HTTPParser*>(self_);
- self->url.insert(self->url.end(), at, at+length);
-
- // url params
- self->url_params = get_url_params(self->url);
-
+ self->raw_url.insert(self->raw_url.end(), at, at+length);
return 0;
}
static int on_header_field(http_parser* self_, const char* at, size_t length)
@@ -138,6 +78,11 @@ namespace crow
static int on_message_complete(http_parser* self_)
{
HTTPParser* self = static_cast<HTTPParser*>(self_);
+
+ // url params
+ self->url = self->raw_url.substr(0, self->raw_url.find("?"));
+ self->url_params = query_string(self->raw_url);
+
self->process_message();
return 0;
}
@@ -173,6 +118,7 @@ namespace crow
void clear()
{
url.clear();
+ raw_url.clear();
header_building_state = 0;
header_field.clear();
header_value.clear();
@@ -193,7 +139,7 @@ namespace crow
request to_request() const
{
- return request{(HTTPMethod)method, std::move(url), std::move(url_params), std::move(headers), std::move(body)};
+ return request{(HTTPMethod)method, std::move(raw_url), std::move(url), std::move(url_params), std::move(headers), std::move(body)};
}
bool check_version(int major, int minor) const
@@ -201,13 +147,14 @@ namespace crow
return http_major == major && http_minor == minor;
}
+ std::string raw_url;
std::string url;
int header_building_state = 0;
std::string header_field;
std::string header_value;
ci_map headers;
- ci_map url_params;
+ query_string url_params;
std::string body;
Handler* handler_;
diff --git a/include/query_string.h b/include/query_string.h
new file mode 100644
index 0000000..5a42782
--- /dev/null
+++ b/include/query_string.h
@@ -0,0 +1,305 @@
+#pragma once
+
+#include <stdio.h>
+#include <string>
+
+using namespace std;
+
+// ----------------------------------------------------------------------------
+// qs_parse (modified)
+// https://github.com/bartgrantham/qs_parse
+// ----------------------------------------------------------------------------
+/* Similar to strncmp, but handles URL-encoding for either string */
+int qs_strncmp(const char * s, const char * qs, register size_t n);
+
+
+/* Finds the beginning of each key/value pair and stores a pointer in qs_kv.
+ * Also decodes the value portion of the k/v pair *in-place*. In a future
+ * enhancement it will also have a compile-time option of sorting qs_kv
+ * alphabetically by key. */
+int qs_parse(char * qs, char * qs_kv[], int qs_kv_size);
+
+
+/* Used by qs_parse to decode the value portion of a k/v pair */
+int qs_decode(char * qs);
+
+
+/* Looks up the value according to the key on a pre-processed query string
+ * A future enhancement will be a compile-time option to look up the key
+ * in a pre-sorted qs_kv array via a binary search. */
+//char * qs_k2v(const char * key, char * qs_kv[], int qs_kv_size);
+ char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth);
+
+
+/* Non-destructive lookup of value, based on key. User provides the
+ * destinaton string and length. */
+char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len);
+
+// TODO: implement sorting of the qs_kv array; for now ensure it's not compiled
+#undef _qsSORTING
+
+// isxdigit _is_ available in <ctype.h>, but let's avoid another header instead
+#define ISHEX(x) ((((x)>='0'&&(x)<='9') || ((x)>='A'&&(x)<='F') || ((x)>='a'&&(x)<='f')) ? 1 : 0)
+#define HEX2DEC(x) (((x)>='0'&&(x)<='9') ? (x)-48 : ((x)>='A'&&(x)<='F') ? (x)-55 : ((x)>='a'&&(x)<='f') ? (x)-87 : 0)
+#define ISQSCHR(x) ((((x)=='=')||((x)=='#')||((x)=='&')||((x)=='\0')) ? 0 : 1)
+
+int qs_strncmp(const char * s, const char * qs, register size_t n)
+{
+ int i=0;
+ register unsigned char u1, u2, unyb, lnyb;
+
+ while(n-- > 0)
+ {
+ u1 = (unsigned char) *s++;
+ u2 = (unsigned char) *qs++;
+
+ if ( ! ISQSCHR(u1) ) { u1 = '\0'; }
+ if ( ! ISQSCHR(u2) ) { u2 = '\0'; }
+
+ if ( u1 == '+' ) { u1 = ' '; }
+ if ( u1 == '%' ) // easier/safer than scanf
+ {
+ unyb = (unsigned char) *s++;
+ lnyb = (unsigned char) *s++;
+ if ( ISHEX(unyb) && ISHEX(lnyb) )
+ u1 = (HEX2DEC(unyb) * 16) + HEX2DEC(lnyb);
+ else
+ u1 = '\0';
+ }
+
+ if ( u2 == '+' ) { u2 = ' '; }
+ if ( u2 == '%' ) // easier/safer than scanf
+ {
+ unyb = (unsigned char) *qs++;
+ lnyb = (unsigned char) *qs++;
+ if ( ISHEX(unyb) && ISHEX(lnyb) )
+ u2 = (HEX2DEC(unyb) * 16) + HEX2DEC(lnyb);
+ else
+ u2 = '\0';
+ }
+
+ if ( u1 != u2 )
+ return u1 - u2;
+ if ( u1 == '\0' )
+ return 0;
+ i++;
+ }
+ if ( ISQSCHR(*qs) )
+ return -1;
+ else
+ return 0;
+}
+
+
+int qs_parse(char * qs, char * qs_kv[], int qs_kv_size)
+{
+ int i, j;
+ char * substr_ptr;
+
+ for(i=0; i<qs_kv_size; i++) qs_kv[i] = NULL;
+
+ // find the beginning of the k/v substrings
+ if ( (substr_ptr = strchr(qs, '?')) != NULL )
+ substr_ptr++;
+ else
+ substr_ptr = qs;
+
+ i=0;
+ while(i<qs_kv_size)
+ {
+ qs_kv[i] = substr_ptr;
+ j = strcspn(substr_ptr, "&");
+ if ( substr_ptr[j] == '\0' ) { break; }
+ substr_ptr += j + 1;
+ i++;
+ }
+ i++; // x &'s -> means x iterations of this loop -> means *x+1* k/v pairs
+
+ // we only decode the values in place, the keys could have '='s in them
+ // which will hose our ability to distinguish keys from values later
+ for(j=0; j<i; j++)
+ {
+ substr_ptr = qs_kv[j] + strcspn(qs_kv[j], "=&#");
+ if ( substr_ptr[0] == '&' ) // blank value: skip decoding
+ substr_ptr[0] = '\0';
+ else
+ qs_decode(++substr_ptr);
+ }
+
+#ifdef _qsSORTING
+// TODO: qsort qs_kv, using qs_strncmp() for the comparison
+#endif
+
+ return i;
+}
+
+
+int qs_decode(char * qs)
+{
+ int i=0, j=0;
+
+ while( ISQSCHR(qs[j]) )
+ {
+ if ( qs[j] == '+' ) { qs[i] = ' '; }
+ else if ( qs[j] == '%' ) // easier/safer than scanf
+ {
+ if ( ! ISHEX(qs[j+1]) || ! ISHEX(qs[j+2]) )
+ {
+ qs[i] = '\0';
+ return i;
+ }
+ qs[i] = (HEX2DEC(qs[j+1]) * 16) + HEX2DEC(qs[j+2]);
+ j+=2;
+ }
+ else
+ {
+ qs[i] = qs[j];
+ }
+ i++; j++;
+ }
+ qs[i] = '\0';
+
+ return i;
+}
+
+
+char * qs_k2v(const char * key, char * const * qs_kv, int qs_kv_size, int nth = 0)
+{
+ int i;
+ size_t key_len, skip;
+
+ key_len = strlen(key);
+
+#ifdef _qsSORTING
+// TODO: binary search for key in the sorted qs_kv
+#else // _qsSORTING
+ for(i=0; i<qs_kv_size; i++)
+ {
+ // we rely on the unambiguous '=' to find the value in our k/v pair
+ if ( qs_strncmp(key, qs_kv[i], key_len) == 0 )
+ {
+ skip = strcspn(qs_kv[i], "=");
+ if ( qs_kv[i][skip] == '=' )
+ skip++;
+ // return (zero-char value) ? ptr to trailing '\0' : ptr to value
+ if(nth == 0)
+ return qs_kv[i] + skip;
+ else
+ --nth;
+ }
+ }
+#endif // _qsSORTING
+
+ return NULL;
+}
+
+
+char * qs_scanvalue(const char * key, const char * qs, char * val, size_t val_len)
+{
+ size_t i, key_len;
+ const char * tmp;
+
+ // find the beginning of the k/v substrings
+ if ( (tmp = strchr(qs, '?')) != NULL )
+ qs = tmp + 1;
+
+ key_len = strlen(key);
+ while(qs[0] != '#' && qs[0] != '\0')
+ {
+ if ( qs_strncmp(key, qs, key_len) == 0 )
+ break;
+ qs += strcspn(qs, "&") + 1;
+ }
+
+ if ( qs[0] == '\0' ) return NULL;
+
+ qs += strcspn(qs, "=&#");
+ if ( qs[0] == '=' )
+ {
+ qs++;
+ i = strcspn(qs, "&=#");
+ strncpy(val, qs, (val_len-1)<(i+1) ? (val_len-1) : (i+1));
+ qs_decode(val);
+ }
+ else
+ {
+ if ( val_len > 0 )
+ val[0] = '\0';
+ }
+
+ return val;
+}
+// ----------------------------------------------------------------------------
+
+// TODO to save allocs, capping url size to 2048 seems sane and reasonable but
+// crow should *technically* return a 413 if a URL is longer than this.
+#define MAX_URL_SIZE (2048)
+
+#define NUM_KV_PAIRS (256)
+#define VAL_SIZE (256)
+
+namespace crow
+{
+ class query_string
+ {
+ public:
+ query_string()
+ {
+
+ }
+ query_string(std::string url)
+ {
+ if(url.length() <= MAX_URL_SIZE) {
+ memset(_url, 0, MAX_URL_SIZE); // overkill?
+ memcpy(_url, url.c_str(), url.length());
+ }
+ _kv_size = qs_parse(_url, _kv_pairs, NUM_KV_PAIRS);
+ }
+ void clear() {
+ _url[0] = 0;
+ }
+
+ friend ostream& operator<<(ostream& os, const query_string& qs)
+ {
+ os << "[ ";
+ for(int i = 0; i < qs._kv_size; ++i) {
+ os << qs._kv_pairs[i];
+ if((i + 1) < qs._kv_size) {
+ os << ", ";
+ }
+ }
+ os << " ]";
+ return os;
+
+ }
+
+ char* get (const string name) const
+ {
+ char* ret = qs_k2v(name.c_str(), _kv_pairs, _kv_size);
+ return ret != 0 ? ret : nullptr;
+ }
+
+ vector<char*> get_list (const string name) const
+ {
+ vector<char*> ret;
+ string plus = name + "[]";
+ char* tmp = nullptr;
+ int count = 0;
+ do
+ {
+ tmp = qs_k2v(plus.c_str(), _kv_pairs, _kv_size, count++);
+ if(tmp != nullptr) {
+ ret.push_back(tmp);
+ }
+ } while(tmp != nullptr);
+ return move(ret);
+ }
+
+
+ private:
+ char _url[MAX_URL_SIZE];
+ char* _kv_pairs[NUM_KV_PAIRS];
+ int _kv_size;
+ };
+
+} // end namespace \ No newline at end of file
diff --git a/include/routing.h b/include/routing.h
index d814266..ca88192 100644
--- a/include/routing.h
+++ b/include/routing.h
@@ -623,16 +623,13 @@ public:
void handle(const request& req, response& res)
{
- // remove url params
- auto editedUrl = req.url.substr(0, req.url.find("?"));
-
- auto found = trie_.find(editedUrl);
+ auto found = trie_.find(req.url);
unsigned rule_index = found.first;
if (!rule_index)
{
- CROW_LOG_DEBUG << "Cannot match rules " << editedUrl;
+ CROW_LOG_DEBUG << "Cannot match rules " << req.url;
res = response(404);
res.end();
return;