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"
23 #include "lextable-strings.h"
25 const unsigned char *lws_token_to_string(enum lws_token_indexes token)
27 if ((unsigned int)token >= ARRAY_SIZE(set))
30 return (unsigned char *)set[token];
34 lws_add_http_header_by_name(struct lws *wsi, const unsigned char *name,
35 const unsigned char *value, int length,
36 unsigned char **p, unsigned char *end)
39 if (wsi->mode == LWSCM_HTTP2_SERVING)
40 return lws_add_http2_header_by_name(wsi, name,
41 value, length, p, end);
46 while (*p < end && *name)
52 if (*p + length + 3 >= end)
55 memcpy(*p, value, length);
63 int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
67 if (wsi->mode == LWSCM_HTTP2_SERVING)
72 if ((long)(end - *p) < 3)
81 lws_add_http_header_by_token(struct lws *wsi, enum lws_token_indexes token,
82 const unsigned char *value, int length,
83 unsigned char **p, unsigned char *end)
85 const unsigned char *name;
87 if (wsi->mode == LWSCM_HTTP2_SERVING)
88 return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
90 name = lws_token_to_string(token);
93 return lws_add_http_header_by_name(wsi, name, value, length, p, end);
96 int lws_add_http_header_content_length(struct lws *wsi,
97 unsigned long content_length,
98 unsigned char **p, unsigned char *end)
103 n = sprintf(b, "%lu", content_length);
104 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
105 (unsigned char *)b, n, p, end))
107 wsi->u.http.content_length = content_length;
108 wsi->u.http.content_remain = content_length;
113 static const char *err400[] = {
119 "Method Not Allowed",
121 "Proxy Auth Required",
126 "Precondition Failed",
127 "Request Entity Too Large",
128 "Request URI too Long",
129 "Unsupported Media Type",
130 "Requested Range Not Satisfiable",
134 static const char *err500[] = {
135 "Internal Server Error",
138 "Service Unavailable",
140 "HTTP Version Not Supported"
144 lws_add_http_header_status(struct lws *wsi, unsigned int code,
145 unsigned char **p, unsigned char *end)
147 unsigned char code_and_desc[60];
148 const char *description = "", *p1;
150 static const char * const hver[] = {
151 "HTTP/1.0", "HTTP/1.1", "HTTP/2"
154 #ifdef LWS_WITH_ACCESS_LOG
155 wsi->access_log.response = code;
159 if (wsi->mode == LWSCM_HTTP2_SERVING)
160 return lws_add_http2_header_status(wsi, code, p, end);
162 if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
163 description = err400[code - 400];
164 if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
165 description = err500[code - 500];
171 description = "Not Modified";
173 if (code >= 300 && code < 400)
174 description = "Redirect";
176 if (wsi->u.http.request_version < ARRAY_SIZE(hver))
177 p1 = hver[wsi->u.http.request_version];
181 n = sprintf((char *)code_and_desc, "%s %u %s",
182 p1, code, description);
184 if (lws_add_http_header_by_name(wsi, NULL, code_and_desc,
188 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
190 wsi->context->server_string,
191 wsi->context->server_string_len,
195 if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
196 if (lws_add_http_header_by_name(wsi, (unsigned char *)
197 "Strict-Transport-Security:",
198 (unsigned char *)"max-age=15768000 ; "
199 "includeSubDomains", 36, p, end))
206 * lws_return_http_status() - Return simple http status
207 * @wsi: Websocket instance (available from user callback)
208 * @code: Status index, eg, 404
209 * @html_body: User-readable HTML description < 1KB, or NULL
211 * Helper to report HTTP errors back to the client cleanly and
215 lws_return_http_status(struct lws *wsi, unsigned int code,
216 const char *html_body)
218 struct lws_context *context = lws_get_context(wsi);
219 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
220 unsigned char *p = pt->serv_buf + LWS_PRE;
221 unsigned char *start = p, *body = p + 512;
222 unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
229 len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
232 if (lws_add_http_header_status(wsi, code, &p, end))
235 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
236 (unsigned char *)"text/html", 9,
239 n = sprintf(slen, "%d", len);
240 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
241 (unsigned char *)slen, n,
245 if (lws_finalize_http_header(wsi, &p, end))
248 m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
249 if (m != (int)(p - start))
252 m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
258 lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
259 unsigned char **p, unsigned char *end)
261 unsigned char *start = *p;
264 if (lws_add_http_header_status(wsi, code, p, end))
267 if (lws_add_http_header_by_token(wsi,
268 WSI_TOKEN_HTTP_LOCATION,
272 * if we're going with http/1.1 and keepalive,
273 * we have to give fake content metadata so the
274 * client knows we completed the transaction and
275 * it can do the redirect...
277 if (lws_add_http_header_by_token(wsi,
278 WSI_TOKEN_HTTP_CONTENT_TYPE,
279 (unsigned char *)"text/html", 9,
282 if (lws_add_http_header_by_token(wsi,
283 WSI_TOKEN_HTTP_CONTENT_LENGTH,
284 (unsigned char *)"0", 1, p, end))
287 if (lws_finalize_http_header(wsi, p, end))
290 n = lws_write(wsi, start, *p - start,
291 LWS_WRITE_HTTP_HEADERS);