HTTPConnection.cpp 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /*
  2. * 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. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. /// \file
  11. /// \brief Contains HTTPConnection, used to communicate with web servers
  12. ///
  13. #include "NativeFeatureIncludes.h"
  14. #if _RAKNET_SUPPORT_HTTPConnection==1 && _RAKNET_SUPPORT_TCPInterface==1
  15. #include "TCPInterface.h"
  16. #include "HTTPConnection.h"
  17. #include "RakSleep.h"
  18. #include "RakString.h"
  19. #include "RakAssert.h"
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. using namespace RakNet;
  25. STATIC_FACTORY_DEFINITIONS(HTTPConnection,HTTPConnection);
  26. HTTPConnection::HTTPConnection() : connectionState(CS_NONE)
  27. {
  28. tcp=0;
  29. }
  30. void HTTPConnection::Init(TCPInterface* _tcp, const char *_host, unsigned short _port)
  31. {
  32. tcp=_tcp;
  33. host=_host;
  34. port=_port;
  35. }
  36. void HTTPConnection::Post(const char *remote_path, const char *data, const char *_contentType)
  37. {
  38. OutgoingCommand op;
  39. op.contentType=_contentType;
  40. op.data=data;
  41. op.remotePath=remote_path;
  42. op.isPost=true;
  43. outgoingCommand.Push(op, _FILE_AND_LINE_ );
  44. //printf("Adding outgoing post\n");
  45. }
  46. void HTTPConnection::Get(const char *path)
  47. {
  48. OutgoingCommand op;
  49. op.remotePath=path;
  50. op.isPost=false;
  51. outgoingCommand.Push(op, _FILE_AND_LINE_ );
  52. }
  53. bool HTTPConnection::HasBadResponse(int *code, RakNet::RakString *data)
  54. {
  55. if(badResponses.IsEmpty())
  56. return false;
  57. if (code)
  58. *code = badResponses.Peek().code;
  59. if (data)
  60. *data = badResponses.Pop().data;
  61. return true;
  62. }
  63. void HTTPConnection::CloseConnection()
  64. {
  65. connectionState=CS_DISCONNECTING;
  66. }
  67. void HTTPConnection::Update(void)
  68. {
  69. SystemAddress sa;
  70. sa = tcp->HasCompletedConnectionAttempt();
  71. while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
  72. {
  73. // printf("Connected\n");
  74. connectionState=CS_CONNECTED;
  75. server=sa;
  76. sa = tcp->HasCompletedConnectionAttempt();
  77. }
  78. sa = tcp->HasFailedConnectionAttempt();
  79. while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
  80. {
  81. //printf("Failed connected\n");
  82. CloseConnection();
  83. sa = tcp->HasFailedConnectionAttempt();
  84. }
  85. sa = tcp->HasLostConnection();
  86. while (sa!=UNASSIGNED_SYSTEM_ADDRESS)
  87. {
  88. //printf("Lost connection\n");
  89. CloseConnection();
  90. sa = tcp->HasLostConnection();
  91. }
  92. switch (connectionState)
  93. {
  94. case CS_NONE:
  95. {
  96. if (outgoingCommand.IsEmpty())
  97. return;
  98. //printf("Connecting\n");
  99. server = tcp->Connect(host, port, false);
  100. connectionState = CS_CONNECTING;
  101. }
  102. break;
  103. case CS_DISCONNECTING:
  104. {
  105. if (tcp->ReceiveHasPackets()==false)
  106. {
  107. if (incomingData.IsEmpty()==false)
  108. {
  109. results.Push(incomingData, _FILE_AND_LINE_ );
  110. }
  111. incomingData.Clear();
  112. tcp->CloseConnection(server);
  113. connectionState=CS_NONE;
  114. }
  115. }
  116. break;
  117. case CS_CONNECTING:
  118. {
  119. }
  120. break;
  121. case CS_CONNECTED:
  122. {
  123. //printf("Connected\n");
  124. if (outgoingCommand.IsEmpty())
  125. {
  126. //printf("Closed connection (nothing to do)\n");
  127. CloseConnection();
  128. return;
  129. }
  130. #if OPEN_SSL_CLIENT_SUPPORT==1
  131. tcp->StartSSLClient(server);
  132. #endif
  133. //printf("Sending request\n");
  134. currentProcessingCommand = outgoingCommand.Pop();
  135. RakString request;
  136. if (currentProcessingCommand.isPost)
  137. {
  138. request.Set("POST %s HTTP/1.0\r\n"
  139. "Host: %s:%i\r\n"
  140. "Content-Type: %s\r\n"
  141. "Content-Length: %u\r\n"
  142. "\r\n"
  143. "%s",
  144. currentProcessingCommand.remotePath.C_String(),
  145. host.C_String(),
  146. port,
  147. currentProcessingCommand.contentType.C_String(),
  148. (unsigned) currentProcessingCommand.data.GetLength(),
  149. currentProcessingCommand.data.C_String());
  150. }
  151. else
  152. {
  153. // request.Set("GET %s\r\n", host.C_String());
  154. // http://www.jenkinssoftware.com/forum/index.php?topic=4601.0;topicseen
  155. request.Set("GET %s HTTP/1.0\r\n"
  156. "Host: %s:%i\r\n"
  157. "\r\n",
  158. currentProcessingCommand.remotePath.C_String(),
  159. host.C_String(),
  160. port);
  161. }
  162. // printf(request.C_String());
  163. // request.URLEncode();
  164. tcp->Send(request.C_String(), (unsigned int) request.GetLength(), server,false);
  165. connectionState=CS_PROCESSING;
  166. }
  167. break;
  168. case CS_PROCESSING:
  169. {
  170. }
  171. }
  172. // if (connectionState==CS_PROCESSING && currentProcessingCommand.data.IsEmpty()==false)
  173. // outgoingCommand.PushAtHead(currentProcessingCommand);
  174. }
  175. bool HTTPConnection::HasRead(void) const
  176. {
  177. return results.IsEmpty()==false;
  178. }
  179. RakString HTTPConnection::Read(void)
  180. {
  181. if (results.IsEmpty())
  182. return RakString();
  183. RakNet::RakString resultStr = results.Pop();
  184. // const char *start_of_body = strstr(resultStr.C_String(), "\r\n\r\n");
  185. const char *start_of_body = strpbrk(resultStr.C_String(), "\001\002\003%");
  186. if(start_of_body)
  187. return RakNet::RakString::NonVariadic(start_of_body);
  188. else
  189. return resultStr;
  190. }
  191. SystemAddress HTTPConnection::GetServerAddress(void) const
  192. {
  193. return server;
  194. }
  195. void HTTPConnection::ProcessTCPPacket(Packet *packet)
  196. {
  197. RakAssert(packet);
  198. // read all the packets possible
  199. if(packet->systemAddress == server)
  200. {
  201. if(incomingData.GetLength() == 0)
  202. {
  203. int response_code = atoi((char *)packet->data + strlen("HTTP/1.0 "));
  204. if(response_code > 299)
  205. {
  206. badResponses.Push(BadResponse(packet->data, response_code), _FILE_AND_LINE_ );
  207. //printf("Closed connection (Bad response 2)\n");
  208. CloseConnection();
  209. return;
  210. }
  211. }
  212. RakNet::RakString incomingTemp = RakNet::RakString::NonVariadic((const char*) packet->data);
  213. incomingTemp.URLDecode();
  214. incomingData += incomingTemp;
  215. // printf((const char*) packet->data);
  216. // printf("\n");
  217. RakAssert(strlen((char *)packet->data) == packet->length); // otherwise it contains Null bytes
  218. const char *start_of_body = strstr(incomingData, "\r\n\r\n");
  219. // besides having the server close the connection, they may
  220. // provide a length header and supply that many bytes
  221. if(
  222. // Why was start_of_body here? Makes the GET command fail
  223. // start_of_body &&
  224. connectionState == CS_PROCESSING)
  225. {
  226. /*
  227. // 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
  228. if (strstr((const char*) packet->data, "\r\nConnection: close\r\n"))
  229. {
  230. CloseConnection();
  231. }
  232. else
  233. {
  234. */
  235. long length_of_headers;
  236. if (start_of_body)
  237. {
  238. length_of_headers = (long)(start_of_body + 4 - incomingData.C_String());
  239. const char *length_header = strstr(incomingData, "\r\nLength: ");
  240. if(length_header)
  241. {
  242. long length = atol(length_header + 10) + length_of_headers;
  243. if((long) incomingData.GetLength() >= length)
  244. {
  245. //printf("Closed connection (Got all data due to length header)\n");
  246. CloseConnection();
  247. }
  248. }
  249. }
  250. else
  251. {
  252. // No processing needed
  253. }
  254. //}
  255. }
  256. }
  257. }
  258. bool HTTPConnection::IsBusy(void) const
  259. {
  260. return connectionState != CS_NONE;
  261. }
  262. int HTTPConnection::GetState(void) const
  263. {
  264. return connectionState;
  265. }
  266. HTTPConnection::~HTTPConnection(void)
  267. {
  268. if (tcp)
  269. tcp->CloseConnection(server);
  270. }
  271. #endif // _RAKNET_SUPPORT_*
粤ICP备19079148号