From d0b9e817956a57389f17a3d8e00df51cbe8cc309 Mon Sep 17 00:00:00 2001 From: madmaxoft Date: Fri, 27 Sep 2013 19:34:46 +0200 Subject: [PATCH] Split cHTTPConnection implementation into a separate file. --- VC2008/MCServer.vcproj | 8 ++ source/HTTPServer/HTTPConnection.cpp | 147 +++++++++++++++++++++++++++ source/HTTPServer/HTTPConnection.h | 88 ++++++++++++++++ source/HTTPServer/HTTPServer.cpp | 140 +------------------------ source/HTTPServer/HTTPServer.h | 70 +------------ 5 files changed, 247 insertions(+), 206 deletions(-) create mode 100644 source/HTTPServer/HTTPConnection.cpp create mode 100644 source/HTTPServer/HTTPConnection.h diff --git a/VC2008/MCServer.vcproj b/VC2008/MCServer.vcproj index 7aba32b1d..45579a8a7 100644 --- a/VC2008/MCServer.vcproj +++ b/VC2008/MCServer.vcproj @@ -2719,6 +2719,14 @@ + + + + diff --git a/source/HTTPServer/HTTPConnection.cpp b/source/HTTPServer/HTTPConnection.cpp new file mode 100644 index 000000000..f7318c6ae --- /dev/null +++ b/source/HTTPServer/HTTPConnection.cpp @@ -0,0 +1,147 @@ + +// HTTPConnection.cpp + +// Implements the cHTTPConnection class representing a single persistent connection in the HTTP server. + +#include "Globals.h" +#include "HTTPConnection.h" +#include "HTTPMessage.h" +#include "HTTPServer.h" + + + + + +cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : + m_HTTPServer(a_HTTPServer), + m_State(wcsRecvHeaders), + m_CurrentRequest(NULL) +{ +} + + + + +void cHTTPConnection::SendStatusAndReason(int a_StatusCode, const AString & a_Response) +{ + AppendPrintf(m_OutgoingData, "%d %s\r\n\r\n", a_StatusCode, a_Response.c_str()); +} + + + + + +void cHTTPConnection::Send(const cHTTPResponse & a_Response) +{ + ASSERT(m_State = wcsRecvIdle); + a_Response.AppendToData(m_OutgoingData); + m_State = wcsSendingResp; +} + + + + + +void cHTTPConnection::Send(const void * a_Data, int a_Size) +{ + ASSERT(m_State == wcsSendingResp); + AppendPrintf(m_OutgoingData, "%x\r\n", a_Size); + m_OutgoingData.append((const char *)a_Data, a_Size); +} + + + + + +void cHTTPConnection::FinishResponse(void) +{ + ASSERT(m_State == wcsSendingResp); + m_OutgoingData.append("0\r\n"); + m_State = wcsRecvHeaders; +} + + + + + +void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) +{ + switch (m_State) + { + case wcsRecvHeaders: + { + ASSERT(m_CurrentRequest == NULL); + + // Start searching 3 chars from the end of the already received data, if available: + size_t SearchStart = m_IncomingHeaderData.size(); + SearchStart = (SearchStart > 3) ? SearchStart - 3 : 0; + + m_IncomingHeaderData.append(a_Data, a_Size); + + // Parse the header, if it is complete: + size_t idxEnd = m_IncomingHeaderData.find("\r\n\r\n", SearchStart); + if (idxEnd == AString::npos) + { + return; + } + m_CurrentRequest = new cHTTPRequest; + if (!m_CurrentRequest->ParseHeaders(m_IncomingHeaderData.c_str(), idxEnd + 2)) + { + delete m_CurrentRequest; + m_CurrentRequest = NULL; + m_State = wcsInvalid; + m_HTTPServer.CloseConnection(*this); + return; + } + m_State = wcsRecvBody; + m_HTTPServer.NewRequest(*this, *m_CurrentRequest); + + // Process the rest of the incoming data into the request body: + if (m_IncomingHeaderData.size() > idxEnd + 4) + { + m_IncomingHeaderData.erase(0, idxEnd + 4); + DataReceived(m_IncomingHeaderData.c_str(), m_IncomingHeaderData.size()); + } + break; + } + + case wcsRecvBody: + { + ASSERT(m_CurrentRequest != NULL); + // TODO: Receive the body, and the next request (If HTTP/1.1 keepalive) + break; + } + + default: + { + // TODO: Should we be receiving data in this state? + break; + } + } +} + + + + + +void cHTTPConnection::GetOutgoingData(AString & a_Data) +{ + std::swap(a_Data, m_OutgoingData); +} + + + + + +void cHTTPConnection::SocketClosed(void) +{ + if (m_CurrentRequest != NULL) + { + m_HTTPServer.RequestFinished(*this, *m_CurrentRequest); + } +} + + + + + diff --git a/source/HTTPServer/HTTPConnection.h b/source/HTTPServer/HTTPConnection.h new file mode 100644 index 000000000..e2df5de46 --- /dev/null +++ b/source/HTTPServer/HTTPConnection.h @@ -0,0 +1,88 @@ + +// HTTPConnection.h + +// Declares the cHTTPConnection class representing a single persistent connection in the HTTP server. + + + + + +#pragma once + +#include "../OSSupport/SocketThreads.h" + + + + + +// fwd: +class cHTTPServer; +class cHTTPResponse; +class cHTTPRequest; + + + + + +class cHTTPConnection : + public cSocketThreads::cCallback +{ +public: + + enum eState + { + wcsRecvHeaders, ///< Receiving request headers (m_CurrentRequest == NULL) + wcsRecvBody, ///< Receiving request body (m_CurrentRequest is valid) + wcsRecvIdle, ///< Has received the entire body, waiting to send the response (m_CurrentRequest == NULL) + wcsSendingResp, ///< Sending response body (m_CurrentRequest == NULL) + wcsInvalid, ///< The request was malformed, the connection is closing + } ; + + cHTTPConnection(cHTTPServer & a_HTTPServer); + + /// Sends HTTP status code together with a_Reason (used for HTTP errors) + void SendStatusAndReason(int a_StatusCode, const AString & a_Reason); + + /// Sends the headers contained in a_Response + void Send(const cHTTPResponse & a_Response); + + /// Sends the data as the response (may be called multiple times) + void Send(const void * a_Data, int a_Size); + + /// Sends the data as the response (may be called multiple times) + void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); } + + /// Finishes sending current response, gets ready for receiving another request (HTTP 1.1 keepalive) + void FinishResponse(void); + +protected: + typedef std::map cNameValueMap; + + /// The parent webserver that is to be notified of events on this connection + cHTTPServer & m_HTTPServer; + + /// All the incoming data until the entire request header is parsed + AString m_IncomingHeaderData; + + /// Status in which the request currently is + eState m_State; + + /// Data that is queued for sending, once the socket becomes writable + AString m_OutgoingData; + + /// The request being currently received (valid only between having parsed the headers and finishing receiving the body) + cHTTPRequest * m_CurrentRequest; + + + // cSocketThreads::cCallback overrides: + virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client + virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client + virtual void SocketClosed (void) override; // The socket has been closed for any reason +} ; + +typedef std::vector cHTTPConnections; + + + + + diff --git a/source/HTTPServer/HTTPServer.cpp b/source/HTTPServer/HTTPServer.cpp index e68032bc2..980cad14f 100644 --- a/source/HTTPServer/HTTPServer.cpp +++ b/source/HTTPServer/HTTPServer.cpp @@ -6,6 +6,7 @@ #include "Globals.h" #include "HTTPServer.h" #include "HTTPMessage.h" +#include "HTTPConnection.h" @@ -21,145 +22,6 @@ -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cHTTPConnection: - -cHTTPConnection::cHTTPConnection(cHTTPServer & a_HTTPServer) : - m_HTTPServer(a_HTTPServer), - m_State(wcsRecvHeaders), - m_CurrentRequest(NULL) -{ -} - - - - -void cHTTPConnection::SendStatusAndReason(int a_StatusCode, const AString & a_Response) -{ - AppendPrintf(m_OutgoingData, "%d %s\r\n\r\n", a_StatusCode, a_Response.c_str()); -} - - - - - -void cHTTPConnection::Send(const cHTTPResponse & a_Response) -{ - ASSERT(m_State = wcsRecvIdle); - a_Response.AppendToData(m_OutgoingData); - m_State = wcsSendingResp; -} - - - - - -void cHTTPConnection::Send(const void * a_Data, int a_Size) -{ - ASSERT(m_State == wcsSendingResp); - AppendPrintf(m_OutgoingData, "%x\r\n", a_Size); - m_OutgoingData.append((const char *)a_Data, a_Size); -} - - - - - -void cHTTPConnection::FinishResponse(void) -{ - ASSERT(m_State == wcsSendingResp); - m_OutgoingData.append("0\r\n"); - m_State = wcsRecvHeaders; -} - - - - - -void cHTTPConnection::DataReceived(const char * a_Data, int a_Size) -{ - switch (m_State) - { - case wcsRecvHeaders: - { - ASSERT(m_CurrentRequest == NULL); - - // Start searching 3 chars from the end of the already received data, if available: - size_t SearchStart = m_IncomingHeaderData.size(); - SearchStart = (SearchStart > 3) ? SearchStart - 3 : 0; - - m_IncomingHeaderData.append(a_Data, a_Size); - - // Parse the header, if it is complete: - size_t idxEnd = m_IncomingHeaderData.find("\r\n\r\n", SearchStart); - if (idxEnd == AString::npos) - { - return; - } - m_CurrentRequest = new cHTTPRequest; - if (!m_CurrentRequest->ParseHeaders(m_IncomingHeaderData.c_str(), idxEnd + 2)) - { - delete m_CurrentRequest; - m_CurrentRequest = NULL; - m_State = wcsInvalid; - m_HTTPServer.CloseConnection(*this); - return; - } - m_State = wcsRecvBody; - m_HTTPServer.NewRequest(*this, *m_CurrentRequest); - - // Process the rest of the incoming data into the request body: - if (m_IncomingHeaderData.size() > idxEnd + 4) - { - m_IncomingHeaderData.erase(0, idxEnd + 4); - DataReceived(m_IncomingHeaderData.c_str(), m_IncomingHeaderData.size()); - } - break; - } - - case wcsRecvBody: - { - ASSERT(m_CurrentRequest != NULL); - // TODO: Receive the body, and the next request (If HTTP/1.1 keepalive) - break; - } - - default: - { - // TODO: Should we be receiving data in this state? - break; - } - } -} - - - - - -void cHTTPConnection::GetOutgoingData(AString & a_Data) -{ - std::swap(a_Data, m_OutgoingData); -} - - - - - -void cHTTPConnection::SocketClosed(void) -{ - if (m_CurrentRequest != NULL) - { - m_HTTPServer.RequestFinished(*this, *m_CurrentRequest); - } -} - - - - - -/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -// cHTTPServer: - cHTTPServer::cHTTPServer(void) : m_ListenThreadIPv4(*this, cSocket::IPv4, "WebServer IPv4"), m_ListenThreadIPv6(*this, cSocket::IPv6, "WebServer IPv6"), diff --git a/source/HTTPServer/HTTPServer.h b/source/HTTPServer/HTTPServer.h index 9287a79e8..fd4782267 100644 --- a/source/HTTPServer/HTTPServer.h +++ b/source/HTTPServer/HTTPServer.h @@ -18,82 +18,18 @@ // fwd: -class cHTTPServer; class cHTTPMessage; class cHTTPRequest; class cHTTPResponse; - - - - - -class cHTTPConnection : - public cSocketThreads::cCallback -{ -public: - - enum eState - { - wcsRecvHeaders, ///< Receiving request headers (m_CurrentRequest == NULL) - wcsRecvBody, ///< Receiving request body (m_CurrentRequest is valid) - wcsRecvIdle, ///< Has received the entire body, waiting to send the response (m_CurrentRequest == NULL) - wcsSendingResp, ///< Sending response body (m_CurrentRequest == NULL) - wcsInvalid, ///< The request was malformed, the connection is closing - } ; - - cHTTPConnection(cHTTPServer & a_HTTPServer); - - /// Sends HTTP status code together with a_Reason (used for HTTP errors) - void SendStatusAndReason(int a_StatusCode, const AString & a_Reason); - - /// Sends the headers contained in a_Response - void Send(const cHTTPResponse & a_Response); - - /// Sends the data as the response (may be called multiple times) - void Send(const void * a_Data, int a_Size); - - /// Sends the data as the response (may be called multiple times) - void Send(const AString & a_Data) { Send(a_Data.data(), a_Data.size()); } - - /// Finishes sending current response, gets ready for receiving another request (HTTP 1.1 keepalive) - void FinishResponse(void); - -protected: - typedef std::map cNameValueMap; - - /// The parent webserver that is to be notified of events on this connection - cHTTPServer & m_HTTPServer; - - /// All the incoming data until the entire request header is parsed - AString m_IncomingHeaderData; - - /// Status in which the request currently is - eState m_State; - - /// Data that is queued for sending, once the socket becomes writable - AString m_OutgoingData; - - /// The request being currently received (valid only between having parsed the headers and finishing receiving the body) - cHTTPRequest * m_CurrentRequest; - - - /// Parses the header in m_IncomingData until the specified end mark - void ParseHeader(size_t a_IdxEnd); - - /// Sends the response status and headers. Transition from wrsRecvBody to wrsSendingResp. - void SendRespHeaders(void); - - // cSocketThreads::cCallback overrides: - virtual void DataReceived (const char * a_Data, int a_Size) override; // Data is received from the client - virtual void GetOutgoingData(AString & a_Data) override; // Data can be sent to client - virtual void SocketClosed (void) override; // The socket has been closed for any reason -} ; +class cHTTPConnection; typedef std::vector cHTTPConnections; + + class cHTTPServer : public cListenThread::cCallback {