2 * libwebsockets - small server side websockets and web server implementation
4 * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
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.
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.
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,
22 #include "private-libwebsockets.h"
24 #include "lextable-strings.h"
27 const unsigned char *lws_token_to_string(enum lws_token_indexes token)
29 if ((unsigned int)token >= ARRAY_SIZE(set))
32 return (unsigned char *)set[token];
36 lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
37 const unsigned char *value, int length,
38 unsigned char **p, unsigned char *end)
41 if (wsi->mode == LWSCM_HTTP2_SERVING)
42 return lws_add_http2_header_by_name(wsi, name,
43 value, length, p, end);
48 while (*p < end && *name)
54 if (*p + length + 3 >= end)
57 memcpy(*p, value, length);
65 int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
69 if (wsi->mode == LWSCM_HTTP2_SERVING)
74 if ((lws_intptr_t)(end - *p) < 3)
83 lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
84 const unsigned char *value, int length,
85 unsigned char **p, unsigned char *end)
87 const unsigned char *name;
89 if (wsi->mode == LWSCM_HTTP2_SERVING)
90 return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
92 name = lws_token_to_string(token);
95 return lws_add_http_header_by_name(wsi, name, value, length, p, end);
98 int lws_add_http_header_content_length(struct lws *wsi,
99 lws_filepos_t content_length,
100 unsigned char **p, unsigned char *end)
105 n = sprintf(b, "%llu", (unsigned long long)content_length);
106 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
107 (unsigned char *)b, n, p, end))
109 wsi->u.http.content_length = content_length;
110 wsi->u.http.content_remain = content_length;
115 STORE_IN_ROM static const char * const err400[] = {
121 "Method Not Allowed",
123 "Proxy Auth Required",
128 "Precondition Failed",
129 "Request Entity Too Large",
130 "Request URI too Long",
131 "Unsupported Media Type",
132 "Requested Range Not Satisfiable",
136 STORE_IN_ROM static const char * const err500[] = {
137 "Internal Server Error",
140 "Service Unavailable",
142 "HTTP Version Not Supported"
146 lws_add_http_header_status(struct lws *wsi, unsigned int _code,
147 unsigned char **p, unsigned char *end)
149 STORE_IN_ROM static const char * const hver[] = {
150 "HTTP/1.0", "HTTP/1.1", "HTTP/2"
152 const struct lws_protocol_vhost_options *headers;
153 unsigned int code = _code & LWSAHH_CODE_MASK;
154 const char *description = "", *p1;
155 unsigned char code_and_desc[60];
158 #ifdef LWS_WITH_ACCESS_LOG
159 wsi->access_log.response = code;
163 if (wsi->mode == LWSCM_HTTP2_SERVING)
164 return lws_add_http2_header_status(wsi, code, p, end);
166 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
167 description = err400[code - 400];
168 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
169 description = err500[code - 500];
175 description = "Not Modified";
177 if (code >= 300 && code < 400)
178 description = "Redirect";
180 if (wsi->u.http.request_version < ARRAY_SIZE(hver))
181 p1 = hver[wsi->u.http.request_version];
185 n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description);
187 if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end))
190 headers = wsi->vhost->headers;
192 if (lws_add_http_header_by_name(wsi,
193 (const unsigned char *)headers->name,
194 (unsigned char *)headers->value,
195 strlen(headers->value), p, end))
198 headers = headers->next;
201 if (wsi->context->server_string &&
202 !(_code & LWSAHH_FLAG_NO_SERVER_NAME))
203 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
204 (unsigned char *)wsi->context->server_string,
205 wsi->context->server_string_len, p, end))
208 if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
209 if (lws_add_http_header_by_name(wsi, (unsigned char *)
210 "Strict-Transport-Security:",
211 (unsigned char *)"max-age=15768000 ; "
212 "includeSubDomains", 36, p, end))
219 lws_return_http_status(struct lws *wsi, unsigned int code,
220 const char *html_body)
222 struct lws_context *context = lws_get_context(wsi);
223 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
224 unsigned char *p = pt->serv_buf + LWS_PRE;
225 unsigned char *start = p;
226 unsigned char *end = p + context->pt_serv_buf_size - LWS_PRE;
233 if (lws_add_http_header_status(wsi, code, &p, end))
236 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
237 (unsigned char *)"text/html", 9,
241 len = 37 + strlen(html_body) + sprintf(slen, "%d", code);
242 n = sprintf(slen, "%d", len);
244 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
245 (unsigned char *)slen, n,
249 if (lws_finalize_http_header(wsi, &p, end))
252 #if defined(LWS_USE_HTTP2)
254 unsigned char *body = p + 512;
256 m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
257 if (m != (int)(p - start))
260 len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
264 m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
267 p += lws_snprintf((char *)p, end - p - 1,
268 "<html><body><h1>%u</h1>%s</body></html>",
271 n = (int)(p - start);
272 m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
281 lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
282 unsigned char **p, unsigned char *end)
284 unsigned char *start = *p;
287 if (lws_add_http_header_status(wsi, code, p, end))
290 if (lws_add_http_header_by_token(wsi,
291 WSI_TOKEN_HTTP_LOCATION,
295 * if we're going with http/1.1 and keepalive,
296 * we have to give fake content metadata so the
297 * client knows we completed the transaction and
298 * it can do the redirect...
300 if (lws_add_http_header_by_token(wsi,
301 WSI_TOKEN_HTTP_CONTENT_TYPE,
302 (unsigned char *)"text/html", 9,
305 if (lws_add_http_header_by_token(wsi,
306 WSI_TOKEN_HTTP_CONTENT_LENGTH,
307 (unsigned char *)"0", 1, p, end))
310 if (lws_finalize_http_header(wsi, p, end))
313 n = lws_write(wsi, start, *p - start,
314 LWS_WRITE_HTTP_HEADERS);