api rationalization use new names internally
[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         return (unsigned char *)set[token];
30 }
31
32 int lws_add_http_header_by_name(struct libwebsocket_context *context,
33                             struct libwebsocket *wsi,
34                             const unsigned char *name,
35                             const unsigned char *value,
36                             int length,
37                             unsigned char **p,
38                             unsigned char *end)
39 {
40 #ifdef LWS_USE_HTTP2
41         if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
42                 return lws_add_http2_header_by_name(context, wsi, name, value, length, p, end);
43 #else
44         (void)wsi;
45         (void)context;
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         return 0;
62 }
63
64 int lws_finalize_http_header(struct libwebsocket_context *context,
65                             struct libwebsocket *wsi,
66                             unsigned char **p,
67                             unsigned char *end)
68 {
69         (void)context;
70 #ifdef LWS_USE_HTTP2
71         if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
72                 return 0;
73 #else
74         (void)wsi;
75 #endif
76         if ((long)(end - *p) < 3)
77                 return 1;
78         *((*p)++) = '\x0d';
79         *((*p)++) = '\x0a';
80         return 0;
81 }
82
83 int lws_add_http_header_by_token(struct libwebsocket_context *context,
84                             struct libwebsocket *wsi,
85                             enum lws_token_indexes token,
86                             const unsigned char *value,
87                             int length,
88                             unsigned char **p,
89                             unsigned char *end)
90 {
91         const unsigned char *name;
92 #ifdef LWS_USE_HTTP2
93         if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
94                 return lws_add_http2_header_by_token(context, wsi, token, value, length, p, end);
95 #endif
96         name = lws_token_to_string(token);
97         if (!name)
98                 return 1;
99         return lws_add_http_header_by_name(context, wsi, name, value, length, p, end);
100 }
101
102 int lws_add_http_header_content_length(struct libwebsocket_context *context,
103                             struct libwebsocket *wsi,
104                             unsigned long content_length,
105                             unsigned char **p,
106                             unsigned char *end)
107 {
108         char b[24];
109         int n;
110
111         n = sprintf(b, "%lu", content_length);
112         if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_LENGTH, (unsigned char *)b, n, p, end))
113                 return 1;
114         wsi->u.http.content_length = content_length;
115         wsi->u.http.content_remain = content_length;
116
117         return 0;
118 }
119
120 static const char *err400[] = {
121         "Bad Request",
122         "Unauthorized",
123         "Payment Required",
124         "Forbidden",
125         "Not Found",
126         "Method Not Allowed",
127         "Not Acceptable",
128         "Proxy Auth Required",
129         "Request Timeout",
130         "Conflict",
131         "Gone",
132         "Length Required",
133         "Precondition Failed",
134         "Request Entity Too Large",
135         "Request URI too Long",
136         "Unsupported Media Type",
137         "Requested Range Not Satisfiable",
138         "Expectation Failed"
139 };
140
141 static const char *err500[] = {
142         "Internal Server Error",
143         "Not Implemented",
144         "Bad Gateway",
145         "Service Unavailable",
146         "Gateway Timeout",
147         "HTTP Version Not Supported"
148 };
149
150 int lws_add_http_header_status(struct libwebsocket_context *context,
151                             struct libwebsocket *wsi,
152                             unsigned int code,
153                             unsigned char **p,
154                             unsigned char *end)
155 {
156         unsigned char code_and_desc[60];
157         const char *description = "";
158         int n;
159
160 #ifdef LWS_USE_HTTP2
161         if (wsi->mode == LWS_CONNMODE_HTTP2_SERVING)
162                 return lws_add_http2_header_status(context, wsi, code, p, end);
163 #endif
164         if (code >= 400 && code < (400 + ARRAY_SIZE(err400)))
165                 description = err400[code - 400];
166         if (code >= 500 && code < (500 + ARRAY_SIZE(err500)))
167                 description = err500[code - 500];
168
169         n = sprintf((char *)code_and_desc, "HTTP/1.0 %u %s", code, description);
170
171         return lws_add_http_header_by_name(context, wsi, NULL, code_and_desc, n, p, end);
172 }
173
174 /**
175  * lws_return_http_status() - Return simple http status
176  * @context:            libwebsockets context
177  * @wsi:                Websocket instance (available from user callback)
178  * @code:               Status index, eg, 404
179  * @html_body:          User-readable HTML description < 1KB, or NULL
180  *
181  *      Helper to report HTTP errors back to the client cleanly and
182  *      consistently
183  */
184 LWS_VISIBLE int lws_return_http_status(
185                 struct libwebsocket_context *context, struct libwebsocket *wsi,
186                                        unsigned int code, const char *html_body)
187 {
188         int n, m;
189
190         unsigned char *p = context->service_buffer + LWS_SEND_BUFFER_PRE_PADDING;
191         unsigned char *start = p;
192         unsigned char *end = p + sizeof(context->service_buffer) -
193                                         LWS_SEND_BUFFER_PRE_PADDING;
194
195         if (!html_body)
196                 html_body = "";
197
198         if (lws_add_http_header_status(context, wsi, code, &p, end))
199                 return 1;
200         if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_SERVER, (unsigned char *)"libwebsockets", 13, &p, end))
201                 return 1;
202         if (lws_add_http_header_by_token(context, wsi, WSI_TOKEN_HTTP_CONTENT_TYPE, (unsigned char *)"text/html", 9, &p, end))
203                 return 1;
204         if (lws_finalize_http_header(context, wsi, &p, end))
205                 return 1;
206
207         m = lws_write(wsi, start, p - start, LWS_WRITE_HTTP_HEADERS);
208         if (m != (int)(p - start))
209                 return 1;
210
211         n = sprintf((char *)start, "<html><body><h1>%u</h1>%s</body></html>", code, html_body);
212         m = lws_write(wsi, start, n, LWS_WRITE_HTTP);
213
214         return m != n;
215 }