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];
170 if (code >= 300 && code < 400)
171 description = "Redirect";
173 if (wsi->u.http.request_version < ARRAY_SIZE(hver))
174 p1 = hver[wsi->u.http.request_version];
178 n = sprintf((char *)code_and_desc, "%s %u %s",
179 p1, code, description);
181 return lws_add_http_header_by_name(wsi, NULL, code_and_desc,
186 * lws_return_http_status() - Return simple http status
187 * @wsi: Websocket instance (available from user callback)
188 * @code: Status index, eg, 404
189 * @html_body: User-readable HTML description < 1KB, or NULL
191 * Helper to report HTTP errors back to the client cleanly and
195 lws_return_http_status(struct lws *wsi, unsigned int code,
196 const char *html_body)
198 struct lws_context *context = lws_get_context(wsi);
199 struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
200 unsigned char *p = pt->serv_buf + LWS_PRE;
201 unsigned char *start = p, *body = p + 512;
202 unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
209 len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
212 if (lws_add_http_header_status(wsi, code, &p, end))
214 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
215 (unsigned char *)"libwebsockets", 13,
218 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
219 (unsigned char *)"text/html", 9,
222 n = sprintf(slen, "%d", len);
223 if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
224 (unsigned char *)slen, n,
228 if (wsi->vhost->options & LWS_SERVER_OPTION_STS)
229 if (lws_add_http_header_by_name(wsi, (unsigned char *)
230 "Strict-Transport-Security:",
231 (unsigned char *)"max-age=15768000 ; "
232 "includeSubDomains", 36, &p, end))
235 if (lws_finalize_http_header(wsi, &p, end))
238 m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
239 if (m != (int)(p - start))
242 m = lws_write(wsi, body, len, LWS_WRITE_HTTP);