PageRenderTime 187ms CodeModel.GetById 60ms app.highlight 59ms RepoModel.GetById 61ms app.codeStats 0ms

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