public api remove superfluous context params API BREAK
[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 == LWS_CONNMODE_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 == LWS_CONNMODE_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 == LWS_CONNMODE_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, (unsigned char *)b, n, p, end))
105                 return 1;
106         wsi->u.http.content_length = content_length;
107         wsi->u.http.content_remain = content_length;
108
109         return 0;
110 }
111
112 static const char *err400[] = {
113         "Bad Request",
114         "Unauthorized",
115         "Payment Required",
116         "Forbidden",
117         "Not Found",
118         "Method Not Allowed",
119         "Not Acceptable",
120         "Proxy Auth Required",
121         "Request Timeout",
122         "Conflict",
123         "Gone",
124         "Length Required",
125         "Precondition Failed",
126         "Request Entity Too Large",
127         "Request URI too Long",
128         "Unsupported Media Type",
129         "Requested Range Not Satisfiable",
130         "Expectation Failed"
131 };
132
133 static const char *err500[] = {
134         "Internal Server Error",
135         "Not Implemented",
136         "Bad Gateway",
137         "Service Unavailable",
138         "Gateway Timeout",
139         "HTTP Version Not Supported"
140 };
141
142 int
143 lws_add_http_header_status(struct lws *wsi,
144                            unsigned int code, unsigned char **p,
145                            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 == LWS_CONNMODE_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  * @context:            libwebsockets context
169  * @wsi:                Websocket instance (available from user callback)
170  * @code:               Status index, eg, 404
171  * @html_body:          User-readable HTML description < 1KB, or NULL
172  *
173  *      Helper to report HTTP errors back to the client cleanly and
174  *      consistently
175  */
176 LWS_VISIBLE int
177 lws_return_http_status(struct lws *wsi, unsigned int code, const char *html_body)
178 {
179         int n, m;
180         struct lws_context *context = lws_get_ctx(wsi);
181         unsigned char *p = context->service_buffer +
182                            LWS_SEND_BUFFER_PRE_PADDING;
183         unsigned char *start = p;
184         unsigned char *end = p + sizeof(context->service_buffer) -
185                              LWS_SEND_BUFFER_PRE_PADDING;
186
187         if (!html_body)
188                 html_body = "";
189
190         if (lws_add_http_header_status(wsi, code, &p, end))
191                 return 1;
192         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_SERVER,
193                                          (unsigned char *)"libwebsockets", 13,
194                                          &p, end))
195                 return 1;
196         if (lws_add_http_header_by_token(wsi, WSI_TOKEN_HTTP_CONTENT_TYPE,
197                                          (unsigned char *)"text/html", 9,
198                                          &p, end))
199                 return 1;
200         if (lws_finalize_http_header(wsi, &p, end))
201                 return 1;
202
203         m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
204         if (m != (int)(p - start))
205                 return 1;
206
207         n = sprintf((char *)start, "<html><body><h1>%u</h1>%s</body></html>",
208                     code, html_body);
209         m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
210
211         return m != n;
212 }