SLikeNet 0.1.3

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
HTTPConnection.cpp
Go to the documentation of this file.
1 /*
2 * Original work: Copyright (c) 2014, Oculus VR, Inc.
3 * All rights reserved.
4 *
5 * This source code is licensed under the BSD-style license found in the
6 * RakNet License.txt file in the licenses directory of this source tree. An additional grant
7 * of patent rights can be found in the RakNet Patents.txt file in the same directory.
8 *
9 *
10 * Modified work: Copyright (c) 2017, SLikeSoft UG (haftungsbeschränkt)
11 *
12 * This source code was modified by SLikeSoft. Modifications are licensed under the MIT-style
13 * license found in the license.txt file in the root directory of this source tree.
14 */
15
19
20 #include "slikenet/NativeFeatureIncludes.h"
21 #if _RAKNET_SUPPORT_HTTPConnection==1 && _RAKNET_SUPPORT_TCPInterface==1
22
23 #include "slikenet/TCPInterface.h"
24 #include "slikenet/HTTPConnection.h"
25 #include "slikenet/sleep.h"
26 #include "slikenet/string.h"
27 #include "slikenet/assert.h"
28 #include <string.h>
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32
33 using namespace SLNet;
34
35 STATIC_FACTORY_DEFINITIONS(HTTPConnection,HTTPConnection);
36
37 HTTPConnection::HTTPConnection() : connectionState(CS_NONE)
38 {
39 tcp=0;
40 }
41
42 void HTTPConnection::Init(TCPInterface* _tcp, const char *_host, unsigned short _port)
43 {
44 tcp=_tcp;
45 host=_host;
46 port=_port;
47 }
48
49 void HTTPConnection::Post(const char *remote_path, const char *data, const char *_contentType)
50 {
51 OutgoingCommand op;
52 op.contentType=_contentType;
53 op.data=data;
54 op.remotePath=remote_path;
55 op.isPost=true;
56 outgoingCommand.Push(op, _FILE_AND_LINE_ );
57 //printf("Adding outgoing post\n");
58 }
59
60 void HTTPConnection::Get(const char *path)
61 {
62 OutgoingCommand op;
63 op.remotePath=path;
64 op.isPost=false;
65 outgoingCommand.Push(op, _FILE_AND_LINE_ );
66 }
67
68 bool HTTPConnection::HasBadResponse(int *code, SLNet::RakString *data)
69 {
70 if(badResponses.IsEmpty())
71 return false;
72
73 if (code)
74 *code = badResponses.Peek().code;
75 if (data)
76 *data = badResponses.Pop().data;
77 return true;
78 }
79 void HTTPConnection::CloseConnection()
80 {
81 connectionState=CS_DISCONNECTING;
82 }
83 void HTTPConnection::Update(void)
84 {
85 SystemAddress sa;
86 sa = tcp->HasCompletedConnectionAttempt();
87 while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
88 {
89 // printf("Connected\n");
90 connectionState=CS_CONNECTED;
91 server=sa;
92 sa = tcp->HasCompletedConnectionAttempt();
93 }
94
95 sa = tcp->HasFailedConnectionAttempt();
96 while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
97 {
98 //printf("Failed connected\n");
99 CloseConnection();
100 sa = tcp->HasFailedConnectionAttempt();
101 }
102
103 sa = tcp->HasLostConnection();
104 while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
105 {
106 //printf("Lost connection\n");
107 CloseConnection();
108 sa = tcp->HasLostConnection();
109 }
110
111
112 switch (connectionState)
113 {
114 case CS_NONE:
115 {
116 if (outgoingCommand.IsEmpty())
117 return;
118
119 //printf("Connecting\n");
120 server = tcp->Connect(host, port, false);
121 connectionState = CS_CONNECTING;
122 }
123 break;
124 case CS_DISCONNECTING:
125 {
126 if (tcp->ReceiveHasPackets()==false)
127 {
128 if (incomingData.IsEmpty()==false)
129 {
130 results.Push(incomingData, _FILE_AND_LINE_ );
131 }
132 incomingData.Clear();
133 tcp->CloseConnection(server);
134 connectionState=CS_NONE;
135 }
136 }
137 break;
138 case CS_CONNECTING:
139 {
140 }
141 break;
142 case CS_CONNECTED:
143 {
144 //printf("Connected\n");
145 if (outgoingCommand.IsEmpty())
146 {
147 //printf("Closed connection (nothing to do)\n");
148 CloseConnection();
149 return;
150 }
151
152 #if OPEN_SSL_CLIENT_SUPPORT==1
153 tcp->StartSSLClient(server);
154 #endif
155
156 //printf("Sending request\n");
157 currentProcessingCommand = outgoingCommand.Pop();
158 RakString request;
159 if (currentProcessingCommand.isPost)
160 {
161 request.Set("POST %s HTTP/1.0\r\n"
162 "Host: %s:%i\r\n"
163 "Content-Type: %s\r\n"
164 "Content-Length: %u\r\n"
165 "\r\n"
166 "%s",
167 currentProcessingCommand.remotePath.C_String(),
168 host.C_String(),
169 port,
170 currentProcessingCommand.contentType.C_String(),
171 (unsigned) currentProcessingCommand.data.GetLength(),
172 currentProcessingCommand.data.C_String());
173 }
174 else
175 {
176 // request.Set("GET %s\r\n", host.C_String());
177 // http://www.jenkinssoftware.com/forum/index.php?topic=4601.0;topicseen
178 request.Set("GET %s HTTP/1.0\r\n"
179 "Host: %s:%i\r\n"
180 "\r\n",
181 currentProcessingCommand.remotePath.C_String(),
182 host.C_String(),
183 port);
184 }
185
186 // printf(request.C_String());
187 // request.URLEncode();
188 tcp->Send(request.C_String(), (unsigned int) request.GetLength(), server,false);
189 connectionState=CS_PROCESSING;
190 }
191 break;
192 case CS_PROCESSING:
193 {
194 }
195 }
196
197 // if (connectionState==CS_PROCESSING && currentProcessingCommand.data.IsEmpty()==false)
198 // outgoingCommand.PushAtHead(currentProcessingCommand);
199 }
200 bool HTTPConnection::HasRead(void) const
201 {
202 return results.IsEmpty()==false;
203 }
204 RakString HTTPConnection::Read(void)
205 {
206 if (results.IsEmpty())
207 return RakString();
208
209 SLNet::RakString resultStr = results.Pop();
210 // const char *start_of_body = strstr(resultStr.C_String(), "\r\n\r\n");
211 const char *start_of_body = strpbrk(resultStr.C_String(), "\001\002\003%");
212
213 if(start_of_body)
214 return SLNet::RakString::NonVariadic(start_of_body);
215 else
216 return resultStr;
217 }
218 SystemAddress HTTPConnection::GetServerAddress(void) const
219 {
220 return server;
221 }
222 void HTTPConnection::ProcessTCPPacket(Packet *packet)
223 {
224 RakAssert(packet);
225
226 // read all the packets possible
227 if(packet->systemAddress == server)
228 {
229 if(incomingData.GetLength() == 0)
230 {
231 int response_code = atoi((char *)packet->data + strlen("HTTP/1.0 "));
232
233 if(response_code > 299)
234 {
235 badResponses.Push(BadResponse(packet->data, response_code), _FILE_AND_LINE_ );
236 //printf("Closed connection (Bad response 2)\n");
237 CloseConnection();
238 return;
239 }
240 }
241
242 SLNet::RakString incomingTemp = SLNet::RakString::NonVariadic((const char*) packet->data);
243 incomingTemp.URLDecode();
244 incomingData += incomingTemp;
245
246 // printf((const char*) packet->data);
247 // printf("\n");
248
249 RakAssert(strlen((char *)packet->data) == packet->length); // otherwise it contains Null bytes
250
251 const char *start_of_body = strstr(incomingData, "\r\n\r\n");
252
253 // besides having the server close the connection, they may
254 // provide a length header and supply that many bytes
255 if(
256 // Why was start_of_body here? Makes the GET command fail
257 // start_of_body &&
258 connectionState == CS_PROCESSING)
259 {
260 /*
261 // The stupid programmer that wrote this originally didn't think that just because the header contains this value doesn't mean you got the whole message
262 if (strstr((const char*) packet->data, "\r\nConnection: close\r\n"))
263 {
264 CloseConnection();
265 }
266 else
267 {
268 */
269 long length_of_headers;
270 if (start_of_body)
271 {
272 length_of_headers = (long)(start_of_body + 4 - incomingData.C_String());
273 const char *length_header = strstr(incomingData, "\r\nLength: ");
274
275 if(length_header)
276 {
277 long length = atol(length_header + 10) + length_of_headers;
278
279 if((long) incomingData.GetLength() >= length)
280 {
281 //printf("Closed connection (Got all data due to length header)\n");
282 CloseConnection();
283 }
284 }
285 }
286 else
287 {
288 // No processing needed
289 }
290
291
292 //}
293 }
294 }
295 }
296
297 bool HTTPConnection::IsBusy(void) const
298 {
299 return connectionState != CS_NONE;
300 }
301
302 int HTTPConnection::GetState(void) const
303 {
304 return connectionState;
305 }
306
307
308 HTTPConnection::~HTTPConnection(void)
309 {
310 if (tcp)
311 tcp->CloseConnection(server);
312 }
313
314
315 #endif // _RAKNET_SUPPORT_*