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