header.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. /*
  2. * libwebsockets - small server side websockets and web server implementation
  3. *
  4. * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
  5. *
  6. * This library is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation:
  9. * version 2.1 of the License.
  10. *
  11. * This library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public
  17. * License along with this library; if not, write to the Free Software
  18. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  19. * MA 02110-1301 USA
  20. */
  21. #include "private-libwebsockets.h"
  22. #include "lextable-strings.h"
  23. const unsigned char *lws_token_to_string(enum lws_token_indexes token)
  24. {
  25. if ((unsigned int)token >= ARRAY_SIZE(set))
  26. return NULL;
  27. return (unsigned char *)set[token];
  28. }
  29. int
  30. lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
  31. const unsigned char *value, int length,
  32. unsigned char **p, unsigned char *end)
  33. {
  34. #ifdef LWS_USE_HTTP2
  35. if (wsi->mode == LWSCM_HTTP2_SERVING)
  36. return lws_add_http2_header_by_name(wsi, name,
  37. value, length, p, end);
  38. #else
  39. (void)wsi;
  40. #endif
  41. if (name) {
  42. while (*p < end && *name)
  43. *((*p)++) = *name++;
  44. if (*p == end)
  45. return 1;
  46. *((*p)++) = ' ';
  47. }
  48. if (*p + length + 3 >= end)
  49. return 1;
  50. memcpy(*p, value, length);
  51. *p += length;
  52. *((*p)++) = '\x0d';
  53. *((*p)++) = '\x0a';
  54. return 0;
  55. }
  56. int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
  57. unsigned char *end)
  58. {
  59. #ifdef LWS_USE_HTTP2
  60. if (wsi->mode == LWSCM_HTTP2_SERVING)
  61. return 0;
  62. #else
  63. (void)wsi;
  64. #endif
  65. if ((long)(end - *p) < 3)
  66. return 1;
  67. *((*p)++) = '\x0d';
  68. *((*p)++) = '\x0a';
  69. return 0;
  70. }
  71. int
  72. lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
  73. const unsigned char *value, int length,
  74. unsigned char **p, unsigned char *end)
  75. {
  76. const unsigned char *name;
  77. #ifdef LWS_USE_HTTP2
  78. if (wsi->mode == LWSCM_HTTP2_SERVING)
  79. return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
  80. #endif
  81. name = lws_token_to_string(token);
  82. if (!name)
  83. return 1;
  84. return lws_add_http_header_by_name(wsi, name, value, length, p, end);
  85. }
  86. int lws_add_http_header_content_length(struct lws *wsi,
  87. unsigned long content_length,
  88. unsigned char **p, unsigned char *end)
  89. {
  90. char b[24];
  91. int n;
  92. n = sprintf(b, "%lu", content_length);
  93. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
  94. (unsigned char *)b, n, p, end))
  95. return 1;
  96. wsi->u.http.content_length = content_length;
  97. wsi->u.http.content_remain = content_length;
  98. return 0;
  99. }
  100. STORE_IN_ROM static const char * const err400[] = {
  101. "Bad Request",
  102. "Unauthorized",
  103. "Payment Required",
  104. "Forbidden",
  105. "Not Found",
  106. "Method Not Allowed",
  107. "Not Acceptable",
  108. "Proxy Auth Required",
  109. "Request Timeout",
  110. "Conflict",
  111. "Gone",
  112. "Length Required",
  113. "Precondition Failed",
  114. "Request Entity Too Large",
  115. "Request URI too Long",
  116. "Unsupported Media Type",
  117. "Requested Range Not Satisfiable",
  118. "Expectation Failed"
  119. };
  120. STORE_IN_ROM static const char * const err500[] = {
  121. "Internal Server Error",
  122. "Not Implemented",
  123. "Bad Gateway",
  124. "Service Unavailable",
  125. "Gateway Timeout",
  126. "HTTP Version Not Supported"
  127. };
  128. int
  129. lws_add_http_header_status(struct lws *wsi, unsigned int _code,
  130. unsigned char **p, unsigned char *end)
  131. {
  132. STORE_IN_ROM static const char * const hver[] = {
  133. "HTTP/1.0", "HTTP/1.1", "HTTP/2"
  134. };
  135. const struct lws_protocol_vhost_options *headers;
  136. unsigned int code = _code & LWSAHH_CODE_MASK;
  137. const char *description = "", *p1;
  138. unsigned char code_and_desc[60];
  139. int n;
  140. #ifdef LWS_WITH_ACCESS_LOG
  141. wsi->access_log.response = code;
  142. #endif
  143. #ifdef LWS_USE_HTTP2
  144. if (wsi->mode == LWSCM_HTTP2_SERVING)
  145. return lws_add_http2_header_status(wsi, code, p, end);
  146. #endif
  147. if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
  148. description = err400[code - 400];
  149. if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
  150. description = err500[code - 500];
  151. if (code == 200)
  152. description = "OK";
  153. if (code == 304)
  154. description = "Not Modified";
  155. else
  156. if (code >= 300 && code < 400)
  157. description = "Redirect";
  158. if (wsi->u.http.request_version < ARRAY_SIZE(hver))
  159. p1 = hver[wsi->u.http.request_version];
  160. else
  161. p1 = hver[0];
  162. n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description);
  163. if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end))
  164. return 1;
  165. headers = wsi->vhost->headers;
  166. while (headers) {
  167. if (lws_add_http_header_by_name(wsi,
  168. (const unsigned char *)headers->name,
  169. (unsigned char *)headers->value,
  170. strlen(headers->value), p, end))
  171. return 1;
  172. headers = headers->next;
  173. }
  174. if (wsi->context->server_string &&
  175. !(_code & LWSAHH_FLAG_NO_SERVER_NAME))
  176. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
  177. (unsigned char *)wsi->context->server_string,
  178. wsi->context->server_string_len, p, end))
  179. return 1;
  180. if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
  181. if (lws_add_http_header_by_name(wsi, (unsigned char *)
  182. "Strict-Transport-Security:",
  183. (unsigned char *)"max-age=15768000 ; "
  184. "includeSubDomains", 36, p, end))
  185. return 1;
  186. return 0;
  187. }
  188. LWS_VISIBLE int
  189. lws_return_http_status(struct lws *wsi, unsigned int code,
  190. const char *html_body)
  191. {
  192. struct lws_context *context = lws_get_context(wsi);
  193. struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
  194. unsigned char *p = pt->serv_buf + LWS_PRE;
  195. unsigned char *start = p, *body = p + 512;
  196. unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
  197. int n, m, len;
  198. char slen[20];
  199. if (!html_body)
  200. html_body = "";
  201. len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
  202. code, html_body);
  203. if (lws_add_http_header_status(wsi, code, &p, end))
  204. return 1;
  205. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
  206. (unsigned char *)"text/html", 9,
  207. &p, end))
  208. return 1;
  209. n = sprintf(slen, "%d", len);
  210. if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
  211. (unsigned char *)slen, n,
  212. &p, end))
  213. return 1;
  214. if (lws_finalize_http_header(wsi, &p, end))
  215. return 1;
  216. m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
  217. if (m != (int)(p - start))
  218. return 1;
  219. m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
  220. return m != n;
  221. }
  222. LWS_VISIBLE int
  223. lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
  224. unsigned char **p, unsigned char *end)
  225. {
  226. unsigned char *start = *p;
  227. int n;
  228. if (lws_add_http_header_status(wsi, code, p, end))
  229. return -1;
  230. if (lws_add_http_header_by_token(wsi,
  231. WSI_TOKEN_HTTP_LOCATION,
  232. loc, len, p, end))
  233. return -1;
  234. /*
  235. * if we're going with http/1.1 and keepalive,
  236. * we have to give fake content metadata so the
  237. * client knows we completed the transaction and
  238. * it can do the redirect...
  239. */
  240. if (lws_add_http_header_by_token(wsi,
  241. WSI_TOKEN_HTTP_CONTENT_TYPE,
  242. (unsigned char *)"text/html", 9,
  243. p, end))
  244. return -1;
  245. if (lws_add_http_header_by_token(wsi,
  246. WSI_TOKEN_HTTP_CONTENT_LENGTH,
  247. (unsigned char *)"0", 1, p, end))
  248. return -1;
  249. if (lws_finalize_http_header(wsi, p, end))
  250. return -1;
  251. n = lws_write(wsi, start, *p - start,
  252. LWS_WRITE_HTTP_HEADERS);
  253. return n;
  254. }