lws_intptr_t
[platform/upstream/libwebsockets.git] / lib / header.c
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
22 #include "private-libwebsockets.h"
23
24 #include "lextable-strings.h"
25
26
27 const unsigned char *lws_token_to_string(enum lws_token_indexes token)
28 {
29         if ((unsigned int)token >= ARRAY_SIZE(set))
30                 return NULL;
31
32         return (unsigned char *)set[token];
33 }
34
35 int
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)
39 {
40 #ifdef LWS_USE_HTTP2
41         if (wsi->mode == LWSCM_HTTP2_SERVING)
42                 return lws_add_http2_header_by_name(wsi, name,
43                                                     value, length, p, end);
44 #else
45         (void)wsi;
46 #endif
47         if (name) {
48                 while (*p < end && *name)
49                         *((*p)++) = *name++;
50                 if (*p == end)
51                         return 1;
52                 *((*p)++) = ' ';
53         }
54         if (*p + length + 3 >= end)
55                 return 1;
56
57         memcpy(*p, value, length);
58         *p += length;
59         *((*p)++) = '\x0d';
60         *((*p)++) = '\x0a';
61
62         return 0;
63 }
64
65 int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
66                              unsigned char *end)
67 {
68 #ifdef LWS_USE_HTTP2
69         if (wsi->mode == LWSCM_HTTP2_SERVING)
70                 return 0;
71 #else
72         (void)wsi;
73 #endif
74         if ((lws_intptr_t)(end - *p) < 3)
75                 return 1;
76         *((*p)++) = '\x0d';
77         *((*p)++) = '\x0a';
78
79         return 0;
80 }
81
82 int
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)
86 {
87         const unsigned char *name;
88 #ifdef LWS_USE_HTTP2
89         if (wsi->mode == LWSCM_HTTP2_SERVING)
90                 return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
91 #endif
92         name = lws_token_to_string(token);
93         if (!name)
94                 return 1;
95         return lws_add_http_header_by_name(wsi, name, value, length, p, end);
96 }
97
98 int lws_add_http_header_content_length(struct lws *wsi,
99                                        lws_filepos_t content_length,
100                                        unsigned char **p, unsigned char *end)
101 {
102         char b[24];
103         int n;
104
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))
108                 return 1;
109         wsi->u.http.content_length = content_length;
110         wsi->u.http.content_remain = content_length;
111
112         return 0;
113 }
114
115 STORE_IN_ROM static const char * const err400[] = {
116         "Bad Request",
117         "Unauthorized",
118         "Payment Required",
119         "Forbidden",
120         "Not Found",
121         "Method Not Allowed",
122         "Not Acceptable",
123         "Proxy Auth Required",
124         "Request Timeout",
125         "Conflict",
126         "Gone",
127         "Length Required",
128         "Precondition Failed",
129         "Request Entity Too Large",
130         "Request URI too Long",
131         "Unsupported Media Type",
132         "Requested Range Not Satisfiable",
133         "Expectation Failed"
134 };
135
136 STORE_IN_ROM static const char * const err500[] = {
137         "Internal Server Error",
138         "Not Implemented",
139         "Bad Gateway",
140         "Service Unavailable",
141         "Gateway Timeout",
142         "HTTP Version Not Supported"
143 };
144
145 int
146 lws_add_http_header_status(struct lws *wsi, unsigned int _code,
147                            unsigned char **p, unsigned char *end)
148 {
149         STORE_IN_ROM static const char * const hver[] = {
150                 "HTTP/1.0", "HTTP/1.1", "HTTP/2"
151         };
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];
156         int n;
157
158 #ifdef LWS_WITH_ACCESS_LOG
159         wsi->access_log.response = code;
160 #endif
161
162 #ifdef LWS_USE_HTTP2
163         if (wsi->mode == LWSCM_HTTP2_SERVING)
164                 return lws_add_http2_header_status(wsi, code, p, end);
165 #endif
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];
170
171         if (code == 200)
172                 description = "OK";
173
174         if (code == 304)
175                 description = "Not Modified";
176         else
177                 if (code >= 300 && code < 400)
178                         description = "Redirect";
179
180         if (wsi->u.http.request_version < ARRAY_SIZE(hver))
181                 p1 = hver[wsi->u.http.request_version];
182         else
183                 p1 = hver[0];
184
185         n = sprintf((char *)code_and_desc, "%s %u %s", p1, code, description);
186
187         if (lws_add_http_header_by_name(wsi, NULL, code_and_desc, n, p, end))
188                 return 1;
189
190         headers = wsi->vhost->headers;
191         while (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))
196                         return 1;
197
198                 headers = headers->next;
199         }
200
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))
206                         return 1;
207
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))
213                         return 1;
214
215         return 0;
216 }
217
218 LWS_VISIBLE int
219 lws_return_http_status(struct lws *wsi, unsigned int code,
220                        const char *html_body)
221 {
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;
227         int n = 0, m, len;
228         char slen[20];
229
230         if (!html_body)
231                 html_body = "";
232
233         if (lws_add_http_header_status(wsi, code, &p, end))
234                 return 1;
235
236         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
237                                          (unsigned char *)"text/html", 9,
238                                          &p, end))
239                 return 1;
240
241         len = 37 + strlen(html_body) + sprintf(slen, "%d", code);
242         n = sprintf(slen, "%d", len);
243
244         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
245                                          (unsigned char *)slen, n,
246                                          &p, end))
247                 return 1;
248
249         if (lws_finalize_http_header(wsi, &p, end))
250                 return 1;
251
252 #if defined(LWS_USE_HTTP2)
253         {
254                 unsigned char *body = p + 512;
255
256                 m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
257                 if (m != (int)(p - start))
258                         return 1;
259
260                 len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
261                       code, html_body);
262
263                 n = len;
264                 m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
265         }
266 #else
267         p += lws_snprintf((char *)p, end - p - 1,
268                           "<html><body><h1>%u</h1>%s</body></html>",
269                           code, html_body);
270
271         n = (int)(p - start);
272         m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
273         if (m != n)
274                 return 1;
275 #endif
276
277         return m != n;
278 }
279
280 LWS_VISIBLE int
281 lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
282                   unsigned char **p, unsigned char *end)
283 {
284         unsigned char *start = *p;
285         int n;
286
287         if (lws_add_http_header_status(wsi, code, p, end))
288                 return -1;
289
290         if (lws_add_http_header_by_token(wsi,
291                         WSI_TOKEN_HTTP_LOCATION,
292                         loc, len, p, end))
293                 return -1;
294         /*
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...
299          */
300         if (lws_add_http_header_by_token(wsi,
301                         WSI_TOKEN_HTTP_CONTENT_TYPE,
302                         (unsigned char *)"text/html", 9,
303                         p, end))
304                 return -1;
305         if (lws_add_http_header_by_token(wsi,
306                         WSI_TOKEN_HTTP_CONTENT_LENGTH,
307                         (unsigned char *)"0", 1, p, end))
308                 return -1;
309
310         if (lws_finalize_http_header(wsi, p, end))
311                 return -1;
312
313         n = lws_write(wsi, start, *p - start,
314                         LWS_WRITE_HTTP_HEADERS);
315
316         return n;
317 }