lws_get_ctx conversion
[platform/upstream/libwebsockets.git] / lib / server-handshake.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
24 #define LWS_CPYAPP(ptr, str) { strcpy(ptr, str); ptr += strlen(str); }
25 #ifndef LWS_NO_EXTENSIONS
26 LWS_VISIBLE int
27 lws_extension_server_handshake(struct lws_context *context,
28                                struct lws *wsi, char **p)
29 {
30         int n;
31         char *c;
32         char ext_name[128];
33         struct lws_extension *ext;
34         int ext_count = 0;
35         int more = 1;
36
37         /*
38          * Figure out which extensions the client has that we want to
39          * enable on this connection, and give him back the list
40          */
41
42         if (!lws_hdr_total_length(wsi, WSI_TOKEN_EXTENSIONS))
43                 return 0;
44
45         /*
46          * break down the list of client extensions
47          * and go through them
48          */
49
50         if (lws_hdr_copy(wsi, (char *)context->service_buffer,
51                         sizeof(context->service_buffer),
52                                               WSI_TOKEN_EXTENSIONS) < 0)
53                 return 1;
54
55         c = (char *)context->service_buffer;
56         lwsl_parser("WSI_TOKEN_EXTENSIONS = '%s'\n", c);
57         wsi->count_active_extensions = 0;
58         n = 0;
59         while (more) {
60
61                 if (*c && (*c != ',' && *c != ' ' && *c != '\t')) {
62                         ext_name[n] = *c++;
63                         if (n < sizeof(ext_name) - 1)
64                                 n++;
65                         continue;
66                 }
67                 ext_name[n] = '\0';
68                 if (!*c)
69                         more = 0;
70                 else {
71                         c++;
72                         if (!n)
73                                 continue;
74                 }
75
76                 /* check a client's extension against our support */
77
78                 ext = lws_get_ctx(wsi)->extensions;
79
80                 while (ext && ext->callback) {
81
82                         if (strcmp(ext_name, ext->name)) {
83                                 ext++;
84                                 continue;
85                         }
86
87                         /*
88                          * oh, we do support this one he
89                          * asked for... but let's ask user
90                          * code if it's OK to apply it on this
91                          * particular connection + protocol
92                          */
93
94                         n = lws_get_ctx(wsi)->
95                                 protocols[0].callback(
96                                         lws_get_ctx(wsi),
97                                         wsi,
98                                   LWS_CALLBACK_CONFIRM_EXTENSION_OKAY,
99                                           wsi->user_space, ext_name, 0);
100
101                         /*
102                          * zero return from callback means
103                          * go ahead and allow the extension,
104                          * it's what we get if the callback is
105                          * unhandled
106                          */
107
108                         if (n) {
109                                 ext++;
110                                 continue;
111                         }
112
113                         /* apply it */
114
115                         if (ext_count)
116                                 *(*p)++ = ',';
117                         else
118                                 LWS_CPYAPP(*p,
119                                  "\x0d\x0aSec-WebSocket-Extensions: ");
120                         *p += sprintf(*p, "%s", ext_name);
121                         ext_count++;
122
123                         /* instantiate the extension on this conn */
124
125                         wsi->active_extensions_user[
126                                 wsi->count_active_extensions] =
127                                      lws_zalloc(ext->per_session_data_size);
128                         if (wsi->active_extensions_user[
129                              wsi->count_active_extensions] == NULL) {
130                                 lwsl_err("Out of mem\n");
131                                 return 1;
132                         }
133
134                         wsi->active_extensions[
135                                   wsi->count_active_extensions] = ext;
136
137                         /* allow him to construct his context */
138
139                         ext->callback(lws_get_ctx(wsi),
140                                         ext, wsi,
141                                         LWS_EXT_CALLBACK_CONSTRUCT,
142                                         wsi->active_extensions_user[
143                                 wsi->count_active_extensions], NULL, 0);
144
145                         wsi->count_active_extensions++;
146                         lwsl_parser("count_active_extensions <- %d\n",
147                                           wsi->count_active_extensions);
148
149                         ext++;
150                 }
151
152                 n = 0;
153         }
154
155         return 0;
156 }
157 #endif
158 int
159 handshake_0405(struct lws_context *context, struct lws *wsi)
160 {
161         unsigned char hash[20];
162         int n;
163         char *response;
164         char *p;
165         int accept_len;
166
167         if (!lws_hdr_total_length(wsi, WSI_TOKEN_HOST) ||
168                                 !lws_hdr_total_length(wsi, WSI_TOKEN_KEY)) {
169                 lwsl_parser("handshake_04 missing pieces\n");
170                 /* completed header processing, but missing some bits */
171                 goto bail;
172         }
173
174         if (lws_hdr_total_length(wsi, WSI_TOKEN_KEY) >=
175                                                      MAX_WEBSOCKET_04_KEY_LEN) {
176                 lwsl_warn("Client key too long %d\n", MAX_WEBSOCKET_04_KEY_LEN);
177                 goto bail;
178         }
179
180         /*
181          * since key length is restricted above (currently 128), cannot
182          * overflow
183          */
184         n = sprintf((char *)context->service_buffer,
185                                 "%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11",
186                                 lws_hdr_simple_ptr(wsi, WSI_TOKEN_KEY));
187
188         lws_SHA1(context->service_buffer, n, hash);
189
190         accept_len = lws_b64_encode_string((char *)hash, 20,
191                         (char *)context->service_buffer,
192                         sizeof(context->service_buffer));
193         if (accept_len < 0) {
194                 lwsl_warn("Base64 encoded hash too long\n");
195                 goto bail;
196         }
197
198         /* allocate the per-connection user memory (if any) */
199         if (lws_ensure_user_space(wsi))
200                 goto bail;
201
202         /* create the response packet */
203
204         /* make a buffer big enough for everything */
205
206         response = (char *)context->service_buffer + MAX_WEBSOCKET_04_KEY_LEN + LWS_SEND_BUFFER_PRE_PADDING;
207         p = response;
208         LWS_CPYAPP(p, "HTTP/1.1 101 Switching Protocols\x0d\x0a"
209                       "Upgrade: WebSocket\x0d\x0a"
210                       "Connection: Upgrade\x0d\x0a"
211                       "Sec-WebSocket-Accept: ");
212         strcpy(p, (char *)context->service_buffer);
213         p += accept_len;
214
215         if (lws_hdr_total_length(wsi, WSI_TOKEN_PROTOCOL)) {
216                 LWS_CPYAPP(p, "\x0d\x0aSec-WebSocket-Protocol: ");
217                 n = lws_hdr_copy(wsi, p, 128, WSI_TOKEN_PROTOCOL);
218                 if (n < 0)
219                         goto bail;
220                 p += n;
221         }
222
223 #ifndef LWS_NO_EXTENSIONS
224         /*
225          * Figure out which extensions the client has that we want to
226          * enable on this connection, and give him back the list
227          */
228         if (lws_extension_server_handshake(context, wsi, &p))
229                 goto bail;
230 #endif
231
232         //LWS_CPYAPP(p, "\x0d\x0a""An-unknown-header: blah");
233
234         /* end of response packet */
235
236         LWS_CPYAPP(p, "\x0d\x0a\x0d\x0a");
237         
238         if (!lws_any_extension_handled(context, wsi,
239                         LWS_EXT_CALLBACK_HANDSHAKE_REPLY_TX,
240                                                      response, p - response)) {
241
242                 /* okay send the handshake response accepting the connection */
243
244                 lwsl_parser("issuing resp pkt %d len\n", (int)(p - response));
245 #ifdef DEBUG
246                 fwrite(response, 1,  p - response, stderr);
247 #endif
248                 n = lws_write(wsi, (unsigned char *)response,
249                                                   p - response, LWS_WRITE_HTTP_HEADERS);
250                 if (n != (p - response)) {
251                         lwsl_debug("handshake_0405: ERROR writing to socket\n");
252                         goto bail;
253                 }
254
255         }
256
257         /* alright clean up and set ourselves into established state */
258
259         wsi->state = WSI_STATE_ESTABLISHED;
260         wsi->lws_rx_parse_state = LWS_RXPS_NEW;
261
262         /* notify user code that we're ready to roll */
263
264         if (wsi->protocol->callback)
265                 wsi->protocol->callback(lws_get_ctx(wsi),
266                                 wsi, LWS_CALLBACK_ESTABLISHED,
267                                           wsi->user_space,
268 #ifdef LWS_OPENSSL_SUPPORT
269                                           wsi->ssl,
270 #else
271                                           NULL,
272 #endif
273                                           0);
274
275         return 0;
276
277
278 bail:
279         /* free up his parsing allocations */
280         lws_free_header_table(wsi);
281         return -1;
282 }
283