1
0

Rewritten HTTPServer to use size_t for data lengths.

This commit is contained in:
madmaxoft 2014-04-01 16:36:00 +02:00
parent 0d916a3e2f
commit 1795cca552
16 changed files with 97 additions and 90 deletions

View File

@ -20,7 +20,7 @@ cEnvelopeParser::cEnvelopeParser(cCallbacks & a_Callbacks) :
int cEnvelopeParser::Parse(const char * a_Data, int a_Size)
size_t cEnvelopeParser::Parse(const char * a_Data, size_t a_Size)
{
if (!m_IsInHeaders)
{
@ -55,7 +55,7 @@ int cEnvelopeParser::Parse(const char * a_Data, int a_Size)
{
// An error has occurred
m_IsInHeaders = false;
return -1;
return AString::npos;
}
Last = idxCRLF + 2;
idxCRLF = m_IncomingData.find("\r\n", idxCRLF + 2);

View File

@ -19,7 +19,9 @@ public:
class cCallbacks
{
public:
/// Called when a full header line is parsed
virtual ~cCallbacks() {}
/** Called when a full header line is parsed */
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) = 0;
} ;
@ -27,40 +29,41 @@ public:
cEnvelopeParser(cCallbacks & a_Callbacks);
/** Parses the incoming data.
Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header
Returns the number of bytes consumed from the input. The bytes not consumed are not part of the envelope header.
Returns AString::npos on error
*/
int Parse(const char * a_Data, int a_Size);
size_t Parse(const char * a_Data, size_t a_Size);
/// Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream
/** Makes the parser forget everything parsed so far, so that it can be reused for parsing another datastream */
void Reset(void);
/// Returns true if more input is expected for the envelope header
/** Returns true if more input is expected for the envelope header */
bool IsInHeaders(void) const { return m_IsInHeaders; }
/// Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions
/** Sets the IsInHeaders flag; used by cMultipartParser to simplify the parser initial conditions */
void SetIsInHeaders(bool a_IsInHeaders) { m_IsInHeaders = a_IsInHeaders; }
public:
/// Callbacks to call for the various events
/** Callbacks to call for the various events */
cCallbacks & m_Callbacks;
/// Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data.
/** Set to true while the parser is still parsing the envelope headers. Once set to true, the parser will not consume any more data. */
bool m_IsInHeaders;
/// Buffer for the incoming data until it is parsed
/** Buffer for the incoming data until it is parsed */
AString m_IncomingData;
/// Holds the last parsed key; used for line-wrapped values
/** Holds the last parsed key; used for line-wrapped values */
AString m_LastKey;
/// Holds the last parsed value; used for line-wrapped values
/** Holds the last parsed value; used for line-wrapped values */
AString m_LastValue;
/// Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them
/** Notifies the callback of the key/value stored in m_LastKey/m_LastValue, then erases them */
void NotifyLast(void);
/// Parses one line of header data. Returns true if successful
/** Parses one line of header data. Returns true if successful */
bool ParseLine(const char * a_Data, size_t a_Size);
} ;

View File

@ -67,7 +67,7 @@ void cHTTPConnection::Send(const cHTTPResponse & a_Response)
void cHTTPConnection::Send(const void * a_Data, int a_Size)
void cHTTPConnection::Send(const void * a_Data, size_t a_Size)
{
ASSERT(m_State == wcsSendingResp);
AppendPrintf(m_OutgoingData, "%x\r\n", a_Size);
@ -155,8 +155,8 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
m_CurrentRequest = new cHTTPRequest;
}
int BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size);
if (BytesConsumed < 0)
size_t BytesConsumed = m_CurrentRequest->ParseHeaders(a_Data, a_Size);
if (BytesConsumed == AString::npos)
{
delete m_CurrentRequest;
m_CurrentRequest = NULL;
@ -174,16 +174,16 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
m_State = wcsRecvBody;
m_HTTPServer.NewRequest(*this, *m_CurrentRequest);
m_CurrentRequestBodyRemaining = m_CurrentRequest->GetContentLength();
if (m_CurrentRequestBodyRemaining < 0)
if (m_CurrentRequestBodyRemaining == AString::npos)
{
// The body length was not specified in the request, assume zero
m_CurrentRequestBodyRemaining = 0;
}
// Process the rest of the incoming data into the request body:
if (a_Size > BytesConsumed)
if (a_Size > (int)BytesConsumed)
{
DataReceived(a_Data + BytesConsumed, a_Size - BytesConsumed);
DataReceived(a_Data + BytesConsumed, a_Size - (int)BytesConsumed);
}
else
{
@ -197,7 +197,7 @@ void cHTTPConnection::DataReceived(const char * a_Data, int a_Size)
ASSERT(m_CurrentRequest != NULL);
if (m_CurrentRequestBodyRemaining > 0)
{
int BytesToConsume = std::min(m_CurrentRequestBodyRemaining, a_Size);
size_t BytesToConsume = std::min(m_CurrentRequestBodyRemaining, (size_t)a_Size);
m_HTTPServer.RequestBody(*this, *m_CurrentRequest, a_Data, BytesToConsume);
m_CurrentRequestBodyRemaining -= BytesToConsume;
}

View File

@ -51,7 +51,7 @@ public:
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);
void Send(const void * a_Data, size_t 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()); }
@ -87,7 +87,7 @@ protected:
/** Number of bytes that remain to read for the complete body of the message to be received.
Valid only in wcsRecvBody */
int m_CurrentRequestBodyRemaining;
size_t m_CurrentRequestBodyRemaining;
// cSocketThreads::cCallback overrides:

View File

@ -243,7 +243,7 @@ void cHTTPFormParser::OnPartHeader(const AString & a_Key, const AString & a_Valu
void cHTTPFormParser::OnPartData(const char * a_Data, int a_Size)
void cHTTPFormParser::OnPartData(const char * a_Data, size_t a_Size)
{
if (m_CurrentPartName.empty())
{

View File

@ -40,7 +40,7 @@ public:
virtual void OnFileStart(cHTTPFormParser & a_Parser, const AString & a_FileName) = 0;
/// Called when more file data has come for the current file in the form data
virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) = 0;
virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) = 0;
/// Called when the current file part has ended in the form data
virtual void OnFileEnd(cHTTPFormParser & a_Parser) = 0;
@ -103,7 +103,7 @@ protected:
// cMultipartParser::cCallbacks overrides:
virtual void OnPartStart (void) override;
virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) override;
virtual void OnPartData (const char * a_Data, int a_Size) override;
virtual void OnPartData (const char * a_Data, size_t a_Size) override;
virtual void OnPartEnd (void) override;
} ;

View File

@ -25,7 +25,7 @@
cHTTPMessage::cHTTPMessage(eKind a_Kind) :
m_Kind(a_Kind),
m_ContentLength(-1)
m_ContentLength(AString::npos)
{
}
@ -81,23 +81,23 @@ cHTTPRequest::cHTTPRequest(void) :
int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
size_t cHTTPRequest::ParseHeaders(const char * a_Data, size_t a_Size)
{
if (!m_IsValid)
{
return -1;
return AString::npos;
}
if (m_Method.empty())
{
// The first line hasn't been processed yet
int res = ParseRequestLine(a_Data, a_Size);
if ((res < 0) || (res == a_Size))
size_t res = ParseRequestLine(a_Data, a_Size);
if ((res == AString::npos) || (res == a_Size))
{
return res;
}
int res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res);
if (res2 < 0)
size_t res2 = m_EnvelopeParser.Parse(a_Data + res, a_Size - res);
if (res2 == AString::npos)
{
m_IsValid = false;
return res2;
@ -107,8 +107,8 @@ int cHTTPRequest::ParseHeaders(const char * a_Data, int a_Size)
if (m_EnvelopeParser.IsInHeaders())
{
int res = m_EnvelopeParser.Parse(a_Data, a_Size);
if (res < 0)
size_t res = m_EnvelopeParser.Parse(a_Data, a_Size);
if (res == AString::npos)
{
m_IsValid = false;
}
@ -138,7 +138,7 @@ AString cHTTPRequest::GetBareURL(void) const
int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
size_t cHTTPRequest::ParseRequestLine(const char * a_Data, size_t a_Size)
{
m_IncomingHeaderData.append(a_Data, a_Size);
size_t IdxEnd = m_IncomingHeaderData.size();
@ -158,7 +158,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
if (LineStart >= IdxEnd)
{
m_IsValid = false;
return -1;
return AString::npos;
}
int NumSpaces = 0;
@ -186,7 +186,7 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
{
// Too many spaces in the request
m_IsValid = false;
return -1;
return AString::npos;
}
}
NumSpaces += 1;
@ -198,13 +198,13 @@ int cHTTPRequest::ParseRequestLine(const char * a_Data, int a_Size)
{
// LF too early, without a CR, without two preceeding spaces or too soon after the second space
m_IsValid = false;
return -1;
return AString::npos;
}
// Check that there's HTTP/version at the end
if (strncmp(a_Data + URLEnd + 1, "HTTP/1.", 7) != 0)
{
m_IsValid = false;
return -1;
return AString::npos;
}
m_Method = m_IncomingHeaderData.substr(LineStart, MethodEnd - LineStart);
m_URL = m_IncomingHeaderData.substr(MethodEnd + 1, URLEnd - MethodEnd - 1);

View File

@ -42,7 +42,7 @@ public:
void SetContentLength(int a_ContentLength) { m_ContentLength = a_ContentLength; }
const AString & GetContentType (void) const { return m_ContentType; }
int GetContentLength(void) const { return m_ContentLength; }
size_t GetContentLength(void) const { return m_ContentLength; }
protected:
typedef std::map<AString, AString> cNameValueMap;
@ -54,8 +54,10 @@ protected:
/** 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;
/** Length of the content that is to be received.
AString::npos when the object is created.
Parsed by AddHeader() or set directly by SetContentLength() */
size_t m_ContentLength;
} ;
@ -72,9 +74,9 @@ public:
cHTTPRequest(void);
/** Parses the request line and then headers from the received data.
Returns the number of bytes consumed or a negative number for error
Returns the number of bytes consumed or AString::npos number for error
*/
int ParseHeaders(const char * a_Data, int a_Size);
size_t ParseHeaders(const char * a_Data, size_t a_Size);
/** Returns true if the request did contain a Content-Length header */
bool HasReceivedContentLength(void) const { return (m_ContentLength >= 0); }
@ -145,7 +147,7 @@ protected:
/** Parses the incoming data for the first line (RequestLine)
Returns the number of bytes consumed, or -1 for an error
*/
int ParseRequestLine(const char * a_Data, int a_Size);
size_t ParseRequestLine(const char * a_Data, size_t a_Size);
// cEnvelopeParser::cCallbacks overrides:
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override;

View File

@ -38,7 +38,7 @@ class cDebugCallbacks :
}
virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override
virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override
{
UNUSED(a_Connection);
@ -100,7 +100,7 @@ class cDebugCallbacks :
}
virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, int a_Size) override
virtual void OnFileData(cHTTPFormParser & a_Parser, const char * a_Data, size_t a_Size) override
{
// TODO
}
@ -242,7 +242,7 @@ void cHTTPServer::NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Re
void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size)
void cHTTPServer::RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size)
{
m_Callbacks->OnRequestBody(a_Connection, a_Request, a_Data, a_Size);
}

View File

@ -44,8 +44,9 @@ public:
*/
virtual void OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0;
/// Called when another part of request body has arrived.
virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) = 0;
/** Called when another part of request body has arrived.
May be called multiple times for a single request. */
virtual void OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) = 0;
/// Called when the request body has been fully received in previous calls to OnRequestBody()
virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) = 0;
@ -90,8 +91,9 @@ protected:
/// Called by cHTTPConnection when it finishes parsing the request header
void NewRequest(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);
/// Called by cHTTPConenction when it receives more data for the request body
void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size);
/** Called by cHTTPConenction when it receives more data for the request body.
May be called multiple times for a single request. */
void RequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size);
/// Called by cHTTPConnection when it detects that the request has finished (all of its body has been received)
void RequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request);

View File

@ -97,8 +97,6 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a
m_EnvelopeParser(*this),
m_HasHadData(false)
{
static AString s_Multipart = "multipart/";
// Check that the content type is multipart:
AString ContentType(a_ContentType);
if (strncmp(ContentType.c_str(), "multipart/", 10) != 0)
@ -146,7 +144,7 @@ cMultipartParser::cMultipartParser(const AString & a_ContentType, cCallbacks & a
void cMultipartParser::Parse(const char * a_Data, int a_Size)
void cMultipartParser::Parse(const char * a_Data, size_t a_Size)
{
// Skip parsing if invalid
if (!m_IsValid)
@ -160,8 +158,8 @@ void cMultipartParser::Parse(const char * a_Data, int a_Size)
{
if (m_EnvelopeParser.IsInHeaders())
{
int BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size());
if (BytesConsumed < 0)
size_t BytesConsumed = m_EnvelopeParser.Parse(m_IncomingData.data(), m_IncomingData.size());
if (BytesConsumed == AString::npos)
{
m_IsValid = false;
return;

View File

@ -22,50 +22,52 @@ public:
class cCallbacks
{
public:
/// Called when a new part starts
virtual ~cCallbacks() {}
/** Called when a new part starts */
virtual void OnPartStart(void) = 0;
/// Called when a complete header line is received for a part
/** Called when a complete header line is received for a part */
virtual void OnPartHeader(const AString & a_Key, const AString & a_Value) = 0;
/// Called when body for a part is received
virtual void OnPartData(const char * a_Data, int a_Size) = 0;
/** Called when body for a part is received */
virtual void OnPartData(const char * a_Data, size_t a_Size) = 0;
/// Called when the current part ends
/** Called when the current part ends */
virtual void OnPartEnd(void) = 0;
} ;
/// Creates the parser, expects to find the boundary in a_ContentType
/** Creates the parser, expects to find the boundary in a_ContentType */
cMultipartParser(const AString & a_ContentType, cCallbacks & a_Callbacks);
/// Parses more incoming data
void Parse(const char * a_Data, int a_Size);
/** Parses more incoming data */
void Parse(const char * a_Data, size_t a_Size);
protected:
/// The callbacks to call for various parsing events
/** The callbacks to call for various parsing events */
cCallbacks & m_Callbacks;
/// True if the data parsed so far is valid; if false, further parsing is skipped
/** True if the data parsed so far is valid; if false, further parsing is skipped */
bool m_IsValid;
/// Parser for each part's envelope
/** Parser for each part's envelope */
cEnvelopeParser m_EnvelopeParser;
/// Buffer for the incoming data until it is parsed
/** Buffer for the incoming data until it is parsed */
AString m_IncomingData;
/// The boundary, excluding both the initial "--" and the terminating CRLF
/** The boundary, excluding both the initial "--" and the terminating CRLF */
AString m_Boundary;
/// Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting.
/** Set to true if some data for the current part has already been signalized to m_Callbacks. Used for proper CRLF inserting. */
bool m_HasHadData;
/// Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size
void ParseLine(const char * a_Data, int a_Size);
/** Parse one line of incoming data. The CRLF has already been stripped from a_Data / a_Size */
void ParseLine(const char * a_Data, size_t a_Size);
/// Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size
void ParseHeaderLine(const char * a_Data, int a_Size);
/** Parse one line of incoming data in the headers section of a part. The CRLF has already been stripped from a_Data / a_Size */
void ParseHeaderLine(const char * a_Data, size_t a_Size);
// cEnvelopeParser overrides:
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override;

View File

@ -24,7 +24,7 @@ public:
// Now try parsing char-by-char, to debug transitions across datachunk boundaries:
cNameValueParser Parser2;
for (int i = 0; i < sizeof(Data) - 1; i++)
for (size_t i = 0; i < sizeof(Data) - 1; i++)
{
Parser2.Parse(Data + i, 1);
}
@ -82,7 +82,7 @@ cNameValueParser::cNameValueParser(bool a_AllowsKeyOnly) :
cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly) :
cNameValueParser::cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly) :
m_State(psKeySpace),
m_AllowsKeyOnly(a_AllowsKeyOnly)
{
@ -93,12 +93,12 @@ cNameValueParser::cNameValueParser(const char * a_Data, int a_Size, bool a_Allow
void cNameValueParser::Parse(const char * a_Data, int a_Size)
void cNameValueParser::Parse(const char * a_Data, size_t a_Size)
{
ASSERT(m_State != psFinished); // Calling Parse() after Finish() is wrong!
int Last = 0;
for (int i = 0; i < a_Size;)
for (size_t i = 0; i < a_Size;)
{
switch (m_State)
{

View File

@ -21,10 +21,10 @@ public:
cNameValueParser(bool a_AllowsKeyOnly = true);
/// Creates an empty parser, then parses the data given. Doesn't call Finish(), so more data can be parsed later
cNameValueParser(const char * a_Data, int a_Size, bool a_AllowsKeyOnly = true);
cNameValueParser(const char * a_Data, size_t a_Size, bool a_AllowsKeyOnly = true);
/// Parses the data given
void Parse(const char * a_Data, int a_Size);
void Parse(const char * a_Data, size_t a_Size);
/// Notifies the parser that no more data will be coming. Returns true if the parser state is valid
bool Finish(void);

View File

@ -490,7 +490,7 @@ void cWebAdmin::OnRequestBegun(cHTTPConnection & a_Connection, cHTTPRequest & a_
void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size)
void cWebAdmin::OnRequestBody(cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size)
{
UNUSED(a_Connection);
cRequestData * Data = (cRequestData *)(a_Request.GetUserData());
@ -537,7 +537,7 @@ void cWebAdmin::OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest &
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// cWebAdmin::cWebadminRequestData
void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, int a_Size)
void cWebAdmin::cWebadminRequestData::OnBody(const char * a_Data, size_t a_Size)
{
m_Form.Parse(a_Data, a_Size);
}

View File

@ -151,7 +151,7 @@ protected:
virtual ~cRequestData() {} // Force a virtual destructor in all descendants
/** Called when a new chunk of body data is received */
virtual void OnBody(const char * a_Data, int a_Size) = 0;
virtual void OnBody(const char * a_Data, size_t a_Size) = 0;
} ;
/** The body handler for requests in the "/webadmin" and "/~webadmin" paths */
@ -169,14 +169,14 @@ protected:
}
// cRequestData overrides:
virtual void OnBody(const char * a_Data, int a_Size) override;
virtual void OnBody(const char * a_Data, size_t a_Size) override;
// cHTTPFormParser::cCallbacks overrides. Files are ignored:
virtual void OnFileStart(cHTTPFormParser &, const AString & a_FileName) override
{
UNUSED(a_FileName);
}
virtual void OnFileData(cHTTPFormParser &, const char * a_Data, int a_Size) override
virtual void OnFileData(cHTTPFormParser &, const char * a_Data, size_t a_Size) override
{
UNUSED(a_Data);
UNUSED(a_Size);
@ -216,7 +216,7 @@ protected:
// cHTTPServer::cCallbacks overrides:
virtual void OnRequestBegun (cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, int a_Size) override;
virtual void OnRequestBody (cHTTPConnection & a_Connection, cHTTPRequest & a_Request, const char * a_Data, size_t a_Size) override;
virtual void OnRequestFinished(cHTTPConnection & a_Connection, cHTTPRequest & a_Request) override;
} ; // tolua_export