Commit 87d92741 authored by Mathieu STEFANI's avatar Mathieu STEFANI

Some general improvement on parsing

parent 1534f524
...@@ -21,12 +21,9 @@ namespace Net { ...@@ -21,12 +21,9 @@ namespace Net {
namespace Http { namespace Http {
static constexpr char CR = 0xD;
static constexpr char LF = 0xA;
static constexpr char CRLF[] = {CR, LF};
template< class CharT, class Traits> template< class CharT, class Traits>
std::basic_ostream<CharT, Traits>& crlf(std::basic_ostream<CharT, Traits>& os) { std::basic_ostream<CharT, Traits>& crlf(std::basic_ostream<CharT, Traits>& os) {
static constexpr char CRLF[] = {0xD, 0xA};
os.write(CRLF, 2); os.write(CRLF, 2);
} }
...@@ -43,44 +40,42 @@ namespace Private { ...@@ -43,44 +40,42 @@ namespace Private {
Parser::RequestLineStep::apply(StreamCursor& cursor) { Parser::RequestLineStep::apply(StreamCursor& cursor) {
StreamCursor::Revert revert(cursor); StreamCursor::Revert revert(cursor);
auto tryMatch = [&](const char* const str) { // Method
const size_t len = std::strlen(str); //
if (strncmp(cursor.offset(), str, len) == 0) { struct MethodValue {
cursor.advance(len - 1); const char* const str;
return true; const size_t len;
}
return false; Method repr;
}; };
// Method static constexpr MethodValue Methods[] = {
#define METHOD(repr, str) \
{ str, sizeof(str) - 1, Method::repr },
HTTP_METHODS
#undef METHOD
};
if (tryMatch("OPTIONS")) { bool found = false;
request->method = Method::Options; for (const auto& method: Methods) {
} if (match_raw(method.str, method.len, cursor)) {
else if (tryMatch("GET")) { request->method = method.repr;
request->method = Method::Get; found = true;
} break;
else if (tryMatch("POST")) { }
request->method = Method::Post;
}
else if (tryMatch("HEAD")) {
request->method = Method::Head;
}
else if (tryMatch("PUT")) {
request->method = Method::Put;
}
else if (tryMatch("DELETE")) {
request->method = Method::Delete;
} }
else {
if (!found) {
raise("Unknown HTTP request method"); raise("Unknown HTTP request method");
} }
auto n = cursor.next(); int n;
if (n == StreamCursor::Eof) return State::Again;
else if (n != ' ') raise("Malformed HTTP request after Method, expected SP");
if (!cursor.advance(2)) return State::Again; if (cursor.eof()) return State::Again;
else if ((n = cursor.current()) != ' ')
raise("Malformed HTTP request after Method, expected SP");
if (!cursor.advance(1)) return State::Again;
size_t start = cursor; size_t start = cursor;
...@@ -193,7 +188,7 @@ namespace Private { ...@@ -193,7 +188,7 @@ namespace Private {
return State::Again; return State::Again;
} }
else { else {
request->body.append(cursor.offset(), cursor.diff(start)); request->body.append(cursor.offset(), remaining);
} }
} }
...@@ -216,7 +211,7 @@ namespace Private { ...@@ -216,7 +211,7 @@ namespace Private {
return State::Again; return State::Again;
} }
request->body.append(cursor.offset(start), cursor.diff(start)); request->body.append(cursor.offset(start), contentLength);
} }
bytesRead = 0; bytesRead = 0;
...@@ -311,7 +306,11 @@ void ...@@ -311,7 +306,11 @@ void
Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) { Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) {
try { try {
auto& parser = getParser(peer); auto& parser = getParser(peer);
// scope (failure), {
// parser.reset();
// };
if (!parser.feed(buffer, len)) { if (!parser.feed(buffer, len)) {
parser.reset();
throw HttpError(Code::Request_Entity_Too_Large, "Request exceeded maximum buffer size"); throw HttpError(Code::Request_Entity_Too_Large, "Request exceeded maximum buffer size");
} }
...@@ -323,10 +322,12 @@ Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) { ...@@ -323,10 +322,12 @@ Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) {
} catch (const HttpError &err) { } catch (const HttpError &err) {
Response response(err.code(), err.reason()); Response response(err.code(), err.reason());
response.writeTo(peer); response.writeTo(peer);
getParser(peer).reset();
} }
catch (const std::exception& e) { catch (const std::exception& e) {
Response response(Code::Internal_Server_Error, e.what()); Response response(Code::Internal_Server_Error, e.what());
response.writeTo(peer); response.writeTo(peer);
getParser(peer).reset();
} }
} }
......
...@@ -131,9 +131,8 @@ CacheControl::parseRaw(const char* str, size_t len) { ...@@ -131,9 +131,8 @@ CacheControl::parseRaw(const char* str, size_t len) {
bool found = false; bool found = false;
// First scan trivial directives // First scan trivial directives
for (const auto& d: TrivialDirectives) { for (const auto& d: TrivialDirectives) {
if (memcmp(cursor.offset(), d.str, memsize(d.size)) == 0) { if (match_raw(d.str, d.size, cursor)) {
directives_.push_back(CacheDirective(d.repr)); directives_.push_back(CacheDirective(d.repr));
cursor.advance(d.size);
found = true; found = true;
break; break;
} }
...@@ -142,12 +141,9 @@ CacheControl::parseRaw(const char* str, size_t len) { ...@@ -142,12 +141,9 @@ CacheControl::parseRaw(const char* str, size_t len) {
// Not found, let's try timed directives // Not found, let's try timed directives
if (!found) { if (!found) {
for (const auto& d: TimedDirectives) { for (const auto& d: TimedDirectives) {
if (memcmp(cursor.offset(), d.str, memsize(d.size)) == 0) { if (match_raw(d.str, d.size, cursor)) {
int c; int c;
while (!cursor.eof() && cursor.current() != '=') if (!cursor.advance(1)) {
cursor.advance(1);
if (cursor.eof() || !cursor.advance(1)) {
throw std::runtime_error("Invalid caching directive, missing delta-seconds"); throw std::runtime_error("Invalid caching directive, missing delta-seconds");
} }
......
...@@ -91,3 +91,16 @@ void ...@@ -91,3 +91,16 @@ void
StreamCursor::reset() { StreamCursor::reset() {
value = 0; value = 0;
} }
bool
match_raw(const void* buf, size_t len, StreamCursor& cursor) {
if (cursor.remaining() < len)
return false;
if (memcmp(cursor.offset(), buf, len) == 0) {
cursor.advance(len);
return true;
}
return false;
}
...@@ -69,6 +69,7 @@ public: ...@@ -69,6 +69,7 @@ public:
void reset() { void reset() {
memset(bytes, 0, N); memset(bytes, 0, N);
size = 0;
setArea(bytes, bytes, bytes); setArea(bytes, bytes, bytes);
} }
...@@ -134,3 +135,5 @@ private: ...@@ -134,3 +135,5 @@ private:
const BasicStreamBuf& buf; const BasicStreamBuf& buf;
size_t value; size_t value;
}; };
bool match_raw(const void* buf, size_t len, StreamCursor& cursor);
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment