post example in test server
[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 #include "lextable-strings.h"
24
25 const unsigned char *lws_token_to_string(enum lws_token_indexes token)
26 {
27         if ((unsigned int)token >= ARRAY_SIZE(set))
28                 return NULL;
29
30         return (unsigned char *)set[token];
31 }
32
33 int
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)
37 {
38 #ifdef LWS_USE_HTTP2
39         if (wsi->mode == LWSCM_HTTP2_SERVING)
40                 return lws_add_http2_header_by_name(wsi, name,
41                                                     value, length, p, end);
42 #else
43         (void)wsi;
44 #endif
45         if (name) {
46                 while (*p < end && *name)
47                         *((*p)++) = *name++;
48                 if (*p == end)
49                         return 1;
50                 *((*p)++) = ' ';
51         }
52         if (*p + length + 3 >= end)
53                 return 1;
54
55         memcpy(*p, value, length);
56         *p += length;
57         *((*p)++) = '\x0d';
58         *((*p)++) = '\x0a';
59
60         return 0;
61 }
62
63 int lws_finalize_http_header(struct lws *wsi, unsigned char **p,
64                              unsigned char *end)
65 {
66 #ifdef LWS_USE_HTTP2
67         if (wsi->mode == LWSCM_HTTP2_SERVING)
68                 return 0;
69 #else
70         (void)wsi;
71 #endif
72         if ((long)(end - *p) < 3)
73                 return 1;
74         *((*p)++) = '\x0d';
75         *((*p)++) = '\x0a';
76
77         return 0;
78 }
79
80 int
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)
84 {
85         const unsigned char *name;
86 #ifdef LWS_USE_HTTP2
87         if (wsi->mode == LWSCM_HTTP2_SERVING)
88                 return lws_add_http2_header_by_token(wsi, token, value, length, p, end);
89 #endif
90         name = lws_token_to_string(token);
91         if (!name)
92                 return 1;
93         return lws_add_http_header_by_name(wsi, name, value, length, p, end);
94 }
95
96 int lws_add_http_header_content_length(struct lws *wsi,
97                                        unsigned long content_length,
98                                        unsigned char **p, unsigned char *end)
99 {
100         char b[24];
101         int n;
102
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))
106                 return 1;
107         wsi->u.http.content_length = content_length;
108         wsi->u.http.content_remain = content_length;
109
110         return 0;
111 }
112
113 static const char *err400[] = {
114         "Bad Request",
115         "Unauthorized",
116         "Payment Required",
117         "Forbidden",
118         "Not Found",
119         "Method Not Allowed",
120         "Not Acceptable",
121         "Proxy Auth Required",
122         "Request Timeout",
123         "Conflict",
124         "Gone",
125         "Length Required",
126         "Precondition Failed",
127         "Request Entity Too Large",
128         "Request URI too Long",
129         "Unsupported Media Type",
130         "Requested Range Not Satisfiable",
131         "Expectation Failed"
132 };
133
134 static const char *err500[] = {
135         "Internal Server Error",
136         "Not Implemented",
137         "Bad Gateway",
138         "Service Unavailable",
139         "Gateway Timeout",
140         "HTTP Version Not Supported"
141 };
142
143 int
144 lws_add_http_header_status(struct lws *wsi, unsigned int code,
145                            unsigned char **p, unsigned char *end)
146 {
147         unsigned char code_and_desc[60];
148         const char *description = "", *p1;
149         int n;
150         static const char * const hver[] = {
151                 "HTTP/1.0", "HTTP/1.1", "HTTP/2"
152         };
153
154 #ifdef LWS_WITH_ACCESS_LOG
155         wsi->access_log.response = code;
156 #endif
157
158 #ifdef LWS_USE_HTTP2
159         if (wsi->mode == LWSCM_HTTP2_SERVING)
160                 return lws_add_http2_header_status(wsi, code, p, end);
161 #endif
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];
166
167         if (code == 200)
168                 description = "OK";
169
170         if (code == 304)
171                 description = "Not Modified";
172         else
173                 if (code >= 300 && code < 400)
174                         description = "Redirect";
175
176         if (wsi->u.http.request_version < ARRAY_SIZE(hver))
177                 p1 = hver[wsi->u.http.request_version];
178         else
179                 p1 = hver[0];
180
181         n = sprintf((char *)code_and_desc, "%s %u %s",
182                     p1, code, description);
183
184         if (lws_add_http_header_by_name(wsi, NULL, code_and_desc,
185                                            n, p, end))
186                 return 1;
187
188         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
189                                          (unsigned char *)
190                                                  wsi->context->server_string,
191                                          wsi->context->server_string_len,
192                                          p, end))
193                 return 1;
194
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))
200                         return 1;
201
202         return 0;
203 }
204
205 /**
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
210  *
211  *      Helper to report HTTP errors back to the client cleanly and
212  *      consistently
213  */
214 LWS_VISIBLE int
215 lws_return_http_status(struct lws *wsi, unsigned int code,
216                        const char *html_body)
217 {
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;
223         int n, m, len;
224         char slen[20];
225
226         if (!html_body)
227                 html_body = "";
228
229         len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
230                       code, html_body);
231
232         if (lws_add_http_header_status(wsi, code, &p, end))
233                 return 1;
234
235         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
236                                          (unsigned char *)"text/html", 9,
237                                          &p, end))
238                 return 1;
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,
242                                          &p, end))
243                 return 1;
244
245         if (lws_finalize_http_header(wsi, &p, end))
246                 return 1;
247
248         m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
249         if (m != (int)(p - start))
250                 return 1;
251
252         m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
253
254         return m != n;
255 }
256
257 LWS_VISIBLE int
258 lws_http_redirect(struct lws *wsi, int code, const unsigned char *loc, int len,
259                   unsigned char **p, unsigned char *end)
260 {
261         unsigned char *start = *p;
262         int n;
263
264         if (lws_add_http_header_status(wsi, code, p, end))
265                 return -1;
266
267         if (lws_add_http_header_by_token(wsi,
268                         WSI_TOKEN_HTTP_LOCATION,
269                         loc, len, p, end))
270                 return -1;
271         /*
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...
276          */
277         if (lws_add_http_header_by_token(wsi,
278                         WSI_TOKEN_HTTP_CONTENT_TYPE,
279                         (unsigned char *)"text/html", 9,
280                         p, end))
281                 return -1;
282         if (lws_add_http_header_by_token(wsi,
283                         WSI_TOKEN_HTTP_CONTENT_LENGTH,
284                         (unsigned char *)"0", 1, p, end))
285                 return -1;
286
287         if (lws_finalize_http_header(wsi, p, end))
288                 return -1;
289
290         n = lws_write(wsi, start, *p - start,
291                         LWS_WRITE_HTTP_HEADERS);
292
293         return n;
294 }