1 /*
2     Copyright (c) 2013 250bpm s.r.o.  All rights reserved.
3     Copyright (c) 2014-2016 Jack R. Dunaway.  All rights reserved.
4     Copyright 2017 Garrett D'Amore <garrett@damore.org>
5 
6     Permission is hereby granted, free of charge, to any person obtaining a copy
7     of this software and associated documentation files (the "Software"),
8     to deal in the Software without restriction, including without limitation
9     the rights to use, copy, modify, merge, publish, distribute, sublicense,
10     and/or sell copies of the Software, and to permit persons to whom
11     the Software is furnished to do so, subject to the following conditions:
12 
13     The above copyright notice and this permission notice shall be included
14     in all copies or substantial portions of the Software.
15 
16     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18     FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19     THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20     LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21     FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22     IN THE SOFTWARE.
23 */
24 
25 #include "ws_handshake.h"
26 #include "sha1.h"
27 
28 #include "../../aio/timer.h"
29 
30 #include "../../core/sock.h"
31 
32 #include "../utils/base64.h"
33 
34 #include "../../utils/alloc.h"
35 #include "../../utils/err.h"
36 #include "../../utils/cont.h"
37 #include "../../utils/fast.h"
38 #include "../../utils/wire.h"
39 #include "../../utils/attr.h"
40 #include "../../utils/random.h"
41 #include "../../utils/strcasestr.h"
42 
43 #include <stddef.h>
44 #include <string.h>
45 #include <ctype.h>
46 
47 #define	CRLF	"\r\n"
48 
49 /*****************************************************************************/
50 /***  BEGIN undesirable dependency *******************************************/
51 /*****************************************************************************/
52 /*  TODO: A transport should be SP agnostic; alas, these includes are        */
53 /*        required for the map. Ideally, this map would live in another      */
54 /*        abstraction layer; perhaps a "registry" of Scalability Protocols?  */
55 /*****************************************************************************/
56 #include "../../pair.h"
57 #include "../../reqrep.h"
58 #include "../../pubsub.h"
59 #include "../../survey.h"
60 #include "../../pipeline.h"
61 #include "../../bus.h"
62 
63 static const struct nn_ws_sp_map NN_WS_HANDSHAKE_SP_MAP[] = {
64     { NN_PAIR,       NN_PAIR,       "pair.sp.nanomsg.org" },
65     { NN_REQ,        NN_REP,        "req.sp.nanomsg.org" },
66     { NN_REP,        NN_REQ,        "rep.sp.nanomsg.org" },
67     { NN_PUB,        NN_SUB,        "pub.sp.nanomsg.org" },
68     { NN_SUB,        NN_PUB,        "sub.sp.nanomsg.org" },
69     { NN_SURVEYOR,   NN_RESPONDENT, "surveyor.sp.nanomsg.org" },
70     { NN_RESPONDENT, NN_SURVEYOR,   "respondent.sp.nanomsg.org" },
71     { NN_PUSH,       NN_PULL,       "push.sp.nanomsg.org" },
72     { NN_PULL,       NN_PUSH,       "pull.sp.nanomsg.org" },
73     { NN_BUS,        NN_BUS,        "bus.sp.nanomsg.org" }
74 };
75 
76 const size_t NN_WS_HANDSHAKE_SP_MAP_LEN = sizeof (NN_WS_HANDSHAKE_SP_MAP) /
77     sizeof (NN_WS_HANDSHAKE_SP_MAP [0]);
78 /*****************************************************************************/
79 /***  END undesirable dependency *********************************************/
80 /*****************************************************************************/
81 
82 /*  State machine finite states. */
83 #define NN_WS_HANDSHAKE_STATE_IDLE 1
84 #define NN_WS_HANDSHAKE_STATE_SERVER_RECV 2
85 #define NN_WS_HANDSHAKE_STATE_SERVER_REPLY 3
86 #define NN_WS_HANDSHAKE_STATE_CLIENT_SEND 4
87 #define NN_WS_HANDSHAKE_STATE_CLIENT_RECV 5
88 #define NN_WS_HANDSHAKE_STATE_HANDSHAKE_SENT 6
89 #define NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR 7
90 #define NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE 8
91 #define NN_WS_HANDSHAKE_STATE_DONE 9
92 #define NN_WS_HANDSHAKE_STATE_STOPPING 10
93 
94 /*  Subordinate srcptr objects. */
95 #define NN_WS_HANDSHAKE_SRC_USOCK 1
96 #define NN_WS_HANDSHAKE_SRC_TIMER 2
97 
98 /*  Time allowed to complete handshake. */
99 #define NN_WS_HANDSHAKE_TIMEOUT 5000
100 
101 /*  Possible return codes internal to the parsing operations. */
102 #define NN_WS_HANDSHAKE_NOMATCH 0
103 #define NN_WS_HANDSHAKE_MATCH 1
104 
105 /*  Possible return codes from parsing opening handshake from peer. */
106 #define NN_WS_HANDSHAKE_VALID 0
107 #define NN_WS_HANDSHAKE_RECV_MORE 1
108 #define NN_WS_HANDSHAKE_INVALID -1
109 
110 /*  Possible handshake responses to send to client when acting as server. */
111 #define NN_WS_HANDSHAKE_RESPONSE_NULL -1
112 #define NN_WS_HANDSHAKE_RESPONSE_OK 0
113 #define NN_WS_HANDSHAKE_RESPONSE_TOO_BIG 1
114 #define NN_WS_HANDSHAKE_RESPONSE_UNUSED2 2
115 #define NN_WS_HANDSHAKE_RESPONSE_WSPROTO 3
116 #define NN_WS_HANDSHAKE_RESPONSE_WSVERSION 4
117 #define NN_WS_HANDSHAKE_RESPONSE_NNPROTO 5
118 #define NN_WS_HANDSHAKE_RESPONSE_NOTPEER 6
119 #define NN_WS_HANDSHAKE_RESPONSE_UNKNOWNTYPE 7
120 
121 /*  Private functions. */
122 static void nn_ws_handshake_handler (struct nn_fsm *self, int src, int type,
123     void *srcptr);
124 static void nn_ws_handshake_shutdown (struct nn_fsm *self, int src, int type,
125     void *srcptr);
126 static void nn_ws_handshake_leave (struct nn_ws_handshake *self, int rc);
127 
128 /*  WebSocket protocol support functions. */
129 static int nn_ws_handshake_parse_client_opening (struct nn_ws_handshake *self);
130 static void nn_ws_handshake_server_reply (struct nn_ws_handshake *self);
131 static void nn_ws_handshake_client_request (struct nn_ws_handshake *self);
132 static int nn_ws_handshake_parse_server_response (struct nn_ws_handshake *self);
133 static int nn_ws_handshake_hash_key (const char *key, size_t key_len,
134     char *hashed, size_t hashed_len);
135 
136 /*  String parsing support functions. */
137 
138 /*  Scans for reference token against subject string, optionally ignoring
139     case sensitivity and/or leading spaces in subject. On match, advances
140     the subject pointer to the next non-ignored character past match. Both
141     strings must be NULL terminated to avoid undefined behavior. Returns
142     NN_WS_HANDSHAKE_MATCH on match; else, NN_WS_HANDSHAKE_NOMATCH. */
143 static int nn_ws_match_token (const char* token, const char **subj,
144     int case_insensitive, int ignore_leading_sp);
145 
146 /*  Scans subject string for termination sequence, optionally ignoring
147     leading and/or trailing spaces in subject. On match, advances
148     the subject pointer to the next character past match. Both
149     strings must be NULL terminated to avoid undefined behavior. If the
150     match succeeds, values are stored into *addr and *len. */
151 static int nn_ws_match_value (const char* termseq, const char **subj,
152     int ignore_leading_sp, int ignore_trailing_sp, const char **addr,
153     size_t* const len);
154 
155 /*  Compares subject octet stream to expected value, optionally ignoring
156     case sensitivity. Returns non-zero on success, zero on failure. */
157 static int nn_ws_validate_value (const char* expected, const char *subj,
158     size_t subj_len, int case_insensitive);
159 
nn_ws_handshake_init(struct nn_ws_handshake * self,int src,struct nn_fsm * owner)160 void nn_ws_handshake_init (struct nn_ws_handshake *self, int src,
161     struct nn_fsm *owner)
162 {
163     nn_fsm_init (&self->fsm, nn_ws_handshake_handler, nn_ws_handshake_shutdown,
164         src, self, owner);
165     self->state = NN_WS_HANDSHAKE_STATE_IDLE;
166     nn_timer_init (&self->timer, NN_WS_HANDSHAKE_SRC_TIMER, &self->fsm);
167     nn_fsm_event_init (&self->done);
168     self->timeout = NN_WS_HANDSHAKE_TIMEOUT;
169     self->usock = NULL;
170     self->usock_owner.src = -1;
171     self->usock_owner.fsm = NULL;
172     self->pipebase = NULL;
173 }
174 
nn_ws_handshake_term(struct nn_ws_handshake * self)175 void nn_ws_handshake_term (struct nn_ws_handshake *self)
176 {
177     nn_assert_state (self, NN_WS_HANDSHAKE_STATE_IDLE);
178 
179     nn_fsm_event_term (&self->done);
180     nn_timer_term (&self->timer);
181     nn_fsm_term (&self->fsm);
182 }
183 
nn_ws_handshake_isidle(struct nn_ws_handshake * self)184 int nn_ws_handshake_isidle (struct nn_ws_handshake *self)
185 {
186     return nn_fsm_isidle (&self->fsm);
187 }
188 
nn_ws_handshake_start(struct nn_ws_handshake * self,struct nn_usock * usock,struct nn_pipebase * pipebase,int mode,const char * resource,const char * host)189 void nn_ws_handshake_start (struct nn_ws_handshake *self,
190     struct nn_usock *usock, struct nn_pipebase *pipebase,
191     int mode, const char *resource, const char *host)
192 {
193     /*  It's expected this resource has been allocated during intial connect. */
194     if (mode == NN_WS_CLIENT)
195         nn_assert (strlen (resource) >= 1);
196 
197     /*  Take ownership of the underlying socket. */
198     nn_assert (self->usock == NULL && self->usock_owner.fsm == NULL);
199     self->usock_owner.src = NN_WS_HANDSHAKE_SRC_USOCK;
200     self->usock_owner.fsm = &self->fsm;
201     nn_usock_swap_owner (usock, &self->usock_owner);
202     self->usock = usock;
203     self->pipebase = pipebase;
204     self->mode = mode;
205     self->resource = resource;
206     self->remote_host = host;
207 
208     memset (self->opening_hs, 0, sizeof (self->opening_hs));
209     memset (self->response, 0, sizeof (self->response));
210 
211     self->recv_pos = 0;
212     self->retries = 0;
213 
214     /*  Calculate the absolute minimum length possible for a valid opening
215         handshake. This is an optimization since we must poll for the
216         remainder of the opening handshake in small byte chunks. */
217     switch (self->mode) {
218     case NN_WS_SERVER:
219         self->recv_len = strlen (
220             "GET x HTTP/1.1\r\n"
221             "Upgrade: websocket\r\n"
222             "Connection: Upgrade\r\n"
223             "Host: x\r\n"
224             "Origin: x\r\n"
225             "Sec-WebSocket-Key: xxxxxxxxxxxxxxxxxxxxxxxx\r\n"
226             "Sec-WebSocket-Version: xx\r\n\r\n");
227         break;
228     case NN_WS_CLIENT:
229         /*  Shortest conceiveable response from server is a terse status. */
230         self->recv_len = strlen ("HTTP/1.1 xxx\r\n\r\n");
231         break;
232     default:
233         /*  Developer error; unexpected mode. */
234         nn_assert (0);
235         break;
236     }
237 
238     /*  Launch the state machine. */
239     nn_fsm_start (&self->fsm);
240 }
241 
nn_ws_handshake_stop(struct nn_ws_handshake * self)242 void nn_ws_handshake_stop (struct nn_ws_handshake *self)
243 {
244     nn_fsm_stop (&self->fsm);
245 }
246 
nn_ws_handshake_shutdown(struct nn_fsm * self,int src,int type,NN_UNUSED void * srcptr)247 static void nn_ws_handshake_shutdown (struct nn_fsm *self, int src, int type,
248     NN_UNUSED void *srcptr)
249 {
250     struct nn_ws_handshake *handshaker;
251 
252     handshaker = nn_cont (self, struct nn_ws_handshake, fsm);
253 
254     if (nn_slow (src == NN_FSM_ACTION && type == NN_FSM_STOP)) {
255         nn_timer_stop (&handshaker->timer);
256         handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING;
257     }
258     if (nn_slow (handshaker->state == NN_WS_HANDSHAKE_STATE_STOPPING)) {
259         if (!nn_timer_isidle (&handshaker->timer))
260             return;
261         handshaker->state = NN_WS_HANDSHAKE_STATE_IDLE;
262         nn_fsm_stopped (&handshaker->fsm, NN_WS_HANDSHAKE_STOPPED);
263         return;
264     }
265 
266     nn_fsm_bad_state (handshaker->state, src, type);
267 }
268 
nn_ws_match_token(const char * token,const char ** subj,int case_insensitive,int ignore_leading_sp)269 static int nn_ws_match_token (const char* token, const char **subj,
270     int case_insensitive, int ignore_leading_sp)
271 {
272     const char *pos;
273 
274     nn_assert (token && *subj);
275 
276     pos = *subj;
277 
278     if (ignore_leading_sp) {
279         while (*pos == '\x20' && *pos) {
280             pos++;
281         }
282     }
283 
284     if (case_insensitive) {
285         while (*token && *pos) {
286             if (tolower (*token) != tolower (*pos))
287                 return NN_WS_HANDSHAKE_NOMATCH;
288             token++;
289             pos++;
290         }
291     }
292     else {
293         while (*token && *pos) {
294             if (*token != *pos)
295                 return NN_WS_HANDSHAKE_NOMATCH;
296             token++;
297             pos++;
298         }
299     }
300 
301     /*  Encountered end of subject before matching completed. */
302     if (!*pos && *token)
303         return NN_WS_HANDSHAKE_NOMATCH;
304 
305     /*  Entire token has been matched. */
306     nn_assert (!*token);
307 
308     /*  On success, advance subject position. */
309     *subj = pos;
310 
311     return NN_WS_HANDSHAKE_MATCH;
312 }
313 
nn_ws_match_value(const char * termseq,const char ** subj,int ignore_leading_sp,int ignore_trailing_sp,const char ** addr,size_t * const len)314 static int nn_ws_match_value (const char* termseq, const char **subj,
315     int ignore_leading_sp, int ignore_trailing_sp, const char **addr,
316     size_t* const len)
317 {
318     const char *start;
319     const char *end;
320 
321     nn_assert (termseq && *subj);
322 
323     start = *subj;
324     if (addr)
325         *addr = NULL;
326     if (len)
327         *len = 0;
328 
329     /*  Find first occurence of termination sequence. */
330     end = strstr (start, termseq);
331 
332     /*  Was a termination sequence found? */
333     if (end) {
334         *subj = end + strlen (termseq);
335     }
336     else {
337         return NN_WS_HANDSHAKE_NOMATCH;
338     }
339 
340     if (ignore_leading_sp) {
341         while (*start == '\x20' && start < end) {
342             start++;
343         }
344     }
345 
346     if (addr)
347         *addr = start;
348 
349     /*  In this special case, the value was "found", but is just empty or
350         ignored space. */
351     if (start == end)
352         return NN_WS_HANDSHAKE_MATCH;
353 
354     if (ignore_trailing_sp) {
355         while (*(end - 1) == '\x20' && start < end) {
356             end--;
357         }
358     }
359 
360     if (len)
361         *len = end - start;
362 
363     return NN_WS_HANDSHAKE_MATCH;
364 }
365 
nn_ws_validate_value(const char * expected,const char * subj,size_t subj_len,int case_insensitive)366 static int nn_ws_validate_value (const char* expected, const char *subj,
367     size_t subj_len, int case_insensitive)
368 {
369     if (strlen (expected) != subj_len)
370         return NN_WS_HANDSHAKE_NOMATCH;
371 
372     if (case_insensitive) {
373         while (*expected && *subj) {
374             if (tolower (*expected) != tolower (*subj))
375                 return NN_WS_HANDSHAKE_NOMATCH;
376             expected++;
377             subj++;
378         }
379     }
380     else {
381         while (*expected && *subj) {
382             if (*expected != *subj)
383                 return NN_WS_HANDSHAKE_NOMATCH;
384             expected++;
385             subj++;
386         }
387     }
388 
389     return NN_WS_HANDSHAKE_MATCH;
390 }
391 
nn_ws_handshake_handler(struct nn_fsm * self,int src,int type,NN_UNUSED void * srcptr)392 static void nn_ws_handshake_handler (struct nn_fsm *self, int src, int type,
393     NN_UNUSED void *srcptr)
394 {
395     struct nn_ws_handshake *handshaker;
396 
397     size_t i;
398 
399     handshaker = nn_cont (self, struct nn_ws_handshake, fsm);
400 
401     switch (handshaker->state) {
402 
403 /******************************************************************************/
404 /*  IDLE state.                                                               */
405 /******************************************************************************/
406     case NN_WS_HANDSHAKE_STATE_IDLE:
407         switch (src) {
408 
409         case NN_FSM_ACTION:
410             switch (type) {
411             case NN_FSM_START:
412                 nn_assert (handshaker->recv_pos == 0);
413                 nn_assert (handshaker->recv_len >= NN_WS_HANDSHAKE_TERMSEQ_LEN);
414 
415                 nn_timer_start (&handshaker->timer, handshaker->timeout);
416 
417                 switch (handshaker->mode) {
418                 case NN_WS_CLIENT:
419                     /*  Send opening handshake to server. */
420                     nn_assert (handshaker->recv_len <=
421                         sizeof (handshaker->response));
422                     handshaker->state = NN_WS_HANDSHAKE_STATE_CLIENT_SEND;
423                     nn_ws_handshake_client_request (handshaker);
424                     return;
425                 case NN_WS_SERVER:
426                     /*  Begin receiving opening handshake from client. */
427                     nn_assert (handshaker->recv_len <=
428                         sizeof (handshaker->opening_hs));
429                     handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_RECV;
430                     nn_usock_recv (handshaker->usock, handshaker->opening_hs,
431                         handshaker->recv_len, NULL);
432                     return;
433                 default:
434                     /*  Unexpected mode. */
435                     nn_assert (0);
436                     return;
437                 }
438 
439             default:
440                 nn_fsm_bad_action (handshaker->state, src, type);
441             }
442 
443         default:
444             nn_fsm_bad_source (handshaker->state, src, type);
445         }
446 
447 /******************************************************************************/
448 /*  SERVER_RECV state.                                                        */
449 /******************************************************************************/
450     case NN_WS_HANDSHAKE_STATE_SERVER_RECV:
451         switch (src) {
452 
453         case NN_WS_HANDSHAKE_SRC_USOCK:
454             switch (type) {
455             case NN_USOCK_RECEIVED:
456                 /*  Parse bytes received thus far. */
457                 switch (nn_ws_handshake_parse_client_opening (handshaker)) {
458                 case NN_WS_HANDSHAKE_INVALID:
459                     /*  Opening handshake parsed successfully but does not
460                         contain valid values. Respond failure to client. */
461                     handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_REPLY;
462                     nn_ws_handshake_server_reply (handshaker);
463                     return;
464                 case NN_WS_HANDSHAKE_VALID:
465                     /*  Opening handshake parsed successfully, and is valid.
466                         Respond success to client. */
467                     handshaker->state = NN_WS_HANDSHAKE_STATE_SERVER_REPLY;
468                     nn_ws_handshake_server_reply (handshaker);
469                     return;
470                 case NN_WS_HANDSHAKE_RECV_MORE:
471                     /*  Not enough bytes have been received to determine
472                         validity; remain in the receive state, and retrieve
473                         more bytes from client. */
474                     handshaker->recv_pos += handshaker->recv_len;
475 
476                     /*  Validate the previous recv operation. */
477                     nn_assert (handshaker->recv_pos <
478                         sizeof (handshaker->opening_hs));
479 
480                     /*  Ensure we can back-track at least the length of the
481                         termination sequence to determine how many bytes to
482                         receive on the next retry. This is an assertion, not
483                         a conditional, since under no condition is it
484                         necessary to initially receive so few bytes. */
485                     nn_assert (handshaker->recv_pos >=
486                         (int) NN_WS_HANDSHAKE_TERMSEQ_LEN);
487 
488                     /*  We only compare if we have at least one byte to
489                         compare against.  When i drops to zero, it means
490                         we don't have any bytes to match against, and it is
491                         automatically true. */
492                     for (i = NN_WS_HANDSHAKE_TERMSEQ_LEN; i > 0; i--) {
493                         if (memcmp (NN_WS_HANDSHAKE_TERMSEQ,
494                             handshaker->opening_hs + handshaker->recv_pos - i,
495                             i) == 0) {
496                             break;
497                         }
498                     }
499 
500                     nn_assert (i < NN_WS_HANDSHAKE_TERMSEQ_LEN);
501 
502                     handshaker->recv_len = NN_WS_HANDSHAKE_TERMSEQ_LEN - i;
503 
504                     /*  In the unlikely case the client would overflow what we
505                         assumed was a sufficiently-large buffer to receive the
506                         handshake, we fail the client. */
507                     if (handshaker->recv_len + handshaker->recv_pos >
508                         sizeof (handshaker->opening_hs)) {
509                         handshaker->response_code =
510                             NN_WS_HANDSHAKE_RESPONSE_TOO_BIG;
511                         handshaker->state =
512                             NN_WS_HANDSHAKE_STATE_SERVER_REPLY;
513                         nn_ws_handshake_server_reply (handshaker);
514                     }
515                     else {
516                         handshaker->retries++;
517                         nn_usock_recv (handshaker->usock,
518                             handshaker->opening_hs + handshaker->recv_pos,
519                             handshaker->recv_len, NULL);
520                     }
521                     return;
522                 default:
523                     nn_fsm_error ("Unexpected handshake result",
524                         handshaker->state, src, type);
525                 }
526                 return;
527             case NN_USOCK_SHUTDOWN:
528                 /*  Ignore it and wait for ERROR event. */
529                 return;
530             case NN_USOCK_ERROR:
531                 nn_timer_stop (&handshaker->timer);
532                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
533                 return;
534             default:
535                 nn_fsm_bad_action (handshaker->state, src, type);
536             }
537 
538         case NN_WS_HANDSHAKE_SRC_TIMER:
539             switch (type) {
540             case NN_TIMER_TIMEOUT:
541                 nn_timer_stop (&handshaker->timer);
542                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
543                 return;
544             default:
545                 nn_fsm_bad_action (handshaker->state, src, type);
546             }
547 
548         default:
549             nn_fsm_bad_source (handshaker->state, src, type);
550         }
551 
552 /******************************************************************************/
553 /*  SERVER_REPLY state.                                                       */
554 /******************************************************************************/
555     case NN_WS_HANDSHAKE_STATE_SERVER_REPLY:
556         switch (src) {
557 
558         case NN_WS_HANDSHAKE_SRC_USOCK:
559             switch (type) {
560             case NN_USOCK_SENT:
561                 /*  As per RFC 6455 4.2.2, the handshake is now complete
562                     and the connection is immediately ready for send/recv. */
563                 nn_timer_stop (&handshaker->timer);
564                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE;
565             case NN_USOCK_SHUTDOWN:
566                 /*  Ignore it and wait for ERROR event. */
567                 return;
568             case NN_USOCK_ERROR:
569                 nn_timer_stop (&handshaker->timer);
570                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
571                 return;
572             default:
573                 nn_fsm_bad_action (handshaker->state, src, type);
574             }
575 
576         case NN_WS_HANDSHAKE_SRC_TIMER:
577             switch (type) {
578             case NN_TIMER_TIMEOUT:
579                 nn_timer_stop (&handshaker->timer);
580                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
581                 return;
582             default:
583                 nn_fsm_bad_action (handshaker->state, src, type);
584             }
585 
586         default:
587             nn_fsm_bad_source (handshaker->state, src, type);
588         }
589 
590 /******************************************************************************/
591 /*  CLIENT_SEND state.                                                        */
592 /******************************************************************************/
593     case NN_WS_HANDSHAKE_STATE_CLIENT_SEND:
594         switch (src) {
595 
596         case NN_WS_HANDSHAKE_SRC_USOCK:
597             switch (type) {
598             case NN_USOCK_SENT:
599                 handshaker->state = NN_WS_HANDSHAKE_STATE_CLIENT_RECV;
600                 nn_usock_recv (handshaker->usock, handshaker->response,
601                     handshaker->recv_len, NULL);
602                 return;
603             case NN_USOCK_SHUTDOWN:
604                 /*  Ignore it and wait for ERROR event. */
605                 return;
606             case NN_USOCK_ERROR:
607                 nn_timer_stop (&handshaker->timer);
608                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
609                 return;
610             default:
611                 nn_fsm_bad_action (handshaker->state, src, type);
612             }
613 
614         case NN_WS_HANDSHAKE_SRC_TIMER:
615             switch (type) {
616             case NN_TIMER_TIMEOUT:
617                 nn_timer_stop (&handshaker->timer);
618                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
619                 return;
620             default:
621                 nn_fsm_bad_action (handshaker->state, src, type);
622             }
623 
624         default:
625             nn_fsm_bad_source (handshaker->state, src, type);
626         }
627 
628 /******************************************************************************/
629 /*  CLIENT_RECV state.                                                        */
630 /******************************************************************************/
631     case NN_WS_HANDSHAKE_STATE_CLIENT_RECV:
632         switch (src) {
633 
634         case NN_WS_HANDSHAKE_SRC_USOCK:
635             switch (type) {
636             case NN_USOCK_RECEIVED:
637                 /*  Parse bytes received thus far. */
638                 switch (nn_ws_handshake_parse_server_response (handshaker)) {
639                 case NN_WS_HANDSHAKE_INVALID:
640                     /*  Opening handshake parsed successfully but does not
641                         contain valid values. Fail connection. */
642                         nn_timer_stop (&handshaker->timer);
643                         handshaker->state =
644                             NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
645                     return;
646                 case NN_WS_HANDSHAKE_VALID:
647                     /*  As per RFC 6455 4.2.2, the handshake is now complete
648                         and the connection is immediately ready for send/recv. */
649                     nn_timer_stop (&handshaker->timer);
650                     handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE;
651                     return;
652                 case NN_WS_HANDSHAKE_RECV_MORE:
653                     /*  Not enough bytes have been received to determine
654                         validity; remain in the receive state, and retrieve
655                         more bytes from client. */
656                     handshaker->recv_pos += handshaker->recv_len;
657 
658                     /*  Validate the previous recv operation. */
659                     nn_assert (handshaker->recv_pos <
660                         sizeof (handshaker->response));
661 
662                     /*  Ensure we can back-track at least the length of the
663                         termination sequence to determine how many bytes to
664                         receive on the next retry. This is an assertion, not
665                         a conditional, since under no condition is it
666                         necessary to initially receive so few bytes. */
667                     nn_assert (handshaker->recv_pos >=
668                         (int) NN_WS_HANDSHAKE_TERMSEQ_LEN);
669 
670                     /*  If i goes to 0, it no need to compare. */
671                     for (i = NN_WS_HANDSHAKE_TERMSEQ_LEN; i > 0; i--) {
672                         if (memcmp (NN_WS_HANDSHAKE_TERMSEQ,
673                             handshaker->response + handshaker->recv_pos - i,
674                             i) == 0) {
675                             break;
676                         }
677                     }
678 
679                     nn_assert (i < NN_WS_HANDSHAKE_TERMSEQ_LEN);
680 
681                     handshaker->recv_len = NN_WS_HANDSHAKE_TERMSEQ_LEN - i;
682 
683                     /*  In the unlikely case the client would overflow what we
684                         assumed was a sufficiently-large buffer to receive the
685                         handshake, we fail the connection. */
686                     if (handshaker->recv_len + handshaker->recv_pos >
687                         sizeof (handshaker->response)) {
688                         nn_timer_stop (&handshaker->timer);
689                         handshaker->state =
690                             NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
691                     }
692                     else {
693                         handshaker->retries++;
694                         nn_usock_recv (handshaker->usock,
695                             handshaker->response + handshaker->recv_pos,
696                             handshaker->recv_len, NULL);
697                     }
698                     return;
699                 default:
700                     nn_fsm_error ("Unexpected handshake result",
701                         handshaker->state, src, type);
702                 }
703                 return;
704             case NN_USOCK_SHUTDOWN:
705                 /*  Ignore it and wait for ERROR event. */
706                 return;
707             case NN_USOCK_ERROR:
708                 nn_timer_stop (&handshaker->timer);
709                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
710                 return;
711             default:
712                 nn_fsm_bad_action (handshaker->state, src, type);
713             }
714 
715         case NN_WS_HANDSHAKE_SRC_TIMER:
716             switch (type) {
717             case NN_TIMER_TIMEOUT:
718                 nn_timer_stop (&handshaker->timer);
719                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
720                 return;
721             default:
722                 nn_fsm_bad_action (handshaker->state, src, type);
723             }
724 
725         default:
726             nn_fsm_bad_source (handshaker->state, src, type);
727         }
728 
729 /******************************************************************************/
730 /*  HANDSHAKE_SENT state.                                                     */
731 /******************************************************************************/
732     case NN_WS_HANDSHAKE_STATE_HANDSHAKE_SENT:
733         switch (src) {
734 
735         case NN_WS_HANDSHAKE_SRC_USOCK:
736             switch (type) {
737             case NN_USOCK_SENT:
738                 /*  As per RFC 6455 4.2.2, the handshake is now complete
739                     and the connection is immediately ready for send/recv. */
740                 nn_timer_stop (&handshaker->timer);
741                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE;
742                 return;
743             case NN_USOCK_SHUTDOWN:
744                 /*  Ignore it and wait for ERROR event. */
745                 return;
746             case NN_USOCK_ERROR:
747                 nn_timer_stop (&handshaker->timer);
748                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
749                 return;
750             default:
751                 nn_fsm_bad_action (handshaker->state, src, type);
752             }
753 
754         case NN_WS_HANDSHAKE_SRC_TIMER:
755             switch (type) {
756             case NN_TIMER_TIMEOUT:
757                 nn_timer_stop (&handshaker->timer);
758                 handshaker->state = NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR;
759                 return;
760             default:
761                 nn_fsm_bad_action (handshaker->state, src, type);
762             }
763 
764         default:
765             nn_fsm_bad_source (handshaker->state, src, type);
766         }
767 
768 /******************************************************************************/
769 /*  STOPPING_TIMER_ERROR state.                                               */
770 /******************************************************************************/
771     case NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_ERROR:
772         switch (src) {
773 
774         case NN_WS_HANDSHAKE_SRC_USOCK:
775             /*  Ignore. The only circumstance the client would send bytes is
776                 to notify the server it is closing the connection. Wait for the
777                 socket to eventually error. */
778             return;
779 
780         case NN_WS_HANDSHAKE_SRC_TIMER:
781             switch (type) {
782             case NN_TIMER_STOPPED:
783                 nn_ws_handshake_leave (handshaker, NN_WS_HANDSHAKE_ERROR);
784                 return;
785             default:
786                 nn_fsm_bad_action (handshaker->state, src, type);
787             }
788 
789         default:
790             nn_fsm_bad_source (handshaker->state, src, type);
791         }
792 
793 /******************************************************************************/
794 /*  STOPPING_TIMER_DONE state.                                                */
795 /******************************************************************************/
796     case NN_WS_HANDSHAKE_STATE_STOPPING_TIMER_DONE:
797         switch (src) {
798 
799         case NN_WS_HANDSHAKE_SRC_USOCK:
800             /*  Ignore. The only circumstance the client would send bytes is
801                 to notify the server it is closing the connection. Wait for the
802                 socket to eventually error. */
803             return;
804 
805         case NN_WS_HANDSHAKE_SRC_TIMER:
806             switch (type) {
807             case NN_TIMER_STOPPED:
808                 nn_ws_handshake_leave (handshaker, NN_WS_HANDSHAKE_OK);
809                 return;
810             default:
811                 nn_fsm_bad_action (handshaker->state, src, type);
812             }
813 
814         default:
815             nn_fsm_bad_source (handshaker->state, src, type);
816         }
817 
818 /******************************************************************************/
819 /*  DONE state.                                                               */
820 /*  The header exchange was either done successfully of failed. There's       */
821 /*  nothing that can be done in this state except stopping the object.        */
822 /******************************************************************************/
823     case NN_WS_HANDSHAKE_STATE_DONE:
824         nn_fsm_bad_source (handshaker->state, src, type);
825 
826 /******************************************************************************/
827 /*  Invalid state.                                                            */
828 /******************************************************************************/
829     default:
830         nn_fsm_bad_state (handshaker->state, src, type);
831     }
832 }
833 
834 /******************************************************************************/
835 /*  State machine actions.                                                    */
836 /******************************************************************************/
837 
nn_ws_handshake_leave(struct nn_ws_handshake * self,int rc)838 static void nn_ws_handshake_leave (struct nn_ws_handshake *self, int rc)
839 {
840     nn_usock_swap_owner (self->usock, &self->usock_owner);
841     self->usock = NULL;
842     self->usock_owner.src = -1;
843     self->usock_owner.fsm = NULL;
844     self->state = NN_WS_HANDSHAKE_STATE_DONE;
845     nn_fsm_raise (&self->fsm, &self->done, rc);
846 }
847 
nn_ws_handshake_parse_client_opening(struct nn_ws_handshake * self)848 static int nn_ws_handshake_parse_client_opening (struct nn_ws_handshake *self)
849 {
850     /*  As per RFC 6455 section 1.7, this parser is not intended to be a
851         general-purpose parser for arbitrary HTTP headers. As with the design
852         philosophy of nanomsg, application-specific exchanges are better
853         reserved for accepted connections, not as fields within these
854         headers. */
855 
856     int rc;
857     const char *pos;
858     unsigned i;
859 
860     /*  Guarantee that a NULL terminator exists to enable treating this
861         recv buffer like a string. */
862     nn_assert (memchr (self->opening_hs, '\0', sizeof (self->opening_hs)));
863 
864     /*  Having found the NULL terminator, from this point forward string
865         functions may be used. */
866     nn_assert (strlen (self->opening_hs) < sizeof (self->opening_hs));
867 
868     pos = self->opening_hs;
869 
870     /*  Is the opening handshake from the client fully received? */
871     if (!strstr (pos, NN_WS_HANDSHAKE_TERMSEQ))
872         return NN_WS_HANDSHAKE_RECV_MORE;
873 
874     self->host = NULL;
875     self->origin = NULL;
876     self->key = NULL;
877     self->upgrade = NULL;
878     self->conn = NULL;
879     self->version = NULL;
880     self->protocol = NULL;
881     self->uri = NULL;
882 
883     self->host_len = 0;
884     self->origin_len = 0;
885     self->key_len = 0;
886     self->upgrade_len = 0;
887     self->conn_len = 0;
888     self->version_len = 0;
889     self->protocol_len = 0;
890     self->uri_len = 0;
891 
892     /*  NB: If we got here, we already have a fully received set of
893         HTTP headers.  So there is no point in asking for more if the
894         headers lack what we need. */
895 
896     /*  This function, if generating a return value that triggers
897         a response to the client, should replace this sentinel value
898         with a proper response code. */
899     self->response_code = NN_WS_HANDSHAKE_RESPONSE_NULL;
900 
901     /*  RFC 7230 3.1.1 Request Line: HTTP Method
902         Note requirement of one space and case sensitivity. */
903     if (!nn_ws_match_token ("GET\x20", &pos, 0, 0))
904         return NN_WS_HANDSHAKE_INVALID;
905 
906     /*  RFC 7230 3.1.1 Request Line: Requested Resource. */
907     if (!nn_ws_match_value ("\x20", &pos, 0, 0, &self->uri, &self->uri_len))
908         return NN_WS_HANDSHAKE_INVALID;
909 
910     /*  RFC 7230 3.1.1 Request Line: HTTP version. Note case sensitivity. */
911     if (!nn_ws_match_token ("HTTP/1.1", &pos, 0, 0))
912         return NN_WS_HANDSHAKE_INVALID;
913 
914     if (!nn_ws_match_token (CRLF, &pos, 0, 0))
915         return NN_WS_HANDSHAKE_INVALID;
916 
917     /*  It's expected the current position is now at the first
918         header field. Match them one by one. */
919     while (strlen (pos))
920     {
921         const char *conn = NULL;
922         size_t conn_len = 0;
923         if (nn_ws_match_token ("Host:", &pos, 1, 0)) {
924             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
925                 &self->host, &self->host_len);
926         }
927         else if (nn_ws_match_token ("Origin:",
928             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
929             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
930                 &self->origin, &self->origin_len);
931         }
932         else if (nn_ws_match_token ("Sec-WebSocket-Key:",
933             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
934             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
935                 &self->key, &self->key_len);
936         }
937         else if (nn_ws_match_token ("Upgrade:",
938             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
939             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
940                 &self->upgrade, &self->upgrade_len);
941         }
942         else if (nn_ws_match_token ("Connection:",
943             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
944 
945             rc = nn_ws_match_value (CRLF, &pos, 1, 1, &conn, &conn_len);
946 
947             /*  The values here can be comma delimited, or they can be
948                 listed as separate Connection headers.  We only care about
949                 the presence of the Upgrade header, and we're willing to
950                 assume well-formedness.  This crummy parse may let clients
951                 send us a malformed header that we ought to reject, but
952                 we'll just cite Postel's law here if anyone asks. */
953             self->conn = nn_strcasestr (conn, "upgrade");
954             if (self->conn != NULL) {
955                 self->conn_len = strlen ("upgrade");
956             }
957         }
958         else if (nn_ws_match_token ("Sec-WebSocket-Version:",
959             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
960             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
961                 &self->version, &self->version_len);
962         }
963         else if (nn_ws_match_token ("Sec-WebSocket-Protocol:",
964             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
965             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
966                 &self->protocol, &self->protocol_len);
967         }
968         else if (nn_ws_match_token ("Sec-WebSocket-Extensions:",
969             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
970             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
971                 &self->extensions, &self->extensions_len);
972         }
973         else if (nn_ws_match_token (CRLF,
974             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
975             /*  Exit loop since all headers are parsed. */
976             break;
977         }
978         else {
979             /*  Skip unknown headers. */
980             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
981                 NULL, NULL);
982         }
983 
984         if (rc != NN_WS_HANDSHAKE_MATCH)
985             return NN_WS_HANDSHAKE_INVALID;
986     }
987 
988     /*  Validate the opening handshake is now fully parsed. Additionally,
989         as per RFC 6455 section 4.1, the client should not send additional data
990         after the opening handshake, so this assertion validates upstream recv
991         logic prevented this case. */
992     nn_assert (strlen (pos) == 0);
993 
994     /*  TODO: protocol expectations below this point are hard-coded here as
995         an initial design decision. Perhaps in the future these values should
996         be settable via compile time (or run-time socket) options? */
997 
998     /*  These header fields are required as per RFC 6455 section 4.1. */
999     if (!self->host || !self->upgrade || !self->conn ||
1000         !self->key || !self->version) {
1001         self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSPROTO;
1002         return NN_WS_HANDSHAKE_INVALID;
1003     }
1004 
1005     /*  RFC 6455 section 4.2.1.6 (version December 2011). */
1006     if (nn_ws_validate_value ("13", self->version,
1007         self->version_len, 1) != NN_WS_HANDSHAKE_MATCH) {
1008         self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSVERSION;
1009         return NN_WS_HANDSHAKE_INVALID;
1010     }
1011 
1012     /*  RFC 6455 section 4.2.1.3 (version December 2011). */
1013     if (nn_ws_validate_value ("websocket", self->upgrade,
1014         self->upgrade_len, 1) != NN_WS_HANDSHAKE_MATCH) {
1015         self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSPROTO;
1016         return NN_WS_HANDSHAKE_INVALID;
1017     }
1018 
1019     /*  RFC 6455 section 4.2.1.4 (version December 2011). */
1020     if (nn_ws_validate_value ("Upgrade", self->conn,
1021         self->conn_len, 1) != NN_WS_HANDSHAKE_MATCH) {
1022         self->response_code = NN_WS_HANDSHAKE_RESPONSE_WSPROTO;
1023         return NN_WS_HANDSHAKE_INVALID;
1024     }
1025 
1026     /*  At this point, client meets RFC 6455 compliance for opening handshake.
1027         Now it's time to check nanomsg-imposed required handshake values. */
1028     if (self->protocol) {
1029         /*  Ensure the client SP is a compatible socket type. */
1030         for (i = 0; i < NN_WS_HANDSHAKE_SP_MAP_LEN; i++) {
1031             if (nn_ws_validate_value (NN_WS_HANDSHAKE_SP_MAP [i].ws_sp,
1032                 self->protocol, self->protocol_len, 1)) {
1033 
1034                 if (self->pipebase->sock->socktype->protocol ==
1035                     NN_WS_HANDSHAKE_SP_MAP [i].server) {
1036                     self->response_code = NN_WS_HANDSHAKE_RESPONSE_OK;
1037                     return NN_WS_HANDSHAKE_VALID;
1038                 }
1039                 else {
1040                     self->response_code = NN_WS_HANDSHAKE_RESPONSE_NOTPEER;
1041                     return NN_WS_HANDSHAKE_INVALID;
1042                 }
1043                 break;
1044             }
1045         }
1046 
1047         self->response_code = NN_WS_HANDSHAKE_RESPONSE_UNKNOWNTYPE;
1048         return NN_WS_HANDSHAKE_INVALID;
1049     }
1050     else {
1051         /*  Be permissive and generous here, assuming that if a protocol is
1052             not explicitly declared, PAIR is presumed. This enables
1053             interoperability with non-nanomsg remote peers, nominally by
1054             making the local socket PAIR type. For any other local
1055             socket type, we expect connection to be rejected as
1056             incompatible if the header is not specified. */
1057 
1058         if (nn_pipebase_ispeer (self->pipebase, NN_PAIR)) {
1059             self->response_code = NN_WS_HANDSHAKE_RESPONSE_OK;
1060             return NN_WS_HANDSHAKE_VALID;
1061         }
1062         else {
1063             self->response_code = NN_WS_HANDSHAKE_RESPONSE_NOTPEER;
1064             return NN_WS_HANDSHAKE_INVALID;
1065         }
1066     }
1067 }
1068 
nn_ws_handshake_parse_server_response(struct nn_ws_handshake * self)1069 static int nn_ws_handshake_parse_server_response (struct nn_ws_handshake *self)
1070 {
1071     /*  As per RFC 6455 section 1.7, this parser is not intended to be a
1072         general-purpose parser for arbitrary HTTP headers. As with the design
1073         philosophy of nanomsg, application-specific exchanges are better
1074         reserved for accepted connections, not as fields within these
1075         headers. */
1076 
1077     int rc;
1078     const char *pos;
1079 
1080     /*  Guarantee that a NULL terminator exists to enable treating this
1081         recv buffer like a string. The lack of such would indicate a failure
1082         upstream to catch a buffer overflow. */
1083     nn_assert (memchr (self->response, '\0', sizeof (self->response)));
1084 
1085     /*  Having found the NULL terminator, from this point forward string
1086         functions may be used. */
1087     nn_assert (strlen (self->response) < sizeof (self->response));
1088 
1089     pos = self->response;
1090 
1091     /*  Is the response from the server fully received? */
1092     if (!strstr (pos, NN_WS_HANDSHAKE_TERMSEQ))
1093         return NN_WS_HANDSHAKE_RECV_MORE;
1094 
1095     self->status_code = NULL;
1096     self->reason_phrase = NULL;
1097     self->server = NULL;
1098     self->accept_key = NULL;
1099     self->upgrade = NULL;
1100     self->conn = NULL;
1101     self->version = NULL;
1102     self->protocol = NULL;
1103 
1104     self->status_code_len = 0;
1105     self->reason_phrase_len = 0;
1106     self->server_len = 0;
1107     self->accept_key_len = 0;
1108     self->upgrade_len = 0;
1109     self->conn_len = 0;
1110     self->version_len = 0;
1111     self->protocol_len = 0;
1112 
1113     /*  RFC 7230 3.1.2 Status Line: HTTP Version. */
1114     if (!nn_ws_match_token ("HTTP/1.1\x20", &pos, 0, 0))
1115         return NN_WS_HANDSHAKE_RECV_MORE;
1116 
1117     /*  RFC 7230 3.1.2 Status Line: Status Code. */
1118     if (!nn_ws_match_value ("\x20", &pos, 0, 0, &self->status_code,
1119         &self->status_code_len))
1120         return NN_WS_HANDSHAKE_RECV_MORE;
1121 
1122     /*  RFC 7230 3.1.2 Status Line: Reason Phrase. */
1123     if (!nn_ws_match_value (CRLF, &pos, 0, 0,
1124         &self->reason_phrase, &self->reason_phrase_len))
1125         return NN_WS_HANDSHAKE_RECV_MORE;
1126 
1127     /*  It's expected the current position is now at the first
1128         header field. Match them one by one. */
1129     while (strlen (pos))
1130     {
1131         if (nn_ws_match_token ("Server:", &pos, 1, 0)) {
1132             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1133                 &self->server, &self->server_len);
1134         }
1135         else if (nn_ws_match_token ("Sec-WebSocket-Accept:",
1136             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1137             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1138                 &self->accept_key, &self->accept_key_len);
1139         }
1140         else if (nn_ws_match_token ("Upgrade:",
1141             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1142             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1143                 &self->upgrade, &self->upgrade_len);
1144         }
1145         else if (nn_ws_match_token ("Connection:",
1146             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1147             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1148                 &self->conn, &self->conn_len);
1149         }
1150         else if (nn_ws_match_token ("Sec-WebSocket-Version-Server:",
1151             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1152             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1153                 &self->version, &self->version_len);
1154         }
1155         else if (nn_ws_match_token ("Sec-WebSocket-Protocol-Server:",
1156             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1157             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1158                 &self->protocol, &self->protocol_len);
1159         }
1160         else if (nn_ws_match_token ("Sec-WebSocket-Extensions:",
1161             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1162             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1163                 &self->extensions, &self->extensions_len);
1164         }
1165         else if (nn_ws_match_token (CRLF,
1166             &pos, 1, 0) == NN_WS_HANDSHAKE_MATCH) {
1167             /*  Exit loop since all headers are parsed. */
1168             break;
1169         }
1170         else {
1171             /*  Skip unknown headers. */
1172             rc = nn_ws_match_value (CRLF, &pos, 1, 1,
1173                 NULL, NULL);
1174         }
1175 
1176         if (rc != NN_WS_HANDSHAKE_MATCH)
1177             return NN_WS_HANDSHAKE_RECV_MORE;
1178     }
1179 
1180     /*  Validate the opening handshake is now fully parsed. Additionally,
1181         as per RFC 6455 section 4.1, the client should not send additional data
1182         after the opening handshake, so this assertion validates upstream recv
1183         logic prevented this case. */
1184     nn_assert (strlen (pos) == 0);
1185 
1186     /*  TODO: protocol expectations below this point are hard-coded here as
1187         an initial design decision. Perhaps in the future these values should
1188         be settable via compile time (or run-time socket) options? */
1189 
1190     /*  These header fields are required as per RFC 6455 4.2.2. */
1191     if (!self->status_code || !self->upgrade || !self->conn ||
1192         !self->accept_key)
1193         return NN_WS_HANDSHAKE_INVALID;
1194 
1195     /*  TODO: Currently, we only handle a successful connection upgrade.
1196         Anything else is treated as a failed connection.
1197         Consider handling other scenarios like 3xx redirects. */
1198     if (nn_ws_validate_value ("101", self->status_code,
1199         self->status_code_len, 1) != NN_WS_HANDSHAKE_MATCH)
1200         return NN_WS_HANDSHAKE_INVALID;
1201 
1202     /*  RFC 6455 section 4.2.2.5.2 (version December 2011). */
1203     if (nn_ws_validate_value ("websocket", self->upgrade,
1204         self->upgrade_len, 1) != NN_WS_HANDSHAKE_MATCH)
1205         return NN_WS_HANDSHAKE_INVALID;
1206 
1207     /*  RFC 6455 section 4.2.2.5.3 (version December 2011). */
1208     if (nn_ws_validate_value ("Upgrade", self->conn,
1209         self->conn_len, 1) != NN_WS_HANDSHAKE_MATCH)
1210         return NN_WS_HANDSHAKE_INVALID;
1211 
1212     /*  RFC 6455 section 4.2.2.5.4 (version December 2011). */
1213     if (nn_ws_validate_value (self->expected_accept_key, self->accept_key,
1214         self->accept_key_len, 1) != NN_WS_HANDSHAKE_MATCH)
1215         return NN_WS_HANDSHAKE_INVALID;
1216 
1217     /*  Server response meets RFC 6455 compliance for opening handshake. */
1218     return NN_WS_HANDSHAKE_VALID;
1219 }
1220 
nn_ws_handshake_client_request(struct nn_ws_handshake * self)1221 static void nn_ws_handshake_client_request (struct nn_ws_handshake *self)
1222 {
1223     struct nn_iovec open_request;
1224     size_t encoded_key_len;
1225     int rc;
1226     unsigned i;
1227 
1228     /*  Generate random 16-byte key as per RFC 6455 4.1 */
1229     uint8_t rand_key [16];
1230 
1231     /*  Known length required to base64 encode above random key plus
1232         string NULL terminator. */
1233     char encoded_key [24 + 1];
1234 
1235     nn_random_generate (rand_key, sizeof (rand_key));
1236 
1237     rc = nn_base64_encode (rand_key, sizeof (rand_key),
1238         encoded_key, sizeof (encoded_key));
1239     nn_assert (rc >=0);
1240 
1241     encoded_key_len = strlen (encoded_key);
1242 
1243     nn_assert (encoded_key_len == sizeof (encoded_key) - 1);
1244 
1245     /*  Pre-calculated expected Accept Key value as per
1246         RFC 6455 section 4.2.2.5.4 (version December 2011). */
1247     rc = nn_ws_handshake_hash_key (encoded_key, encoded_key_len,
1248         self->expected_accept_key, sizeof (self->expected_accept_key));
1249 
1250     nn_assert (rc == NN_WS_HANDSHAKE_ACCEPT_KEY_LEN);
1251 
1252     /*  Lookup SP header value. */
1253     for (i = 0; i < NN_WS_HANDSHAKE_SP_MAP_LEN; i++) {
1254         if (NN_WS_HANDSHAKE_SP_MAP [i].client ==
1255             self->pipebase->sock->socktype->protocol) {
1256             break;
1257         }
1258     }
1259 
1260     /*  Guarantee that the socket type was found in the map. */
1261     nn_assert (i < NN_WS_HANDSHAKE_SP_MAP_LEN);
1262 
1263     sprintf (self->opening_hs,
1264         "GET %s HTTP/1.1\r\n"
1265         "Host: %s\r\n"
1266         "Upgrade: websocket\r\n"
1267         "Connection: Upgrade\r\n"
1268         "Sec-WebSocket-Key: %s\r\n"
1269         "Sec-WebSocket-Version: 13\r\n"
1270         "Sec-WebSocket-Protocol: %s\r\n\r\n",
1271         self->resource, self->remote_host, encoded_key,
1272         NN_WS_HANDSHAKE_SP_MAP[i].ws_sp);
1273 
1274     open_request.iov_len = strlen (self->opening_hs);
1275     open_request.iov_base = self->opening_hs;
1276 
1277     nn_usock_send (self->usock, &open_request, 1);
1278 }
1279 
nn_ws_handshake_server_reply(struct nn_ws_handshake * self)1280 static void nn_ws_handshake_server_reply (struct nn_ws_handshake *self)
1281 {
1282     struct nn_iovec response;
1283     char *code;
1284     char *version;
1285     char *protocol;
1286     int rc;
1287 
1288     /*  Allow room for NULL terminator. */
1289     char accept_key [NN_WS_HANDSHAKE_ACCEPT_KEY_LEN + 1];
1290 
1291     memset (self->response, 0, sizeof (self->response));
1292 
1293     if (self->response_code == NN_WS_HANDSHAKE_RESPONSE_OK) {
1294         /*  Upgrade connection as per RFC 6455 section 4.2.2. */
1295 
1296         rc = nn_ws_handshake_hash_key (self->key, self->key_len,
1297             accept_key, sizeof (accept_key));
1298         nn_assert (rc >= 0);
1299 
1300         nn_assert (strlen (accept_key) == NN_WS_HANDSHAKE_ACCEPT_KEY_LEN);
1301 
1302         protocol = nn_alloc (self->protocol_len + 1, "WebSocket protocol");
1303         alloc_assert (protocol);
1304         strncpy (protocol, self->protocol, self->protocol_len);
1305         protocol [self->protocol_len] = '\0';
1306 
1307         sprintf (self->response,
1308             "HTTP/1.1 101 Switching Protocols\r\n"
1309             "Upgrade: websocket\r\n"
1310             "Connection: Upgrade\r\n"
1311             "Sec-WebSocket-Accept: %s\r\n"
1312             "Sec-WebSocket-Protocol: %s\r\n\r\n",
1313             accept_key, protocol);
1314 
1315         nn_free (protocol);
1316     }
1317     else {
1318         /*  Fail the connection with a helpful hint. */
1319         switch (self->response_code) {
1320         case NN_WS_HANDSHAKE_RESPONSE_TOO_BIG:
1321             code = "400 Opening Handshake Too Long";
1322             break;
1323         case NN_WS_HANDSHAKE_RESPONSE_WSPROTO:
1324             code = "400 Cannot Have Body";
1325             break;
1326         case NN_WS_HANDSHAKE_RESPONSE_WSVERSION:
1327             code = "400 Unsupported WebSocket Version";
1328             break;
1329         case NN_WS_HANDSHAKE_RESPONSE_NNPROTO:
1330             code = "400 Missing nanomsg Required Headers";
1331             break;
1332         case NN_WS_HANDSHAKE_RESPONSE_NOTPEER:
1333             code = "400 Incompatible Socket Type";
1334             break;
1335         case NN_WS_HANDSHAKE_RESPONSE_UNKNOWNTYPE:
1336             code = "400 Unrecognized Socket Type";
1337             break;
1338         default:
1339             /*  Unexpected failure response. */
1340             nn_assert (0);
1341             break;
1342         }
1343 
1344         version = nn_alloc (self->version_len + 1, "WebSocket version");
1345         alloc_assert (version);
1346         strncpy (version, self->version, self->version_len);
1347         version [self->version_len] = '\0';
1348 
1349         /*  Fail connection as per RFC 6455 4.4. */
1350         sprintf (self->response,
1351             "HTTP/1.1 %s\r\n"
1352             "Sec-WebSocket-Version: %s\r\n",
1353             code, version);
1354 
1355         nn_free (version);
1356     }
1357 
1358     response.iov_len = strlen (self->response);
1359     response.iov_base = &self->response;
1360 
1361     nn_usock_send (self->usock, &response, 1);
1362 
1363     return;
1364 }
1365 
nn_ws_handshake_hash_key(const char * key,size_t key_len,char * hashed,size_t hashed_len)1366 static int nn_ws_handshake_hash_key (const char *key, size_t key_len,
1367     char *hashed, size_t hashed_len)
1368 {
1369     int rc;
1370     unsigned i;
1371     struct nn_sha1 hash;
1372 
1373     nn_sha1_init (&hash);
1374 
1375     for (i = 0; i < key_len; i++)
1376         nn_sha1_hashbyte (&hash, key [i]);
1377 
1378     for (i = 0; i < strlen (NN_WS_HANDSHAKE_MAGIC_GUID); i++)
1379         nn_sha1_hashbyte (&hash, NN_WS_HANDSHAKE_MAGIC_GUID [i]);
1380 
1381     rc = nn_base64_encode (nn_sha1_result (&hash),
1382         sizeof (hash.state), hashed, hashed_len);
1383 
1384     return rc;
1385 }
1386 
1387