mirror of
https://github.com/cuberite/cuberite.git
synced 2025-01-07 03:16:55 +08:00
Renamed HTTPServer folder to HTTP.
It contains client code as well.
This commit is contained in:
parent
fce68dc8f3
commit
fea556ca1b
@ -36,7 +36,7 @@
|
||||
#include "../StringCompression.h"
|
||||
#include "../CommandOutput.h"
|
||||
#include "../BuildInfo.h"
|
||||
#include "../HTTPServer/UrlParser.h"
|
||||
#include "../HTTP/UrlParser.h"
|
||||
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/polarssl/include
|
||||
include_directories (SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/../lib/libevent/include")
|
||||
|
||||
set(FOLDERS
|
||||
OSSupport HTTPServer Items Blocks Protocol Generating PolarSSL++ Bindings
|
||||
OSSupport HTTP Items Blocks Protocol Generating PolarSSL++ Bindings
|
||||
WorldStorage Mobs Entities Simulator Simulator/IncrementalRedstoneSimulator
|
||||
BlockEntities UI Noise
|
||||
)
|
||||
|
@ -13,6 +13,7 @@
|
||||
cHTTPResponseParser::cHTTPResponseParser(cHTTPResponseParser::cCallbacks & a_Callbacks):
|
||||
Super(mkResponse),
|
||||
m_Callbacks(a_Callbacks),
|
||||
m_HasHadError(false),
|
||||
m_IsInHeaders(true),
|
||||
m_IsFinished(false),
|
||||
m_EnvelopeParser(*this)
|
||||
@ -56,7 +57,7 @@ size_t cHTTPResponseParser::Parse(const char * a_Data, size_t a_Size)
|
||||
if (!m_Buffer.empty())
|
||||
{
|
||||
// Headers finished and there's still data left in the buffer, process it as message body:
|
||||
m_IsInHeaders = false;
|
||||
HeadersFinished();
|
||||
return ParseBody(m_Buffer.data(), m_Buffer.size());
|
||||
}
|
||||
return 0;
|
||||
@ -132,6 +133,10 @@ void cHTTPResponseParser::HeadersFinished(void)
|
||||
{
|
||||
m_TransferEncodingParser = cTransferEncodingParser::Create(*this, "identity", m_ContentLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_TransferEncodingParser = cTransferEncodingParser::Create(*this, transferEncoding->second, m_ContentLength);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -169,6 +174,7 @@ void cHTTPResponseParser::OnBodyData(const void * a_Data, size_t a_Size)
|
||||
|
||||
void cHTTPResponseParser::OnBodyFinished(void)
|
||||
{
|
||||
m_IsFinished = true;
|
||||
m_Callbacks.OnBodyFinished();
|
||||
}
|
||||
|
393
src/HTTP/TransferEncodingParser.cpp
Normal file
393
src/HTTP/TransferEncodingParser.cpp
Normal file
@ -0,0 +1,393 @@
|
||||
|
||||
// TransferEncodingParser.cpp
|
||||
|
||||
// Implements the cTransferEncodingParser class and its descendants representing the parser for the various transfer encodings (chunked etc.)
|
||||
|
||||
#include "Globals.h"
|
||||
#include "TransferEncodingParser.h"
|
||||
#include "EnvelopeParser.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cChunkedTEParser:
|
||||
|
||||
class cChunkedTEParser:
|
||||
public cTransferEncodingParser,
|
||||
public cEnvelopeParser::cCallbacks
|
||||
{
|
||||
typedef cTransferEncodingParser Super;
|
||||
|
||||
public:
|
||||
cChunkedTEParser(Super::cCallbacks & a_Callbacks):
|
||||
Super(a_Callbacks),
|
||||
m_State(psChunkLength),
|
||||
m_ChunkDataLengthLeft(0),
|
||||
m_TrailerParser(*this)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
enum eState
|
||||
{
|
||||
psChunkLength, ///< Parsing the chunk length hex number
|
||||
psChunkLengthTrailer, ///< Any trailer (chunk extension) specified after the chunk length
|
||||
psChunkLengthLF, ///< The LF character after the CR character terminating the chunk length
|
||||
psChunkData, ///< Relaying chunk data
|
||||
psChunkDataCR, ///< Skipping the extra CR character after chunk data
|
||||
psChunkDataLF, ///< Skipping the extra LF character after chunk data
|
||||
psTrailer, ///< Received an empty chunk, parsing the trailer (through the envelope parser)
|
||||
psFinished, ///< The parser has finished parsing, either successfully or with an error
|
||||
};
|
||||
|
||||
/** The current state of the parser (parsing chunk length / chunk data). */
|
||||
eState m_State;
|
||||
|
||||
/** Number of bytes that still belong to the chunk currently being parsed.
|
||||
When in psChunkLength, the value is the currently parsed length digits. */
|
||||
size_t m_ChunkDataLengthLeft;
|
||||
|
||||
cEnvelopeParser m_TrailerParser;
|
||||
|
||||
|
||||
/** Calls the OnError callback and sets parser state to finished. */
|
||||
void Error(const AString & a_ErrorMsg)
|
||||
{
|
||||
m_State = psFinished;
|
||||
m_Callbacks.OnError(a_ErrorMsg);
|
||||
}
|
||||
|
||||
|
||||
/** Parses the incoming data, the current state is psChunkLength.
|
||||
Stops parsing when either the chunk length has been read, or there is no more data in the input.
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error handler). */
|
||||
size_t ParseChunkLength(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
// Expected input: <hexnumber>[;<trailer>]<CR><LF>
|
||||
// Only the hexnumber is parsed into m_ChunkDataLengthLeft, the rest is postponed into psChunkLengthTrailer or psChunkLengthLF
|
||||
for (size_t i = 0; i < a_Size; i++)
|
||||
{
|
||||
switch (a_Data[i])
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
{
|
||||
m_ChunkDataLengthLeft = m_ChunkDataLengthLeft * 16 + static_cast<decltype(m_ChunkDataLengthLeft)>(a_Data[i] - '0');
|
||||
break;
|
||||
}
|
||||
case 'a':
|
||||
case 'b':
|
||||
case 'c':
|
||||
case 'd':
|
||||
case 'e':
|
||||
case 'f':
|
||||
{
|
||||
m_ChunkDataLengthLeft = m_ChunkDataLengthLeft * 16 + static_cast<decltype(m_ChunkDataLengthLeft)>(a_Data[i] - 'a' + 10);
|
||||
break;
|
||||
}
|
||||
case 'A':
|
||||
case 'B':
|
||||
case 'C':
|
||||
case 'D':
|
||||
case 'E':
|
||||
case 'F':
|
||||
{
|
||||
m_ChunkDataLengthLeft = m_ChunkDataLengthLeft * 16 + static_cast<decltype(m_ChunkDataLengthLeft)>(a_Data[i] - 'A' + 10);
|
||||
break;
|
||||
}
|
||||
case '\r':
|
||||
{
|
||||
m_State = psChunkLengthLF;
|
||||
return i + 1;
|
||||
}
|
||||
case ';':
|
||||
{
|
||||
m_State = psChunkLengthTrailer;
|
||||
return i + 1;
|
||||
}
|
||||
default:
|
||||
{
|
||||
Error(Printf("Invalid character in chunk length line: 0x%x", a_Data[i]));
|
||||
return AString::npos;
|
||||
}
|
||||
} // switch (a_Data[i])
|
||||
} // for i - a_Data[]
|
||||
return a_Size;
|
||||
}
|
||||
|
||||
|
||||
/** Parses the incoming data, the current state is psChunkLengthTrailer.
|
||||
Stops parsing when either the chunk length trailer has been read, or there is no more data in the input.
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error handler). */
|
||||
size_t ParseChunkLengthTrailer(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
// Expected input: <trailer><CR><LF>
|
||||
// The LF itself is not parsed, it is instead postponed into psChunkLengthLF
|
||||
for (size_t i = 0; i < a_Size; i++)
|
||||
{
|
||||
switch (a_Data[i])
|
||||
{
|
||||
case '\r':
|
||||
{
|
||||
m_State = psChunkLengthLF;
|
||||
return i;
|
||||
}
|
||||
default:
|
||||
{
|
||||
if (a_Data[i] < 32)
|
||||
{
|
||||
// Only printable characters are allowed in the trailer
|
||||
Error(Printf("Invalid character in chunk length line: 0x%x", a_Data[i]));
|
||||
return AString::npos;
|
||||
}
|
||||
}
|
||||
} // switch (a_Data[i])
|
||||
} // for i - a_Data[]
|
||||
return a_Size;
|
||||
}
|
||||
|
||||
|
||||
/** Parses the incoming data, the current state is psChunkLengthLF.
|
||||
Only the LF character is expected, if found, moves to psChunkData, otherwise issues an error.
|
||||
If the chunk length that just finished reading is equal to 0, signals the end of stream (via psTrailer).
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error handler). */
|
||||
size_t ParseChunkLengthLF(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
// Expected input: <LF>
|
||||
if (a_Size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (a_Data[0] == '\n')
|
||||
{
|
||||
if (m_ChunkDataLengthLeft == 0)
|
||||
{
|
||||
m_State = psTrailer;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_State = psChunkData;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
Error(Printf("Invalid character past chunk length's CR: 0x%x", a_Data[0]));
|
||||
return AString::npos;
|
||||
}
|
||||
|
||||
|
||||
/** Consumes as much chunk data from the input as possible.
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error() handler). */
|
||||
size_t ParseChunkData(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
ASSERT(m_ChunkDataLengthLeft > 0);
|
||||
auto bytes = std::min(a_Size, m_ChunkDataLengthLeft);
|
||||
m_ChunkDataLengthLeft -= bytes;
|
||||
m_Callbacks.OnBodyData(a_Data, bytes);
|
||||
if (m_ChunkDataLengthLeft == 0)
|
||||
{
|
||||
m_State = psChunkDataCR;
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
/** Parses the incoming data, the current state is psChunkDataCR.
|
||||
Only the CR character is expected, if found, moves to psChunkDataLF, otherwise issues an error.
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error handler). */
|
||||
size_t ParseChunkDataCR(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
// Expected input: <CR>
|
||||
if (a_Size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (a_Data[0] == '\r')
|
||||
{
|
||||
m_State = psChunkDataLF;
|
||||
return 1;
|
||||
}
|
||||
Error(Printf("Invalid character past chunk data: 0x%x", a_Data[0]));
|
||||
return AString::npos;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** Parses the incoming data, the current state is psChunkDataCR.
|
||||
Only the CR character is expected, if found, moves to psChunkDataLF, otherwise issues an error.
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error handler). */
|
||||
size_t ParseChunkDataLF(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
// Expected input: <LF>
|
||||
if (a_Size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if (a_Data[0] == '\n')
|
||||
{
|
||||
m_State = psChunkLength;
|
||||
return 1;
|
||||
}
|
||||
Error(Printf("Invalid character past chunk data's CR: 0x%x", a_Data[0]));
|
||||
return AString::npos;
|
||||
}
|
||||
|
||||
|
||||
/** Parses the incoming data, the current state is psChunkDataCR.
|
||||
The trailer is normally a set of "Header: Value" lines, terminated by an empty line. Use the m_TrailerParser for that.
|
||||
Returns the number of bytes consumed from the input, or AString::npos on error (calls the Error handler). */
|
||||
size_t ParseTrailer(const char * a_Data, size_t a_Size)
|
||||
{
|
||||
auto res = m_TrailerParser.Parse(a_Data, a_Size);
|
||||
if (res == AString::npos)
|
||||
{
|
||||
Error("Error while parsing the trailer");
|
||||
}
|
||||
if ((res < a_Size) || !m_TrailerParser.IsInHeaders())
|
||||
{
|
||||
m_Callbacks.OnBodyFinished();
|
||||
m_State = psFinished;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// cTransferEncodingParser overrides:
|
||||
virtual size_t Parse(const char * a_Data, size_t a_Size) override
|
||||
{
|
||||
while ((a_Size > 0) && (m_State != psFinished))
|
||||
{
|
||||
size_t consumed = 0;
|
||||
switch (m_State)
|
||||
{
|
||||
case psChunkLength: consumed = ParseChunkLength (a_Data, a_Size); break;
|
||||
case psChunkLengthTrailer: consumed = ParseChunkLengthTrailer(a_Data, a_Size); break;
|
||||
case psChunkLengthLF: consumed = ParseChunkLengthLF (a_Data, a_Size); break;
|
||||
case psChunkData: consumed = ParseChunkData (a_Data, a_Size); break;
|
||||
case psChunkDataCR: consumed = ParseChunkDataCR (a_Data, a_Size); break;
|
||||
case psChunkDataLF: consumed = ParseChunkDataLF (a_Data, a_Size); break;
|
||||
case psTrailer: consumed = ParseTrailer (a_Data, a_Size); break;
|
||||
case psFinished: consumed = 0; break; // Not supposed to happen, but Clang complains without it
|
||||
}
|
||||
if (consumed == AString::npos)
|
||||
{
|
||||
return AString::npos;
|
||||
}
|
||||
a_Data += consumed;
|
||||
a_Size -= consumed;
|
||||
}
|
||||
return a_Size;
|
||||
}
|
||||
|
||||
virtual void Finish(void) override
|
||||
{
|
||||
if (m_State != psFinished)
|
||||
{
|
||||
Error(Printf("ChunkedTransferEncoding: Finish signal received before the data stream ended (state: %d)", m_State));
|
||||
}
|
||||
m_State = psFinished;
|
||||
}
|
||||
|
||||
|
||||
// cEnvelopeParser::cCallbacks overrides:
|
||||
virtual void OnHeaderLine(const AString & a_Key, const AString & a_Value) override
|
||||
{
|
||||
// Ignored
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cIdentityTEParser:
|
||||
|
||||
class cIdentityTEParser:
|
||||
public cTransferEncodingParser
|
||||
{
|
||||
typedef cTransferEncodingParser Super;
|
||||
|
||||
public:
|
||||
cIdentityTEParser(cCallbacks & a_Callbacks, size_t a_ContentLength):
|
||||
Super(a_Callbacks),
|
||||
m_BytesLeft(a_ContentLength)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/** How many bytes of content are left before the message ends. */
|
||||
size_t m_BytesLeft;
|
||||
|
||||
// cTransferEncodingParser overrides:
|
||||
virtual size_t Parse(const char * a_Data, size_t a_Size) override
|
||||
{
|
||||
auto size = std::min(a_Size, m_BytesLeft);
|
||||
if (size > 0)
|
||||
{
|
||||
m_Callbacks.OnBodyData(a_Data, size);
|
||||
}
|
||||
m_BytesLeft -= size;
|
||||
if (m_BytesLeft == 0)
|
||||
{
|
||||
m_Callbacks.OnBodyFinished();
|
||||
}
|
||||
return a_Size - size;
|
||||
}
|
||||
|
||||
virtual void Finish(void) override
|
||||
{
|
||||
if (m_BytesLeft > 0)
|
||||
{
|
||||
m_Callbacks.OnError("IdentityTransferEncoding: body was truncated");
|
||||
}
|
||||
else
|
||||
{
|
||||
// BodyFinished has already been called, just bail out
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cTransferEncodingParser:
|
||||
|
||||
cTransferEncodingParserPtr cTransferEncodingParser::Create(
|
||||
cCallbacks & a_Callbacks,
|
||||
const AString & a_TransferEncoding,
|
||||
size_t a_ContentLength
|
||||
)
|
||||
{
|
||||
if (a_TransferEncoding == "chunked")
|
||||
{
|
||||
return std::make_shared<cChunkedTEParser>(a_Callbacks);
|
||||
}
|
||||
if (a_TransferEncoding == "identity")
|
||||
{
|
||||
return std::make_shared<cIdentityTEParser>(a_Callbacks, a_ContentLength);
|
||||
}
|
||||
if (a_TransferEncoding.empty())
|
||||
{
|
||||
return std::make_shared<cIdentityTEParser>(a_Callbacks, a_ContentLength);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -1,132 +0,0 @@
|
||||
|
||||
// TransferEncodingParser.cpp
|
||||
|
||||
// Implements the cTransferEncodingParser class and its descendants representing the parser for the various transfer encodings (chunked etc.)
|
||||
|
||||
#include "Globals.h"
|
||||
#include "TransferEncodingParser.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cChunkedTEParser:
|
||||
|
||||
class cChunkedTEParser:
|
||||
public cTransferEncodingParser
|
||||
{
|
||||
typedef cTransferEncodingParser Super;
|
||||
|
||||
public:
|
||||
cChunkedTEParser(cCallbacks & a_Callbacks):
|
||||
Super(a_Callbacks),
|
||||
m_IsFinished(false)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
|
||||
/** True if the datastream has finished (zero-length chunk received). */
|
||||
bool m_IsFinished;
|
||||
|
||||
|
||||
// cTransferEncodingParser overrides:
|
||||
virtual size_t Parse(const char * a_Data, size_t a_Size) override
|
||||
{
|
||||
// TODO
|
||||
m_Callbacks.OnError("cChunkedTEParser not implemented yet");
|
||||
return AString::npos;
|
||||
}
|
||||
|
||||
virtual void Finish(void) override
|
||||
{
|
||||
if (!m_IsFinished)
|
||||
{
|
||||
m_Callbacks.OnError("ChunkedTransferEncoding: Finish signal received before the data stream ended");
|
||||
}
|
||||
m_IsFinished = true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cIdentityTEParser:
|
||||
|
||||
class cIdentityTEParser:
|
||||
public cTransferEncodingParser
|
||||
{
|
||||
typedef cTransferEncodingParser Super;
|
||||
|
||||
public:
|
||||
cIdentityTEParser(cCallbacks & a_Callbacks, size_t a_ContentLength):
|
||||
Super(a_Callbacks),
|
||||
m_BytesLeft(a_ContentLength)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
protected:
|
||||
/** How many bytes of content are left before the message ends. */
|
||||
size_t m_BytesLeft;
|
||||
|
||||
// cTransferEncodingParser overrides:
|
||||
virtual size_t Parse(const char * a_Data, size_t a_Size) override
|
||||
{
|
||||
auto size = std::min(a_Size, m_BytesLeft);
|
||||
if (size > 0)
|
||||
{
|
||||
m_Callbacks.OnBodyData(a_Data, size);
|
||||
}
|
||||
m_BytesLeft -= size;
|
||||
if (m_BytesLeft == 0)
|
||||
{
|
||||
m_Callbacks.OnBodyFinished();
|
||||
}
|
||||
return a_Size - size;
|
||||
}
|
||||
|
||||
virtual void Finish(void) override
|
||||
{
|
||||
if (m_BytesLeft > 0)
|
||||
{
|
||||
m_Callbacks.OnError("IdentityTransferEncoding: body was truncated");
|
||||
}
|
||||
else
|
||||
{
|
||||
// BodyFinished has already been called, just bail out
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// cTransferEncodingParser:
|
||||
|
||||
cTransferEncodingParserPtr cTransferEncodingParser::Create(
|
||||
cCallbacks & a_Callbacks,
|
||||
const AString & a_TransferEncoding,
|
||||
size_t a_ContentLength
|
||||
)
|
||||
{
|
||||
if (a_TransferEncoding == "chunked")
|
||||
{
|
||||
return std::make_shared<cChunkedTEParser>(a_Callbacks);
|
||||
}
|
||||
if (a_TransferEncoding.empty())
|
||||
{
|
||||
return std::make_shared<cIdentityTEParser>(a_Callbacks, a_ContentLength);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
|
||||
#include "Protocol/Authenticator.h"
|
||||
#include "Protocol/MojangAPI.h"
|
||||
#include "HTTPServer/HTTPServer.h"
|
||||
#include "HTTP/HTTPServer.h"
|
||||
#include "Defines.h"
|
||||
#include "RankManager.h"
|
||||
#include <thread>
|
||||
|
@ -12,8 +12,8 @@
|
||||
#include "Server.h"
|
||||
#include "Root.h"
|
||||
|
||||
#include "HTTPServer/HTTPRequestParser.h"
|
||||
#include "HTTPServer/HTTPServerConnection.h"
|
||||
#include "HTTP/HTTPRequestParser.h"
|
||||
#include "HTTP/HTTPServerConnection.h"
|
||||
|
||||
|
||||
|
||||
|
@ -7,8 +7,8 @@
|
||||
|
||||
#include "Bindings/LuaState.h"
|
||||
#include "IniFile.h"
|
||||
#include "HTTPServer/HTTPServer.h"
|
||||
#include "HTTPServer/HTTPFormParser.h"
|
||||
#include "HTTP/HTTPServer.h"
|
||||
#include "HTTP/HTTPFormParser.h"
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user