A RequestParser that builds a request from interrupted input from a Stream

feature/UrlUtils
Kenneth Barbour 2018-03-07 21:26:51 -05:00 committed by Kenneth Barbour
parent 2a6dd718f7
commit c92d39ddb1
3 changed files with 151 additions and 0 deletions

View File

@ -0,0 +1,81 @@
#include "RequestParser.h"
bool RequestParser::parse() {
while (client.available() && _state != S_ERROR) {
char in = client.read();
switch (_state) {
case S_IN_METHOD:
if (in == ' ') {
*(_i++) = '\0';
request.setMethod(_buffer);
_i = _buffer;
_state = S_IN_URL;
break;
}
*(_i++) = in;
break;
case S_IN_URL:
// skip preceding whitespace
if (in == ' ') {
if (_i == _buffer) continue;
*(_i) = '\0';
request.setUrl(_buffer);
_i = _buffer;
_state = S_IN_HTTPVER;
break;
}
*(_i++) = in;
break;
case S_IN_HTTPVER:
if (in == '\r') continue;
if (in == '\n') {
*(_i) = '\0';
request.setHttpVer(_buffer);
_i = _buffer;
_state = S_IN_HEADER;
break;
}
*(_i++) = in;
break;
case S_IN_HEADER:
if (in == '\r') continue;
if (in == '\n') {
if (_i == _buffer) {
if (request.headers.has("Content-Length"))
_state = S_IN_MESSAGE;
else _state = S_COMPLETE;
break;
}
char * name = _buffer;
char * value = _buffer;
bool s = 0;
while (value < _i) {
if (s) {
if (*value == ' ') value++;
else break;
} else {
if (*value == ':') {
s = true;
*(value++) = '\0';
} else value++;
}
}
request.headers.set(name, value);
_i = _buffer;
break;
}
*(_i++) = in;
break;
case S_COMPLETE:
return true;
default:
_state = S_ERROR;
}
}
return (_state == S_COMPLETE || _state == S_ERROR);
}

View File

@ -0,0 +1,38 @@
#pragma once
#include "HttpRequest.h"
#include "Arduino.h"
#ifndef REQUESTPARSER_BUFFER
#define REQUESTPARSER_BUFFER 512
#endif
enum RequestParserState {
S_IN_METHOD,
S_IN_URL,
S_IN_HTTPVER,
S_IN_HEADER,
S_IN_MESSAGE,
S_COMPLETE,
S_ERROR
};
class RequestParser
{
public:
RequestParser(HttpRequest& req, Stream& client):
request(req),
client(client),
_state(S_IN_METHOD)
{};
bool parse();
bool error() { return _state == S_ERROR; };
private:
char _buffer[REQUESTPARSER_BUFFER] = {};
char * _i = _buffer;
HttpRequest& request;
Stream& client;
RequestParserState _state;
};

View File

@ -0,0 +1,32 @@
#include "catch.hpp"
#include "Buffer.h"
#include "RequestParser.h"
using Catch::Matchers::Equals;
TEST_CASE("Test GET","[RequestParser]")
{
uint8_t _buff[256] = {};
Buffer client(_buff, 256);
HttpRequest request;
RequestParser parser(request, client);
client.write("GET ");
CHECK(parser.parse() == 0);
CHECK_THAT(request.getMethod(), Equals("GET"));
client.write("/foo ");
CHECK(parser.parse() == 0);
CHECK_THAT(request.getUrl(), Equals("/foo"));
client.write("HTTP/1.1\r\n");
CHECK(parser.parse() == 0);
CHECK_THAT(request.getHttpVer(), Equals("HTTP/1.1"));
client.write("Host: localhost\r\n");
CHECK(parser.parse() == 0);
CHECK_THAT(request.headers.get("Host"), Equals("localhost"));
client.write("\r\n");
CHECK(parser.parse());
CHECK(!parser.error());
}