Cuberite
A lightweight, fast and extensible game server for Minecraft
HTTPServerConnection.cpp
Go to the documentation of this file.
1 
2 // HTTPConnection.cpp
3 
4 // Implements the cHTTPServerConnection class representing a single persistent connection in the HTTP server.
5 
6 #include "Globals.h"
7 #include "HTTPServerConnection.h"
8 #include "HTTPMessage.h"
9 #include "HTTPServer.h"
10 
11 
12 
13 
14 
16  m_HTTPServer(a_HTTPServer),
17  m_Parser(*this)
18 {
19 }
20 
21 
22 
23 
24 
26 
27 
28 
29 
30 
31 void cHTTPServerConnection::SendStatusAndReason(int a_StatusCode, const AString & a_Response)
32 {
33  SendData(fmt::format(FMT_STRING("HTTP/1.1 {} {}\r\n"), a_StatusCode, a_Response));
34  SendData(fmt::format(FMT_STRING("Content-Length: {}\r\n\r\n"), a_Response));
35  SendData(a_Response.data(), a_Response.size());
36  m_CurrentRequest.reset();
37  m_Parser.Reset();
38 }
39 
40 
41 
42 
43 
45 {
46  SendData(fmt::format(FMT_STRING("HTTP/1.1 401 Unauthorized\r\nWWW-Authenticate: Basic realm=\"{}\"\r\nContent-Length: 0\r\n\r\n"), a_Realm));
47  m_CurrentRequest.reset();
48  m_Parser.Reset();
49 }
50 
51 
52 
53 
54 
56 {
57  ASSERT(m_CurrentRequest != nullptr);
58  AString toSend;
59  a_Response.AppendToData(toSend);
60  SendData(toSend);
61 }
62 
63 
64 
65 
66 
67 void cHTTPServerConnection::Send(const void * a_Data, size_t a_Size)
68 {
69  ASSERT(m_CurrentRequest != nullptr);
70  // We're sending in Chunked transfer encoding
71  SendData(fmt::format("{0:x}\r\n", a_Size));
72  SendData(a_Data, a_Size);
73  SendData("\r\n");
74 }
75 
76 
77 
78 
79 
81 {
82  ASSERT(m_CurrentRequest != nullptr);
83  SendData("0\r\n\r\n");
84  m_CurrentRequest.reset();
85  m_Parser.Reset();
86 }
87 
88 
89 
90 
91 
93 {
94  if (m_CurrentRequest != nullptr)
95  {
97  }
98  m_Link->Close(); // Terminate the connection
99  m_Link.reset();
100 }
101 
102 
103 
104 
105 
107 {
108  ASSERT(m_Link == nullptr);
109  m_Link = a_Link;
110 }
111 
112 
113 
114 
115 
116 void cHTTPServerConnection::OnReceivedData(const char * a_Data, size_t a_Size)
117 {
118  ASSERT(m_Link != nullptr);
119 
120  m_Parser.Parse(a_Data, a_Size);
121 }
122 
123 
124 
125 
126 
128 {
129  if (m_CurrentRequest != nullptr)
130  {
132  }
133  m_Link.reset();
134 }
135 
136 
137 
138 
139 
140 void cHTTPServerConnection::OnError(int a_ErrorCode, const AString & a_ErrorMsg)
141 {
142  OnRemoteClosed();
143 }
144 
145 
146 
147 
148 
149 void cHTTPServerConnection::OnError(const AString & a_ErrorDescription)
150 {
151  Terminate(); // HTTP data malformed, disconnect
152 }
153 
154 
155 
156 
157 
159 {
160  const auto Split = StringSplit(a_FirstLine, " ");
161  if (Split.size() < 2)
162  {
163  // Invalid request line. We need at least the Method and URL:
164  Terminate();
165  return;
166  }
167 
168  // Create a new request object for this request:
169  m_CurrentRequest = std::make_unique<cHTTPIncomingRequest>(Split[0], Split[1]);
170 }
171 
172 
173 
174 
175 
176 void cHTTPServerConnection::OnHeaderLine(const AString & a_Key, const AString & a_Value)
177 {
178  if (m_CurrentRequest == nullptr)
179  {
180  return;
181  }
182  m_CurrentRequest->AddHeader(a_Key, a_Value);
183 }
184 
185 
186 
187 
188 
190 {
191  if (m_CurrentRequest == nullptr)
192  {
193  return;
194  }
196 }
197 
198 
199 
200 
201 
202 void cHTTPServerConnection::OnBodyData(const void * a_Data, size_t a_Size)
203 {
204  if (m_CurrentRequest == nullptr)
205  {
206  return;
207  }
208  m_HTTPServer.RequestBody(*this, *m_CurrentRequest, a_Data, a_Size);
209 }
210 
211 
212 
213 
214 
216 {
217  // Process the request:
218  if (m_CurrentRequest != nullptr)
219  {
221  }
222 
223  // ...and reset:
224  m_CurrentRequest.reset();
225  m_Parser.Reset();
226 }
227 
228 
229 
230 
231 
232 void cHTTPServerConnection::SendData(const void * a_Data, size_t a_Size)
233 {
234  m_Link->Send(a_Data, a_Size);
235 }
#define ASSERT(x)
Definition: Globals.h:276
std::shared_ptr< cTCPLink > cTCPLinkPtr
Definition: Network.h:25
AStringVector StringSplit(const AString &str, const AString &delim)
Split the string at any of the listed delimiters.
Definition: StringUtils.cpp:55
std::string AString
Definition: StringUtils.h:11
Stores outgoing response headers and serializes them to an HTTP data stream.
Definition: HTTPMessage.h:71
void AppendToData(AString &a_DataStream) const
Appends the response to the specified datastream - response line and headers.
Definition: HTTPMessage.cpp:81
void Reset(void)
Resets the parser to the initial state, so that a new request can be parsed.
size_t Parse(const char *a_Data, size_t a_Size)
Parses the incoming data and calls the appropriate callbacks.
void NewRequest(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request)
Called by cHTTPServerConnection when it finishes parsing the request header.
Definition: HTTPServer.cpp:208
void RequestBody(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request, const void *a_Data, size_t a_Size)
Called by cHTTPConenction when it receives more data for the request body.
Definition: HTTPServer.cpp:217
void RequestFinished(cHTTPServerConnection &a_Connection, cHTTPIncomingRequest &a_Request)
Called by cHTTPServerConnection when it detects that the request has finished (all of its body has be...
Definition: HTTPServer.cpp:226
virtual void OnFirstLine(const AString &a_FirstLine) override
Called when the first line of the request or response is fully parsed.
cTCPLinkPtr m_Link
The network link attached to this connection.
cHTTPServerConnection(cHTTPServer &a_HTTPServer)
Creates a new instance, connected to the specified HTTP server instance.
virtual void OnHeadersFinished(void) override
Called when all the headers have been parsed.
void Terminate(void)
Terminates the connection; finishes any request being currently processed.
virtual void OnBodyFinished(void) override
Called when the entire body has been reported by OnBodyData().
virtual void OnBodyData(const void *a_Data, size_t a_Size) override
Called for each chunk of the incoming body data.
cHTTPMessageParser m_Parser
The parser responsible for reading the requests.
void SendNeedAuth(const AString &a_Realm)
Sends the "401 unauthorized" reply together with instructions on authorizing, using the specified rea...
virtual ~cHTTPServerConnection() override
virtual void OnRemoteClosed(void) override
The socket has been closed for any reason.
cHTTPServer & m_HTTPServer
The parent webserver that is to be notified of events on this connection.
virtual void OnHeaderLine(const AString &a_Key, const AString &a_Value) override
Called when a single header line is parsed.
void FinishResponse(void)
Indicates that the current response is finished, gets ready for receiving another request (HTTP 1....
virtual void OnError(int a_ErrorCode, const AString &a_ErrorMsg) override
An error has occurred on the socket.
virtual void OnReceivedData(const char *a_Data, size_t a_Size) override
Data is received from the client.
std::unique_ptr< cHTTPIncomingRequest > m_CurrentRequest
The request being currently received Valid only between having parsed the headers and finishing recei...
void SendStatusAndReason(int a_StatusCode, const AString &a_Reason)
Sends HTTP status code together with a_Reason (used for HTTP errors).
virtual void OnLinkCreated(cTCPLinkPtr a_Link) override
The link instance has been created, remember it.
void Send(const cHTTPOutgoingResponse &a_Response)
Sends the headers contained in a_Response.
virtual void SendData(const void *a_Data, size_t a_Size)
Called to send raw data over the link.