From f4efcb90808603bbfce5a149f5490bd6fceb880f Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 27 Sep 2013 18:14:26 +0200 Subject: Rewritten HTTPServer to split into cHTTPConnection, cHTTPRequest and cHTTPResponse classes. --- source/HTTPServer/HTTPMessage.h | 121 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 source/HTTPServer/HTTPMessage.h (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h new file mode 100644 index 000000000..a3c4f96d1 --- /dev/null +++ b/source/HTTPServer/HTTPMessage.h @@ -0,0 +1,121 @@ + +// HTTPMessage.h + +// Declares the cHTTPMessage class representing the common ancestor for HTTP request and response classes + + + + + +#pragma once + + + + + +class cHTTPMessage +{ +public: + enum + { + HTTP_OK = 200, + HTTP_BAD_REQUEST = 400, + } ; + + enum eKind + { + mkRequest, + mkResponse, + } ; + + cHTTPMessage(eKind a_Kind); + + /// Adds a header into the internal map of headers. Recognizes special headers: Content-Type and Content-Length + void AddHeader(const AString & a_Key, const AString & a_Value); + + void SetContentType (const AString & a_ContentType) { m_ContentType = a_ContentType; } + void SetContentLength(int a_ContentLength) { m_ContentLength = a_ContentLength; } + + const AString & GetContentType (void) const { return m_ContentType; } + int GetContentLength(void) const { return m_ContentLength; } + +protected: + typedef std::map cNameValueMap; + + eKind m_Kind; + + cNameValueMap m_Headers; + + /// Type of the content; parsed by AddHeader(), set directly by SetContentLength() + AString m_ContentType; + + /// Length of the content that is to be received. -1 when the object is created, parsed by AddHeader() or set directly by SetContentLength() + int m_ContentLength; +} ; + + + + + +class cHTTPRequest : + public cHTTPMessage +{ + typedef cHTTPMessage super; + +public: + cHTTPRequest(void); + + /// Parses the headers information from the received data in the specified string of incoming data. Returns true if successful. + bool ParseHeaders(const char * a_IncomingData, size_t a_idxEnd); + + /// Returns true if the request did contain a Content-Length header + bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } + +protected: + /// Method of the request (GET / PUT / POST / ...) + AString m_Method; + + /// Full URL of the request + AString m_URL; + + /// Number of bytes that remain to read for the complete body of the message to be received + int m_BodyRemaining; + + /** Parses the RequestLine out of a_Data, up to index a_IdxEnd + Returns the index to the next line, or npos if invalid request + */ + size_t ParseRequestLine(const char * a_Data, size_t a_IdxEnd); + + /** Parses one header field out of a_Data, up to offset a_IdxEnd. + Returns the index to the next line (relative to a_Data), or npos if invalid request. + a_Key is set to the key that was parsed (used for multi-line headers) + */ + size_t ParseHeaderField(const char * a_Data, size_t a_IdxEnd, AString & a_Key); + + /** Parses one header field that is known to be a continuation of previous header. + Returns the index to the next line, or npos if invalid request. + */ + size_t ParseHeaderFieldContinuation(const char * a_Data, size_t a_IdxEnd, AString & a_Key); +} ; + + + + + +class cHTTPResponse : + public cHTTPMessage +{ + typedef cHTTPMessage super; + +public: + cHTTPResponse(void); + + /** Appends the response to the specified datastream - response line and headers. + The body will be sent later directly through cConnection::Send() + */ + void AppendToData(AString & a_DataStream) const; +} ; + + + + -- cgit v1.2.3 From 0c3fd5e77d681c25757efaab6acb305d0b5630c1 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 27 Sep 2013 20:33:18 +0200 Subject: Fixed parsing and implemented write nofitication. The web connection finally works with a browser. --- source/HTTPServer/HTTPMessage.h | 3 --- 1 file changed, 3 deletions(-) (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h index a3c4f96d1..fc7b621fe 100644 --- a/source/HTTPServer/HTTPMessage.h +++ b/source/HTTPServer/HTTPMessage.h @@ -78,9 +78,6 @@ protected: /// Full URL of the request AString m_URL; - /// Number of bytes that remain to read for the complete body of the message to be received - int m_BodyRemaining; - /** Parses the RequestLine out of a_Data, up to index a_IdxEnd Returns the index to the next line, or npos if invalid request */ -- cgit v1.2.3 From c22ea7efff5d611d8293eff895b2ff1b234aa5a6 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 27 Sep 2013 21:38:54 +0200 Subject: Added UserData to cHTTPRequest. Callbacks may store one pointer of per-request data in the cHTTPRequest object. The object doesn't touch this data (doesn't own it). --- source/HTTPServer/HTTPMessage.h | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h index fc7b621fe..7b1a27eaa 100644 --- a/source/HTTPServer/HTTPMessage.h +++ b/source/HTTPServer/HTTPMessage.h @@ -71,6 +71,12 @@ public: /// Returns true if the request did contain a Content-Length header bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } + /// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)! + void SetUserData(void * a_UserData) { m_UserData = a_UserData; } + + /// Retrieves the UserData pointer that has been stored within this request. + void * GetUserData(void) const { return m_UserData; } + protected: /// Method of the request (GET / PUT / POST / ...) AString m_Method; @@ -78,6 +84,10 @@ protected: /// Full URL of the request AString m_URL; + /// Data that the HTTPServer callbacks are allowed to store. + void * m_UserData; + + /** Parses the RequestLine out of a_Data, up to index a_IdxEnd Returns the index to the next line, or npos if invalid request */ -- cgit v1.2.3 From 8130e6dd5439e381aae18532ede48441a4b46155 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 28 Sep 2013 19:30:25 +0200 Subject: Created basic cHTTPFormParser. It can parse forms in the application/x-www-form-urlencoded encoding, used for forms without file uploads. --- source/HTTPServer/HTTPMessage.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h index 7b1a27eaa..1c2514739 100644 --- a/source/HTTPServer/HTTPMessage.h +++ b/source/HTTPServer/HTTPMessage.h @@ -71,6 +71,12 @@ public: /// Returns true if the request did contain a Content-Length header bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } + /// Returns the method used in the request + const AString & GetMethod(void) const { return m_Method; } + + /// Returns the URL used in the request + const AString & GetURL(void) const { return m_URL; } + /// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)! void SetUserData(void * a_UserData) { m_UserData = a_UserData; } -- cgit v1.2.3 From 1012fd82fda9e9bc75d2308a3c68cb3b3738bf1b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 4 Oct 2013 13:07:57 +0200 Subject: HTTP Server can now parse multipart/form-data forms; better architecture. --- source/HTTPServer/HTTPMessage.h | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h index 1c2514739..ef8e12ca4 100644 --- a/source/HTTPServer/HTTPMessage.h +++ b/source/HTTPServer/HTTPMessage.h @@ -9,6 +9,8 @@ #pragma once +#include "EnvelopeParser.h" + @@ -58,15 +60,18 @@ protected: class cHTTPRequest : - public cHTTPMessage + public cHTTPMessage, + protected cEnvelopeParser::cCallbacks { typedef cHTTPMessage super; public: cHTTPRequest(void); - /// Parses the headers information from the received data in the specified string of incoming data. Returns true if successful. - bool ParseHeaders(const char * a_IncomingData, size_t a_idxEnd); + /** Parses the request line and then headers from the received data. + Returns the number of bytes consumed or a negative number for error + */ + int ParseHeaders(const char * a_Data, int a_Size); /// Returns true if the request did contain a Content-Length header bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); } @@ -83,7 +88,19 @@ public: /// Retrieves the UserData pointer that has been stored within this request. void * GetUserData(void) const { return m_UserData; } + /// Returns true if more data is expected for the request headers + bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); } + protected: + /// Parser for the envelope data + cEnvelopeParser m_EnvelopeParser; + + /// True if the data received so far is parsed successfully. When false, all further parsing is skipped + bool m_IsValid; + + /// Bufferred incoming data, while parsing for the request line + AString m_IncomingHeaderData; + /// Method of the request (GET / PUT / POST / ...) AString m_Method; @@ -94,21 +111,13 @@ protected: void * m_UserData; - /** Parses the RequestLine out of a_Data, up to index a_IdxEnd - Returns the index to the next line, or npos if invalid request + /** Parses the incoming data for the first line (RequestLine) + Returns the number of bytes consumed, or -1 for an error */ - size_t ParseRequestLine(const char * a_Data, size_t a_IdxEnd); + int ParseRequestLine(const char * a_Data, int a_Size); - /** Parses one header field out of a_Data, up to offset a_IdxEnd. - Returns the index to the next line (relative to a_Data), or npos if invalid request. - a_Key is set to the key that was parsed (used for multi-line headers) - */ - size_t ParseHeaderField(const char * a_Data, size_t a_IdxEnd, AString & a_Key); - - /** Parses one header field that is known to be a continuation of previous header. - Returns the index to the next line, or npos if invalid request. - */ - size_t ParseHeaderFieldContinuation(const char * a_Data, size_t a_IdxEnd, AString & a_Key); + // cEnvelopeParser::cCallbacks overrides: + virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override; } ; -- cgit v1.2.3 From db3d83b38dd61b90466a0721fa9104e742f3fb8b Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 4 Oct 2013 20:28:30 +0200 Subject: Added Basic auth support to cHTTPRequest. --- source/HTTPServer/HTTPMessage.h | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h index ef8e12ca4..151eb468f 100644 --- a/source/HTTPServer/HTTPMessage.h +++ b/source/HTTPServer/HTTPMessage.h @@ -91,6 +91,15 @@ public: /// Returns true if more data is expected for the request headers bool IsInHeaders(void) const { return m_EnvelopeParser.IsInHeaders(); } + /// Returns true if the request did present auth data that was understood by the parser + bool HasAuth(void) const { return m_HasAuth; } + + /// Returns the username that the request presented. Only valid if HasAuth() is true + const AString & GetAuthUsername(void) const { return m_AuthUsername; } + + /// Returns the password that the request presented. Only valid if HasAuth() is true + const AString & GetAuthPassword(void) const { return m_AuthPassword; } + protected: /// Parser for the envelope data cEnvelopeParser m_EnvelopeParser; @@ -110,6 +119,15 @@ protected: /// Data that the HTTPServer callbacks are allowed to store. void * m_UserData; + /// Set to true if the request contains auth data that was understood by the parser + bool m_HasAuth; + + /// The username used for auth + AString m_AuthUsername; + + /// The password used for auth + AString m_AuthPassword; + /** Parses the incoming data for the first line (RequestLine) Returns the number of bytes consumed, or -1 for an error -- cgit v1.2.3 From b5c90d7b20fede4e643e96417684c7c009d063cb Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Sat, 5 Oct 2013 23:08:16 +0200 Subject: WebAdmin uses the new HTTP functionality. This is a partial implementation of #183. --- source/HTTPServer/HTTPMessage.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'source/HTTPServer/HTTPMessage.h') diff --git a/source/HTTPServer/HTTPMessage.h b/source/HTTPServer/HTTPMessage.h index 151eb468f..f5284c535 100644 --- a/source/HTTPServer/HTTPMessage.h +++ b/source/HTTPServer/HTTPMessage.h @@ -82,6 +82,9 @@ public: /// Returns the URL used in the request const AString & GetURL(void) const { return m_URL; } + /// Returns the URL used in the request, without any parameters + AString GetBareURL(void) const; + /// Sets the UserData pointer that is stored within this request. The request doesn't touch this data (doesn't delete it)! void SetUserData(void * a_UserData) { m_UserData = a_UserData; } -- cgit v1.2.3