lws normalize http response
[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 >= 300 && code < 400)
171                 description = "Redirect";
172
173         if (wsi->u.http.request_version < ARRAY_SIZE(hver))
174                 p1 = hver[wsi->u.http.request_version];
175         else
176                 p1 = hver[0];
177
178         n = sprintf((char *)code_and_desc, "%s %u %s",
179                     p1, code, description);
180
181         return lws_add_http_header_by_name(wsi, NULL, code_and_desc,
182                                            n, p, end);
183 }
184
185 /**
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
190  *
191  *      Helper to report HTTP errors back to the client cleanly and
192  *      consistently
193  */
194 LWS_VISIBLE int
195 lws_return_http_status(struct lws *wsi, unsigned int code,
196                        const char *html_body)
197 {
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;
203         int n, m, len;
204         char slen[20];
205
206         if (!html_body)
207                 html_body = "";
208
209         len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
210                       code, html_body);
211
212         if (lws_add_http_header_status(wsi, code, &p, end))
213                 return 1;
214         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
215                                          (unsigned char *)"libwebsockets", 13,
216                                          &p, end))
217                 return 1;
218         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
219                                          (unsigned char *)"text/html", 9,
220                                          &p, end))
221                 return 1;
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,
225                                          &p, end))
226                 return 1;
227
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))
233                         return 1;
234
235         if (lws_finalize_http_header(wsi, &p, end))
236                 return 1;
237
238         m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
239         if (m != (int)(p - start))
240                 return 1;
241
242         m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
243
244         return m != n;
245 }