httpObject.cc 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2013 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "httpObject.h"
  23. #include "platform/platform.h"
  24. #include "platform/event.h"
  25. #include "io/fileStream.h"
  26. #include "sim/simBase.h"
  27. #include "console/consoleInternal.h"
  28. #include "httpObject_ScriptBinding.h"
  29. IMPLEMENT_CONOBJECT(HTTPObject);
  30. //--------------------------------------
  31. HTTPObject::HTTPObject()
  32. {
  33. mHostName = 0;
  34. mPath = 0;
  35. mQuery = 0;
  36. mPost = 0;
  37. mBufferSave = 0;
  38. }
  39. HTTPObject::~HTTPObject()
  40. {
  41. dFree(mHostName);
  42. dFree(mPath);
  43. dFree(mQuery);
  44. dFree(mPost);
  45. mHostName = 0;
  46. mPath = 0;
  47. mQuery = 0;
  48. mPost = 0;
  49. dFree(mBufferSave);
  50. }
  51. //--------------------------------------
  52. //--------------------------------------
  53. void HTTPObject::get(const char *host, const char *path, const char *query)
  54. {
  55. if(mHostName)
  56. dFree(mHostName);
  57. if(mPath)
  58. dFree(mPath);
  59. if(mQuery)
  60. dFree(mQuery);
  61. if(mPost)
  62. dFree(mPost);
  63. if(mBufferSave)
  64. dFree(mBufferSave);
  65. mBufferSave = 0;
  66. mHostName = dStrdup(host);
  67. mPath = dStrdup(path);
  68. if(query)
  69. mQuery = dStrdup(query);
  70. else
  71. mQuery = NULL;
  72. mPost = NULL;
  73. connect(host);
  74. }
  75. void HTTPObject::post(const char *host, const char *path, const char *query, const char *post)
  76. {
  77. if(mHostName)
  78. dFree(mHostName);
  79. if(mPath)
  80. dFree(mPath);
  81. if(mQuery)
  82. dFree(mQuery);
  83. if(mPost)
  84. dFree(mPost);
  85. if(mBufferSave)
  86. dFree(mBufferSave);
  87. mBufferSave = 0;
  88. mHostName = dStrdup(host);
  89. mPath = dStrdup(path);
  90. if(query && query[0])
  91. mQuery = dStrdup(query);
  92. else
  93. mQuery = NULL;
  94. mPost = dStrdup(post);
  95. connect(host);
  96. }
  97. static char getHex(char c)
  98. {
  99. if(c <= 9)
  100. return c + '0';
  101. return c - 10 + 'A';
  102. }
  103. static S32 getHexVal(char c)
  104. {
  105. if(c >= '0' && c <= '9')
  106. return c - '0';
  107. else if(c >= 'A' && c <= 'Z')
  108. return c - 'A' + 10;
  109. else if(c >= 'a' && c <= 'z')
  110. return c - 'a' + 10;
  111. return -1;
  112. }
  113. void HTTPObject::expandPath(char *dest, const char *path, U32 destSize)
  114. {
  115. static bool asciiEscapeTableBuilt = false;
  116. static bool asciiEscapeTable[256];
  117. if(!asciiEscapeTableBuilt)
  118. {
  119. asciiEscapeTableBuilt = true;
  120. U32 i;
  121. for(i = 0; i <= ' '; i++)
  122. asciiEscapeTable[i] = true;
  123. for(;i <= 0x7F; i++)
  124. asciiEscapeTable[i] = false;
  125. for(;i <= 0xFF; i++)
  126. asciiEscapeTable[i] = true;
  127. asciiEscapeTable['\"'] = true;
  128. asciiEscapeTable['_'] = true;
  129. asciiEscapeTable['\''] = true;
  130. asciiEscapeTable['#'] = true;
  131. asciiEscapeTable['$'] = true;
  132. asciiEscapeTable['%'] = true;
  133. asciiEscapeTable['&'] = true;
  134. asciiEscapeTable['+'] = true;
  135. asciiEscapeTable['-'] = true;
  136. asciiEscapeTable['~'] = true;
  137. }
  138. U32 destIndex = 0;
  139. U32 srcIndex = 0;
  140. while(path[srcIndex] && destIndex < destSize - 3)
  141. {
  142. char c = path[srcIndex++];
  143. if(asciiEscapeTable[c])
  144. {
  145. dest[destIndex++] = '%';
  146. dest[destIndex++] = getHex((c >> 4) & 0xF);
  147. dest[destIndex++] = getHex(c & 0xF);
  148. }
  149. else
  150. dest[destIndex++] = c;
  151. }
  152. dest[destIndex] = 0;
  153. }
  154. //--------------------------------------
  155. void HTTPObject::onConnected()
  156. {
  157. Parent::onConnected();
  158. char expPath[8192];
  159. char buffer[8192];
  160. if(mQuery)
  161. {
  162. dSprintf(buffer, sizeof(buffer), "%s?%s", mPath, mQuery);
  163. expandPath(expPath, buffer, sizeof(expPath));
  164. }
  165. else
  166. expandPath(expPath, mPath, sizeof(expPath));
  167. char *pt = dStrchr(mHostName, ':');
  168. if(pt)
  169. *pt = 0;
  170. dSprintf(buffer, sizeof(buffer), "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", expPath, mHostName);
  171. if(pt)
  172. *pt = ':';
  173. send((U8*)buffer, dStrlen(buffer));
  174. mParseState = ParsingStatusLine;
  175. mChunkedEncoding = false;
  176. }
  177. void HTTPObject::onConnectFailed()
  178. {
  179. dFree(mHostName);
  180. dFree(mPath);
  181. dFree(mQuery);
  182. mHostName = 0;
  183. mPath = 0;
  184. mQuery = 0;
  185. Parent::onConnectFailed();
  186. }
  187. void HTTPObject::onDisconnect()
  188. {
  189. dFree(mHostName);
  190. dFree(mPath);
  191. dFree(mQuery);
  192. mHostName = 0;
  193. mPath = 0;
  194. mQuery = 0;
  195. Parent::onDisconnect();
  196. }
  197. bool HTTPObject::processLine(U8 *line)
  198. {
  199. if(mParseState == ParsingStatusLine)
  200. {
  201. mParseState = ParsingHeader;
  202. }
  203. else if(mParseState == ParsingHeader)
  204. {
  205. if(!dStricmp((char *) line, "transfer-encoding: chunked"))
  206. mChunkedEncoding = true;
  207. if(line[0] == 0)
  208. {
  209. if(mChunkedEncoding)
  210. mParseState = ParsingChunkHeader;
  211. else
  212. mParseState = ProcessingBody;
  213. return true;
  214. }
  215. }
  216. else if(mParseState == ParsingChunkHeader)
  217. {
  218. if(line[0]) // strip off the crlf if necessary
  219. {
  220. mChunkSize = 0;
  221. S32 hexVal;
  222. while((hexVal = getHexVal(*line++)) != -1)
  223. {
  224. mChunkSize *= 16;
  225. mChunkSize += hexVal;
  226. }
  227. if(mBufferSave)
  228. {
  229. mBuffer = mBufferSave;
  230. mBufferSize = mBufferSaveSize;
  231. mBufferSave = 0;
  232. }
  233. if(mChunkSize)
  234. mParseState = ProcessingBody;
  235. else
  236. {
  237. mParseState = ProcessingDone;
  238. finishLastLine();
  239. }
  240. }
  241. }
  242. else
  243. {
  244. return Parent::processLine(line);
  245. }
  246. return true;
  247. }
  248. U32 HTTPObject::onDataReceive(U8 *buffer, U32 bufferLen)
  249. {
  250. U32 start = 0;
  251. parseLine(buffer, &start, bufferLen);
  252. return start;
  253. }
  254. //--------------------------------------
  255. U32 HTTPObject::onReceive(U8 *buffer, U32 bufferLen)
  256. {
  257. if(mParseState == ProcessingBody)
  258. {
  259. if(mChunkedEncoding && bufferLen >= mChunkSize)
  260. {
  261. U32 ret = onDataReceive(buffer, mChunkSize);
  262. mChunkSize -= ret;
  263. if(mChunkSize == 0)
  264. {
  265. if(mBuffer)
  266. {
  267. mBufferSaveSize = mBufferSize;
  268. mBufferSave = mBuffer;
  269. mBuffer = 0;
  270. mBufferSize = 0;
  271. }
  272. mParseState = ParsingChunkHeader;
  273. }
  274. return ret;
  275. }
  276. else
  277. {
  278. U32 ret = onDataReceive(buffer, bufferLen);
  279. mChunkSize -= ret;
  280. return ret;
  281. }
  282. }
  283. else if(mParseState != ProcessingDone)
  284. {
  285. U32 start = 0;
  286. parseLine(buffer, &start, bufferLen);
  287. return start;
  288. }
  289. return bufferLen;
  290. }