PageRenderTime 68ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 1ms

/js/lib/Socket.IO-node/support/expresso/deps/jscoverage/http-exchange.c

http://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
C | 494 lines | 371 code | 79 blank | 44 comment | 83 complexity | f3e6871684b6a0ed778439b813a336e4 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-3-Clause
  1. /*
  2. http-exchange.c - HTTP request/response exchange
  3. Copyright (C) 2008 siliconforks.com
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License along
  13. with this program; if not, write to the Free Software Foundation, Inc.,
  14. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  15. */
  16. #include <config.h>
  17. #include "http-server.h"
  18. #include <assert.h>
  19. #include <ctype.h>
  20. #include <string.h>
  21. #include "util.h"
  22. struct HTTPExchange {
  23. HTTPConnection * connection;
  24. HTTPMessage * request_message;
  25. char * method;
  26. char * request_uri;
  27. char * request_http_version;
  28. char * host;
  29. uint16_t port;
  30. char * abs_path;
  31. char * query;
  32. HTTPMessage * response_message;
  33. uint16_t status_code;
  34. char * response_http_version;
  35. };
  36. static const struct {
  37. const int status_code;
  38. const char * const reason_phrase;
  39. } reason_phrases[] = {
  40. {100, "Continue"},
  41. {101, "Switching Protocols"},
  42. {200, "OK"},
  43. {201, "Created"},
  44. {202, "Accepted"},
  45. {203, "Non-Authoritative Information"},
  46. {204, "No Content"},
  47. {205, "Reset Content"},
  48. {206, "Partial Content"},
  49. {301, "Moved Permanently"},
  50. {302, "Found"},
  51. {303, "See Other"},
  52. {304, "Not Modified"},
  53. {305, "Use Proxy"},
  54. {307, "Temporary Redirect"},
  55. {400, "Bad Request"},
  56. {401, "Unauthorized"},
  57. {402, "Payment Required"},
  58. {403, "Forbidden"},
  59. {404, "Not Found"},
  60. {405, "Method Not Allowed"},
  61. {406, "Not Acceptable"},
  62. {407, "Proxy Authentication Required"},
  63. {408, "Request Time-out"},
  64. {409, "Conflict"},
  65. {410, "Gone"},
  66. {411, "Length Required"},
  67. {412, "Precondition Failed"},
  68. {413, "Request Entity Too Large"},
  69. {414, "Request-URI Too Large"},
  70. {415, "Unsupported Media Type"},
  71. {416, "Requested range not satisfiable"},
  72. {417, "Expectation Failed"},
  73. {500, "Internal Server Error"},
  74. {501, "Not Implemented"},
  75. {502, "Bad Gateway"},
  76. {503, "Service Unavailable"},
  77. {504, "Gateway Time-out"},
  78. {505, "HTTP Version not supported"},
  79. };
  80. HTTPExchange * HTTPExchange_new(HTTPConnection * connection) {
  81. HTTPExchange * exchange = xmalloc(sizeof(HTTPExchange));
  82. exchange->connection = connection;
  83. exchange->request_message = HTTPMessage_new(connection);
  84. exchange->method = NULL;
  85. exchange->request_uri = NULL;
  86. exchange->request_http_version = NULL;
  87. exchange->host = NULL;
  88. exchange->port = 0;
  89. exchange->abs_path = NULL;
  90. exchange->query = NULL;
  91. exchange->response_message = HTTPMessage_new(connection);
  92. exchange->response_http_version = NULL;
  93. exchange->status_code = 0;
  94. return exchange;
  95. }
  96. void HTTPExchange_delete(HTTPExchange * exchange) {
  97. HTTPMessage_delete(exchange->response_message);
  98. free(exchange->response_http_version);
  99. HTTPMessage_delete(exchange->request_message);
  100. free(exchange->method);
  101. free(exchange->request_uri);
  102. free(exchange->request_http_version);
  103. free(exchange->host);
  104. free(exchange->abs_path);
  105. free(exchange->query);
  106. free(exchange);
  107. }
  108. int HTTPExchange_get_peer(const HTTPExchange * exchange, struct sockaddr_in * peer) {
  109. return HTTPConnection_get_peer(exchange->connection, peer);
  110. }
  111. HTTPMessage * HTTPExchange_get_request_message(const HTTPExchange * exchange) {
  112. return exchange->request_message;
  113. }
  114. const char * HTTPExchange_get_request_line(const HTTPExchange * exchange) {
  115. return HTTPMessage_get_start_line(exchange->request_message);
  116. }
  117. const char * HTTPExchange_get_method(const HTTPExchange * exchange) {
  118. return exchange->method;
  119. }
  120. const char * HTTPExchange_get_request_uri(const HTTPExchange * exchange) {
  121. return exchange->request_uri;
  122. }
  123. const char * HTTPExchange_get_request_http_version(const HTTPExchange * exchange) {
  124. return exchange->request_http_version;
  125. }
  126. const char * HTTPExchange_get_host(const HTTPExchange * exchange) {
  127. return exchange->host;
  128. }
  129. uint16_t HTTPExchange_get_port(const HTTPExchange * exchange) {
  130. return exchange->port;
  131. }
  132. const char * HTTPExchange_get_abs_path(const HTTPExchange * exchange) {
  133. return exchange->abs_path;
  134. }
  135. void HTTPExchange_set_method(HTTPExchange * exchange, const char * method) {
  136. free(exchange->method);
  137. exchange->method = xstrdup(method);
  138. }
  139. void HTTPExchange_set_request_uri(HTTPExchange * exchange, const char * request_uri) {
  140. free(exchange->request_uri);
  141. exchange->request_uri = xstrdup(request_uri);
  142. }
  143. const HTTPHeader * HTTPExchange_get_request_headers(const HTTPExchange * exchange) {
  144. return HTTPMessage_get_headers(exchange->request_message);
  145. }
  146. const char * HTTPExchange_find_request_header(const HTTPExchange * exchange, const char * name) {
  147. return HTTPMessage_find_header(exchange->request_message, name);
  148. }
  149. void HTTPExchange_add_request_header(HTTPExchange * exchange, const char * name, const char * value) {
  150. HTTPMessage_add_header(exchange->request_message, name, value);
  151. }
  152. void HTTPExchange_set_request_header(HTTPExchange * exchange, const char * name, const char * value) {
  153. HTTPMessage_set_header(exchange->request_message, name, value);
  154. }
  155. void HTTPExchange_set_request_content_length(HTTPExchange * exchange, size_t value) {
  156. HTTPMessage_set_content_length(exchange->request_message, value);
  157. }
  158. int HTTPExchange_read_request_headers(HTTPExchange * exchange) {
  159. int result = 0;
  160. result = HTTPMessage_read_start_line_and_headers(exchange->request_message);
  161. if (result != 0) {
  162. return result;
  163. }
  164. /* parse the Request-Line */
  165. const char * request_line = HTTPMessage_get_start_line(exchange->request_message);
  166. const char * p = request_line;
  167. /* parse the Method */
  168. while (*p != ' ') {
  169. if (*p == '\0') {
  170. return -1;
  171. }
  172. p++;
  173. }
  174. if (p == request_line) {
  175. return -1;
  176. }
  177. exchange->method = xstrndup(request_line, p - request_line);
  178. /* skip over space */
  179. p++;
  180. /* parse the Request-URI */
  181. const char * start = p;
  182. while (*p != ' ') {
  183. if (*p == '\0') {
  184. return -1;
  185. }
  186. p++;
  187. }
  188. if (p == start) {
  189. return -1;
  190. }
  191. exchange->request_uri = xstrndup(start, p - start);
  192. /* skip over space */
  193. p++;
  194. /* parse the HTTP-Version */
  195. start = p;
  196. while (*p != '\r' && *p != '\n') {
  197. if (*p == '\0') {
  198. return -1;
  199. }
  200. p++;
  201. }
  202. if (p == start) {
  203. return -1;
  204. }
  205. exchange->request_http_version = xstrndup(start, p - start);
  206. /* uri elements */
  207. /* RFC 2616 5.1.2: the Request-URI can be an `absoluteURI' or an `abs_path' */
  208. result = URL_parse(exchange->request_uri, &(exchange->host), &(exchange->port),
  209. &(exchange->abs_path), &(exchange->query));
  210. if (result != 0) {
  211. return result;
  212. }
  213. if (exchange->host == NULL) {
  214. /* abs_path */
  215. const char * h = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
  216. if (h == NULL) {
  217. /* this must be an HTTP/1.0 client */
  218. }
  219. else {
  220. result = URL_parse_host_and_port(h, &(exchange->host), &(exchange->port));
  221. if (result != 0) {
  222. return result;
  223. }
  224. }
  225. }
  226. return 0;
  227. }
  228. int HTTPExchange_write_request_headers(HTTPExchange * exchange) {
  229. if (HTTPMessage_has_sent_headers(exchange->request_message)) {
  230. return 0;
  231. }
  232. /* set the Request-Line */
  233. if (HTTPMessage_get_start_line(exchange->request_message) == NULL) {
  234. if (exchange->method == NULL) {
  235. exchange->method = xstrdup("GET");
  236. }
  237. assert(exchange->request_uri != NULL);
  238. char * request_line;
  239. xasprintf(&request_line, "%s %s HTTP/1.1\r\n", exchange->method, exchange->request_uri);
  240. HTTPMessage_set_start_line(exchange->request_message, request_line);
  241. free(request_line);
  242. }
  243. /* set the Host, if necessary */
  244. if (! str_starts_with(exchange->request_uri, "http://")) {
  245. const char * host = HTTPMessage_find_header(exchange->request_message, HTTP_HOST);
  246. if (host == NULL) {
  247. struct sockaddr_in peer;
  248. int result = HTTPConnection_get_peer(exchange->connection, &peer);
  249. if (result != 0) {
  250. return result;
  251. }
  252. const char * a = inet_ntoa(peer.sin_addr);
  253. char * value;
  254. xasprintf(&value, "%s:%u", a, ntohs(peer.sin_port));
  255. HTTPMessage_add_header(exchange->request_message, HTTP_HOST, value);
  256. free(value);
  257. }
  258. }
  259. return HTTPMessage_write_start_line_and_headers(exchange->request_message);
  260. }
  261. bool HTTPExchange_request_has_body(const HTTPExchange * exchange) {
  262. /*
  263. RFC 2616 4.3: a request has a body iff the request has a Content-Length or Transfer-Encoding header
  264. */
  265. return HTTPMessage_find_header(exchange->request_message, HTTP_CONTENT_LENGTH) != NULL ||
  266. HTTPMessage_find_header(exchange->request_message, HTTP_TRANSFER_ENCODING) != NULL;
  267. }
  268. int HTTPExchange_read_entire_request_entity_body(HTTPExchange * exchange, Stream * stream) {
  269. return HTTPMessage_read_entire_entity_body(exchange->request_message, stream);
  270. }
  271. int HTTPExchange_flush_request(HTTPExchange * exchange) {
  272. return HTTPMessage_flush(exchange->request_message);
  273. }
  274. /* response methods */
  275. HTTPMessage * HTTPExchange_get_response_message(const HTTPExchange * exchange) {
  276. return exchange->response_message;
  277. }
  278. const char * HTTPExchange_get_response_http_version(const HTTPExchange * exchange) {
  279. return exchange->response_http_version;
  280. }
  281. uint16_t HTTPExchange_get_status_code(const HTTPExchange * exchange) {
  282. return exchange->status_code;
  283. }
  284. void HTTPExchange_set_status_code(HTTPExchange * exchange, uint16_t status_code) {
  285. exchange->status_code = status_code;
  286. }
  287. const HTTPHeader * HTTPExchange_get_response_headers(const HTTPExchange * exchange) {
  288. return HTTPMessage_get_headers(exchange->response_message);
  289. }
  290. const char * HTTPExchange_find_response_header(const HTTPExchange * exchange, const char * name) {
  291. return HTTPMessage_find_header(exchange->response_message, name);
  292. }
  293. void HTTPExchange_add_response_header(HTTPExchange * exchange, const char * name, const char * value) {
  294. HTTPMessage_add_header(exchange->response_message, name, value);
  295. }
  296. void HTTPExchange_set_response_header(HTTPExchange * exchange, const char * name, const char * value) {
  297. HTTPMessage_set_header(exchange->response_message, name, value);
  298. }
  299. void HTTPExchange_set_response_content_length(HTTPExchange * exchange, size_t value) {
  300. HTTPMessage_set_content_length(exchange->response_message, value);
  301. }
  302. static void skip_digits(const char ** p) {
  303. while (**p != '\0' && isdigit(**p)) {
  304. (*p)++;
  305. }
  306. }
  307. int HTTPExchange_read_response_headers(HTTPExchange * exchange) {
  308. /* make sure the request went through before we try to read stuff */
  309. int result = HTTPExchange_flush_request(exchange);
  310. if (result != 0) {
  311. return result;
  312. }
  313. result = HTTPMessage_read_start_line_and_headers(exchange->response_message);
  314. if (result != 0) {
  315. return result;
  316. }
  317. /* parse the Status-Line (RFC 2616 6.1) */
  318. const char * status_line = HTTPMessage_get_start_line(exchange->response_message);
  319. const char * p = status_line;
  320. /* read the HTTP-Version */
  321. if (! str_starts_with(p, "HTTP/")) {
  322. return -1;
  323. }
  324. p += 5;
  325. const char * start = p;
  326. skip_digits(&p);
  327. if (start == p) {
  328. return -1;
  329. }
  330. if (*p != '.') {
  331. return -1;
  332. }
  333. p++;
  334. start = p;
  335. skip_digits(&p);
  336. if (start == p) {
  337. return -1;
  338. }
  339. if (*p != ' ') {
  340. return -1;
  341. }
  342. exchange->response_http_version = xstrndup(status_line, p - status_line);
  343. /* skip over the space */
  344. p++;
  345. /* read the Status-Code */
  346. start = p;
  347. skip_digits(&p);
  348. if (p - start != 3) {
  349. return -1;
  350. }
  351. if (*p != ' ') {
  352. return -1;
  353. }
  354. exchange->status_code = strtoul(start, NULL, 10);
  355. return 0;
  356. }
  357. int HTTPExchange_write_response_headers(HTTPExchange * exchange) {
  358. if (HTTPMessage_has_sent_headers(exchange->response_message)) {
  359. return 0;
  360. }
  361. /* set the Status-Line (RFC 2616 6.1) */
  362. if (exchange->status_code == 0) {
  363. exchange->status_code = 200;
  364. }
  365. const char * reason_phrase = NULL;
  366. size_t num_reason_phrases = sizeof(reason_phrases) / sizeof(reason_phrases[0]);
  367. for (size_t i = 0; i < num_reason_phrases; i++) {
  368. if (reason_phrases[i].status_code == exchange->status_code) {
  369. reason_phrase = reason_phrases[i].reason_phrase;
  370. break;
  371. }
  372. }
  373. assert(reason_phrase != NULL);
  374. char * status_line;
  375. xasprintf(&status_line, "HTTP/1.1 %u %s\r\n", exchange->status_code, reason_phrase);
  376. HTTPMessage_set_start_line(exchange->response_message, status_line);
  377. free(status_line);
  378. /* set the Content-Type, if necessary */
  379. const char * content_type = HTTPMessage_find_header(exchange->response_message, HTTP_CONTENT_TYPE);
  380. if (content_type == NULL) {
  381. HTTPMessage_set_header(exchange->response_message, HTTP_CONTENT_TYPE, "text/html");
  382. }
  383. return HTTPMessage_write_start_line_and_headers(exchange->response_message);
  384. }
  385. bool HTTPExchange_response_has_body(const HTTPExchange * exchange) {
  386. /*
  387. RFC 2616 4.3: a response has a body iff the request is not HEAD and the response is not 1xx, 204, 304
  388. */
  389. const char * request_method = HTTPExchange_get_method(exchange);
  390. assert(request_method != NULL);
  391. return strcmp(request_method, "HEAD") != 0 &&
  392. exchange->status_code != 304 &&
  393. exchange->status_code != 204 &&
  394. exchange->status_code / 100 != 1;
  395. }
  396. int HTTPExchange_read_entire_response_entity_body(HTTPExchange * exchange, Stream * stream) {
  397. return HTTPMessage_read_entire_entity_body(exchange->response_message, stream);
  398. }
  399. int HTTPExchange_write_response(HTTPExchange * exchange, const void * p, size_t size) {
  400. int result = HTTPExchange_write_response_headers(exchange);
  401. if (result != 0) {
  402. return result;
  403. }
  404. return HTTPMessage_write(exchange->response_message, p, size);
  405. }
  406. int HTTPExchange_flush_response(HTTPExchange * exchange) {
  407. int result = HTTPExchange_write_response_headers(exchange);
  408. if (result != 0) {
  409. return result;
  410. }
  411. return HTTPMessage_flush(exchange->response_message);
  412. }