Skip to content

Commit

Permalink
Merge pull request Working-From-Home#49 from ggjulio/master
Browse files Browse the repository at this point in the history
parser Http
  • Loading branch information
ggjulio authored Aug 25, 2021
2 parents 948c237 + fe7b3c9 commit 77f6f3b
Show file tree
Hide file tree
Showing 10 changed files with 251 additions and 56 deletions.
7 changes: 5 additions & 2 deletions includes/http/HttpRequest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,16 +49,19 @@ class HttpRequest: public AHttpMessage
int getHttpErrorCode();

private:

/// return false if following token is kEndOfInput.
/// meaning the token may be incomplete
bool _getCompleteToken(parser::http::Token& placeHolder, bool skipLWS = false);

/* --- Member variables ------------------------------------------------- */

std::string _method, _version;
Uri _uri;
HttpStatus _code;

bool _isRequestLineParsed;
bool _isHeaderParsed;
bool _isContentParsed;
bool _isComplete;

parser::http::ScannerHttpRequest _scanner;
};
Expand Down
4 changes: 4 additions & 0 deletions includes/parser/ScannerBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
#define SCANNER_BUFFER_HPP

#include <deque>
#include <string>


namespace parser {

Expand All @@ -32,6 +34,8 @@ class ScannerBuffer
// spaghetti fix
void pushNewBuffer(const char *buffer);

std::string toString();

private:

char _c;
Expand Down
7 changes: 5 additions & 2 deletions includes/parser/http/ScannerHttpRequest.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,17 +47,20 @@ class ScannerHttpRequest

Token getToken(bool skipLWS = false);
char getChar();
inline Token peekToken() { return _actualToken; };
Token peekNextToken(bool skipLWS = false);

// spaghetti fix
void pushNewBuffer(const char *buffer);
void putback(Token token);
void putback(std::string str);

private:

bool _charIsString(char c);
Token _makeToken(TokenKind kind, std::string value);

ScannerBuffer _scan;
Token _actualToken;
Token _nextToken;
}; /* class ScannerHttpRequest */

const char* TokenKindToCstring(TokenKind type);
Expand Down
140 changes: 97 additions & 43 deletions src/http/HttpRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
#include "parser/http/ScannerHttpRequest.hpp"

HttpRequest::HttpRequest()
: AHttpMessage(), _code(HttpStatus::None), _isHeaderParsed(false),
_isContentParsed(false), _scanner(NULL)
: AHttpMessage(), _code(HttpStatus::None), _isRequestLineParsed(false),
_isHeaderParsed(false), _isComplete(false), _scanner(NULL)
{}

HttpRequest::~HttpRequest() {}
Expand Down Expand Up @@ -67,71 +67,113 @@ namespace ph = parser::http;

void HttpRequest::read(const char *buffer)
{
ph::Token t;

// if (isComplete())
// throw std::logic_error("Wtf ima complete request already");
_scanner.pushNewBuffer(buffer);

ph::Token t = _scanner.getToken(true);
if (!t.value.compare("GET") || !t.value.compare("POST")
|| !t.value.compare("DELETE"))
// if (!_getCompleteToken(t, true)) return;
// if (!_getCompleteToken(t, true)){std::cout << "TOk" << t << std::endl; return;}
// t = _scanner.getToken(true);

////////////////First line//////////////////////////
///////////////////////////////////////////
if (_isRequestLineParsed == false)
{
this->setMethod(t.value);

t = _scanner.getToken(true);
this->setUri(Uri("http", t.value));

t = _scanner.getToken(true);
this->setVersion(t.value);
if (_method.empty())
{
if (!_getCompleteToken(t, true)) return;
if (!t.value.compare("GET") || !t.value.compare("POST")
|| !t.value.compare("DELETE"))
this->setMethod(t.value);
else
throw std::invalid_argument("Bad http request, No method specified");
// _code.setValue(HttpStatus::BadRequest);
}
if (_uri.empty())
{
if (!_getCompleteToken(t, true)) return;
this->setUri(Uri("http", t.value));

}
if (_version.empty())
{
if (!_getCompleteToken(t, true)) return;
this->setVersion(t.value);
}
{
ph::Token cr;
if (!_getCompleteToken(cr)) return;
if (cr.kind != ph::ScopedEnum::kCarriage)
throw std::invalid_argument("Method line not separated by return carriage");
// _code.setValue(HttpStatus::BadRequest);

if (!_getCompleteToken(t)) {
_scanner.putback(cr);
return;
}
if (t.kind != ph::ScopedEnum::kNewLine)
throw std::invalid_argument("Method line not separated by new line");
// _code.setValue(HttpStatus::BadRequest);
}
_isRequestLineParsed = true;
}
else
_code.setValue(HttpStatus::BadRequest);
// throw std::invalid_argument("Bad http request, No method specified");

t = _scanner.getToken();
if (ph::ScopedEnum::kCarriage != t.kind)
_code.setValue(HttpStatus::BadRequest);
// throw std::invalid_argument("Method line not separated by return carriage");
t = _scanner.getToken();
if (ph::ScopedEnum::kNewLine != t.kind)
_code.setValue(HttpStatus::BadRequest);
// throw std::invalid_argument("Method line not separated by new line");

//////////////////// Headers //////////////////////
///////////////////////////////////////////

std::string name;
std::string value;
bool isValueField = false;
bool isHeader = true;
bool lastIsCariage = false;
while (isHeader && (t = _scanner.getToken()).kind != ph::ScopedEnum::kEndOfInput)

// while (isHeader && (t = _scanner.getToken()).kind != ph::ScopedEnum::kEndOfInput)
// while (!_isHeaderParsed && _getCompleteToken(t) == true)
while (!_isHeaderParsed)
{
if(!_getCompleteToken(t))
{
if (!name.empty())
{
if (isValueField)
_scanner.putback(name+ ": " + value);
else
_scanner.putback(name);
}
return ;
}
switch (t.kind)
{
case ph::ScopedEnum::kCarriage:
lastIsCariage = true;
break;
case ph::ScopedEnum::kNewLine :
if (lastIsCariage == false)
throw std::invalid_argument("MISSING carriage before new line !!!");
{
ph::Token nl;
nl = _scanner.getToken();
if (nl.kind != ph::ScopedEnum::kNewLine)
throw std::invalid_argument("new line !>" + nl.value + "|" + ph::TokenKindToCstring(t.kind));

if (!name.empty())
this->addHeader(name, value);
else
isHeader = false;
_isHeaderParsed = true;
name.clear();
value.clear();
lastIsCariage = false;
isValueField = false;
break;
}
case ph::ScopedEnum::kNewLine :
throw std::invalid_argument("MISSING carriage before new line !!!");
break;
case ph::ScopedEnum::kColon :
lastIsCariage = false;
if (isValueField)
value += t.value;
else
isValueField = true;
break;
case ph::ScopedEnum::kLWS :
lastIsCariage = false;
if (isValueField && !value.empty())
value += t.value;
break;
case ph::ScopedEnum::kString :
lastIsCariage = false;
if (isValueField == false)
name += t.value;
else
Expand All @@ -143,14 +185,25 @@ void HttpRequest::read(const char *buffer)
break;
}
}
_isHeaderParsed = true;
this->getUri().setAuthority(this->getHeader("Host"));

char c;
size_t contentLength = this->getContentLength();
while (contentLength-- && (c = _scanner.getChar()) != -1)
size_t contentLength = this->getContentLength(); // - _content.size();
while (contentLength-- && (c = _scanner.getChar()))
_content += c;
_isContentParsed = true;
if (_content.size() != this->getContentLength()) return ;
_isComplete = true;
}

bool HttpRequest::_getCompleteToken(ph::Token& placeHolder, bool skipLWS)
{
placeHolder = _scanner.getToken(skipLWS);
if (_scanner.peekNextToken().kind == ph::ScopedEnum::kEndOfInput)
{
_scanner.putback(placeHolder);
return false;
}
return true;
}

void HttpRequest::write(std::ostream os)
Expand All @@ -173,13 +226,14 @@ void HttpRequest::clear(void)
_version.clear();
_content.clear();
_headers.clear();
_isRequestLineParsed = false;
_isHeaderParsed = false;
_isContentParsed = false;
_isComplete = false;
}

bool HttpRequest::isComplete(void)
{
return _isHeaderParsed && _isContentParsed;
return _isComplete;
}

int HttpRequest::getHttpErrorCode()
Expand Down
17 changes: 16 additions & 1 deletion src/parser/ScannerBuffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
/* */
/* ************************************************************************** */

#include "parser/ScannerBuffer.hpp"
#include "ScannerBuffer.hpp"

parser::ScannerBuffer::ScannerBuffer() : _c(0) {}

Expand Down Expand Up @@ -50,3 +50,18 @@ void parser::ScannerBuffer::pushNewBuffer(const char *buffer)
while (buffer[i])
_buffer.push_back(buffer[i++]);
}

std::string parser::ScannerBuffer::toString()
{
std::string result;
std::deque<char>::iterator it = _buffer.begin();
std::deque<char>::iterator end = _buffer.end();

while (it != end)
{
result += *it;
it++;
}

return result;
}
24 changes: 23 additions & 1 deletion src/parser/http/ScannerHttpRequest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Token ScannerHttpRequest::getToken(bool skipLWS)
do
{
c = _scan.get();
} while (c != '\n' && isspace(c));
} while (c != '\n' && c != '\r' && isspace(c));
else
c = _scan.get();

Expand Down Expand Up @@ -67,12 +67,34 @@ char ScannerHttpRequest::getChar()
{
return _scan.get();
}
Token ScannerHttpRequest::peekNextToken(bool skipLWS)
{
Token result = getToken(skipLWS);
putback(result);
return result;
}

void ScannerHttpRequest::pushNewBuffer(const char* buffer)
{
_scan.pushNewBuffer(buffer);
}

void ScannerHttpRequest::putback(Token token)
{
this->putback(token.value);
}

void ScannerHttpRequest::putback(std::string str)
{
std::string::reverse_iterator it = str.rbegin();
std::string::reverse_iterator end = str.rend();
while (it != end)
{
_scan.putback(*it);
it++;
}
}

/// Must only be called in the switch statement
bool ScannerHttpRequest::_charIsString(char c){
if (c == ':' || isspace(c))
Expand Down
2 changes: 1 addition & 1 deletion tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ SRC = main.cpp catch_amalgamated.cpp

# Our tests
SRC+= TestsUri.cpp Uri.cpp
SRC+= TestsHttpRequestCreate.cpp
SRC+= TestsHttpRequest.cpp
SRC+= TestsScannerConfig.cpp
SRC+= TestsServerConfig.cpp

Expand Down
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 77f6f3b

Please sign in to comment.