Commit 0329db6a authored by Mathieu STEFANI's avatar Mathieu STEFANI

Body is now correctly parsed. Not fully tested but let's pretend it works

parent 40a6cba8
...@@ -21,6 +21,13 @@ class MyHandler : public Net::Http::Handler { ...@@ -21,6 +21,13 @@ class MyHandler : public Net::Http::Handler {
} }
} }
else if (req.resource == "/echo") {
if (req.method == Net::Http::Method::Post) {
Net::Http::Response response(Net::Http::Code::Ok, req.body);
response.writeTo(peer);
}
}
} }
}; };
......
...@@ -30,13 +30,20 @@ namespace Private { ...@@ -30,13 +30,20 @@ namespace Private {
memset(data, sizeof data, 0); memset(data, sizeof data, 0);
} }
void
Parser::Buffer::reset() {
memset(data, sizeof data, 0);
len = 0;
}
bool bool
Parser::Cursor::advance(size_t count) Parser::Cursor::advance(size_t count)
{ {
if (value + count >= sizeof (buff.data)) { if (value + count >= sizeof (buff.data)) {
//parser->raise("Early EOF"); //parser->raise("Early EOF");
} }
else if (value + count >= buff.len) { // Allowed to advance one past the end
else if (value + count > buff.len) {
return false; return false;
} }
...@@ -78,8 +85,24 @@ namespace Private { ...@@ -78,8 +85,24 @@ namespace Private {
} }
size_t size_t
Parser::Cursor::diff(size_t previous) const { Parser::Cursor::diff(size_t other) const {
return value - previous; return value - other;
}
size_t
Parser::Cursor::diff(const Cursor& other) const {
return value - other.value;
}
size_t
Parser::Cursor::remaining() const {
// assert(val <= buff.len);
return buff.len - value;
}
void
Parser::Cursor::reset() {
value = 0;
} }
void void
...@@ -215,19 +238,54 @@ namespace Private { ...@@ -215,19 +238,54 @@ namespace Private {
Parser::State Parser::State
Parser::BodyStep::apply(Cursor& cursor) { Parser::BodyStep::apply(Cursor& cursor) {
auto cl = request->headers.tryGet<ContentLength>(); auto cl = request->headers.tryGet<ContentLength>();
if (!cl) return Parser::State::Done;
if (cl) { auto contentLength = cl->value();
// CRLF // We already started to read some bytes but we got an incomplete payload
if (bytesRead > 0) {
// How many bytes do we still need to read ?
const size_t remaining = contentLength - bytesRead;
auto start = cursor;
// Could be refactored in a single function / lambda but I'm too lazy
// for that right now
if (!cursor.advance(remaining)) {
const size_t available = cursor.remaining();
request->body.append(cursor.offset(start), available);
bytesRead += available;
cursor.advance(available);
return State::Again;
}
else {
request->body.append(cursor.offset(), cursor.diff(start));
}
}
// This is the first time we are reading the payload
else {
if (!cursor.advance(2)) return State::Again; if (!cursor.advance(2)) return State::Again;
auto len = cl->value(); request->body.reserve(contentLength);
auto start = cursor; auto start = cursor;
if (!cursor.advance(len)) return State::Again; // We have an incomplete body, read what we can
if (!cursor.advance(contentLength)) {
const size_t available = cursor.remaining();
request->body.append(cursor.offset(start), available);
bytesRead += available;
cursor.advance(available);
return State::Again;
}
request->body = std::string(cursor.offset(start), cursor.diff(start)); request->body.append(cursor.offset(start), cursor.diff(start));
} }
bytesRead = 0;
return Parser::State::Done; return Parser::State::Done;
} }
...@@ -254,6 +312,19 @@ namespace Private { ...@@ -254,6 +312,19 @@ namespace Private {
memcpy(buffer.data + buffer.len, data, len); memcpy(buffer.data + buffer.len, data, len);
buffer.len += len; buffer.len += len;
return true;
}
void
Parser::reset() {
buffer.reset();
cursor.reset();
currentStep = 0;
request.headers.clear();
request.body.clear();
request.resource.clear();
} }
ssize_t ssize_t
...@@ -366,15 +437,20 @@ Response::writeTo(Tcp::Peer& peer) ...@@ -366,15 +437,20 @@ Response::writeTo(Tcp::Peer& peer)
void void
Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) { Handler::onInput(const char* buffer, size_t len, Tcp::Peer& peer) {
Private::Parser parser(buffer, len); if (!parser.feed(buffer, len)) {
cout << "Could not feed parser bro" << endl;
}
else {
try { try {
Private::Parser::State state = parser.parse(); auto state = parser.parse();
if (state == Private::Parser::State::Done) { if (state == Private::Parser::State::Done) {
onRequest(parser.request, peer); onRequest(parser.request, peer);
parser.reset();
} }
} catch (const Private::ParsingError &err) { } catch (const Private::ParsingError &err) {
cerr << "Error when parsing HTTP request: " << err.what() << endl; cerr << "Error when parsing HTTP request: " << err.what() << endl;
} }
}
} }
void void
......
...@@ -135,6 +135,8 @@ namespace Private { ...@@ -135,6 +135,8 @@ namespace Private {
char data[Const::MaxBuffer]; char data[Const::MaxBuffer];
size_t len; size_t len;
void reset();
}; };
struct Cursor { struct Cursor {
...@@ -182,8 +184,13 @@ namespace Private { ...@@ -182,8 +184,13 @@ namespace Private {
const char *offset() const; const char *offset() const;
const char *offset(size_t off) const; const char *offset(size_t off) const;
size_t diff(size_t before) const; size_t diff(size_t other) const;
size_t diff(const Cursor& other) const;
size_t remaining() const;
void reset();
private:
const Buffer& buff; const Buffer& buff;
size_t value; size_t value;
}; };
...@@ -221,11 +228,25 @@ namespace Private { ...@@ -221,11 +228,25 @@ namespace Private {
struct BodyStep : public Step { struct BodyStep : public Step {
BodyStep(Request* request) BodyStep(Request* request)
: Step(request) : Step(request)
, bytesRead(0)
{ } { }
State apply(Cursor& cursor); State apply(Cursor& cursor);
private:
size_t bytesRead;
}; };
Parser()
: contentLength(-1)
, currentStep(0)
, cursor(buffer)
{
allSteps[0].reset(new RequestLineStep(&request));
allSteps[1].reset(new HeadersStep(&request));
allSteps[2].reset(new BodyStep(&request));
}
Parser(const char* data, size_t len) Parser(const char* data, size_t len)
: contentLength(-1) : contentLength(-1)
, currentStep(0) , currentStep(0)
...@@ -239,6 +260,7 @@ namespace Private { ...@@ -239,6 +260,7 @@ namespace Private {
} }
bool feed(const char* data, size_t len); bool feed(const char* data, size_t len);
void reset();
State parse(); State parse();
...@@ -305,6 +327,9 @@ public: ...@@ -305,6 +327,9 @@ public:
void onOutput(); void onOutput();
virtual void onRequest(const Request& request, Tcp::Peer& peer) = 0; virtual void onRequest(const Request& request, Tcp::Peer& peer) = 0;
private:
Private::Parser parser;
}; };
class Endpoint { class Endpoint {
......
...@@ -116,6 +116,11 @@ Headers::list() const { ...@@ -116,6 +116,11 @@ Headers::list() const {
return ret; return ret;
} }
void
Headers::clear() {
headers.clear();
}
std::pair<bool, std::shared_ptr<Header>> std::pair<bool, std::shared_ptr<Header>>
Headers::getImpl(const std::string& name) const { Headers::getImpl(const std::string& name) const {
auto it = headers.find(name); auto it = headers.find(name);
......
...@@ -67,6 +67,8 @@ public: ...@@ -67,6 +67,8 @@ public:
std::vector<std::shared_ptr<Header>> list() const; std::vector<std::shared_ptr<Header>> list() const;
void clear();
private: private:
std::pair<bool, std::shared_ptr<Header>> getImpl(const std::string& name) const; std::pair<bool, std::shared_ptr<Header>> getImpl(const std::string& name) const;
......
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