client: protect against possible NULL deref path
[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 = "";
149         int n;
150
151 #ifdef LWS_USE_HTTP2
152         if (wsi->mode == LWSCM_HTTP2_SERVING)
153                 return lws_add_http2_header_status(wsi, code, p, end);
154 #endif
155         if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
156                 description = err400[code - 400];
157         if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
158                 description = err500[code - 500];
159
160         n = sprintf((char *)code_and_desc, "HTTP/1.0 %u %s", code, description);
161
162         return lws_add_http_header_by_name(wsi, NULL, code_and_desc,
163                                            n, p, end);
164 }
165
166 /**
167  * lws_return_http_status() - Return simple http status
168  * @wsi:                Websocket instance (available from user callback)
169  * @code:               Status index, eg, 404
170  * @html_body:          User-readable HTML description < 1KB, or NULL
171  *
172  *      Helper to report HTTP errors back to the client cleanly and
173  *      consistently
174  */
175 LWS_VISIBLE int
176 lws_return_http_status(struct lws *wsi, unsigned int code,
177                        const char *html_body)
178 {
179         struct lws_context *context = lws_get_context(wsi);
180         struct lws_context_per_thread *pt = &context->pt[(int)wsi->tsi];
181         unsigned char *p = pt->serv_buf + LWS_PRE;
182         unsigned char *start = p, *body = p + 512;
183         unsigned char *end = p + LWS_MAX_SOCKET_IO_BUF - LWS_PRE;
184         int n, m, len;
185         char slen[20];
186
187         if (!html_body)
188                 html_body = "";
189
190         len = sprintf((char *)body, "<html><body><h1>%u</h1>%s</body></html>",
191                       code, html_body);
192
193         if (lws_add_http_header_status(wsi, code, &p, end))
194                 return 1;
195         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
196                                          (unsigned char *)"libwebsockets", 13,
197                                          &p, end))
198                 return 1;
199         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
200                                          (unsigned char *)"text/html", 9,
201                                          &p, end))
202                 return 1;
203         n = sprintf(slen, "%d", len);
204         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH,
205                                          (unsigned char *)slen, n,
206                                          &p, end))
207                 return 1;
208
209         if (lws_finalize_http_header(wsi, &p, end))
210                 return 1;
211
212         m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
213         if (m != (int)(p - start))
214                 return 1;
215
216         m = lws_write(wsi, body, len, LWS_WRITE_HTTP);
217
218         return m != n;
219 }