about summary refs log tree commit diff
path: root/src/engine/external/libwebsockets/handshake.c
diff options
context:
space:
mode:
authoreeeee <eeeee@qwe123.info>2015-02-07 14:15:19 -0800
committerdef <dennis@felsin9.de>2015-04-19 16:05:13 +0200
commit424ce4987ced7deda3e355b7b6373680bf506646 (patch)
tree239537b1938ac18c6542a05088bc26c6a2860408 /src/engine/external/libwebsockets/handshake.c
parent9bbe115c522835c34c29196f2595c29c6bf00701 (diff)
downloadzcatch-424ce4987ced7deda3e355b7b6373680bf506646.tar.gz
zcatch-424ce4987ced7deda3e355b7b6373680bf506646.zip
added libwebsockets source code
Diffstat (limited to 'src/engine/external/libwebsockets/handshake.c')
-rw-r--r--src/engine/external/libwebsockets/handshake.c232
1 files changed, 232 insertions, 0 deletions
diff --git a/src/engine/external/libwebsockets/handshake.c b/src/engine/external/libwebsockets/handshake.c
new file mode 100644
index 00000000..856297db
--- /dev/null
+++ b/src/engine/external/libwebsockets/handshake.c
@@ -0,0 +1,232 @@
+/*
+ * libwebsockets - small server side websockets and web server implementation
+ *
+ * Copyright (C) 2010-2013 Andy Green <andy@warmcat.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation:
+ *  version 2.1 of the License.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ *  MA  02110-1301  USA
+ */
+
+#include "private-libwebsockets.h"
+
+/*
+ * -04 of the protocol (actually the 80th version) has a radically different
+ * handshake.  The 04 spec gives the following idea
+ *
+ *    The handshake from the client looks as follows:
+ *
+ *      GET /chat HTTP/1.1
+ *      Host: server.example.com
+ *      Upgrade: websocket
+ *      Connection: Upgrade
+ *      Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
+ *      Sec-WebSocket-Origin: http://example.com
+ *      Sec-WebSocket-Protocol: chat, superchat
+ *	Sec-WebSocket-Version: 4
+ *
+ *  The handshake from the server looks as follows:
+ *
+ *       HTTP/1.1 101 Switching Protocols
+ *       Upgrade: websocket
+ *       Connection: Upgrade
+ *       Sec-WebSocket-Accept: me89jWimTRKTWwrS3aRrL53YZSo=
+ *       Sec-WebSocket-Nonce: AQIDBAUGBwgJCgsMDQ4PEC==
+ *       Sec-WebSocket-Protocol: chat
+ */
+
+#ifndef min
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#endif
+/*
+ * We have to take care about parsing because the headers may be split
+ * into multiple fragments.  They may contain unknown headers with arbitrary
+ * argument lengths.  So, we parse using a single-character at a time state
+ * machine that is completely independent of packet size.
+ */
+
+LWS_VISIBLE int
+libwebsocket_read(struct libwebsocket_context *context,
+		     struct libwebsocket *wsi, unsigned char *buf, size_t len)
+{
+	size_t n;
+	int body_chunk_len;
+	unsigned char *last_char;
+
+	switch (wsi->state) {
+#ifdef LWS_USE_HTTP2
+	case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE:
+	case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS:
+	case WSI_STATE_HTTP2_ESTABLISHED:
+		n = 0;
+		while (n < len) {
+			/*
+			 * we were accepting input but now we stopped doing so
+			 */
+			if (!(wsi->rxflow_change_to & LWS_RXFLOW_ALLOW)) {
+				lws_rxflow_cache(wsi, buf, n, len);
+
+				return 1;
+			}
+
+			/* account for what we're using in rxflow buffer */
+			if (wsi->rxflow_buffer)
+				wsi->rxflow_pos++;
+			if (lws_http2_parser(context, wsi, buf[n++]))
+				goto bail;
+		}
+		break;
+#endif
+http_new:
+	case WSI_STATE_HTTP:
+		wsi->hdr_parsing_completed = 0;
+		/* fallthru */
+	case WSI_STATE_HTTP_ISSUING_FILE:
+		wsi->state = WSI_STATE_HTTP_HEADERS;
+		wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
+		wsi->u.hdr.lextable_pos = 0;
+		/* fallthru */
+	case WSI_STATE_HTTP_HEADERS:
+		lwsl_parser("issuing %d bytes to parser\n", (int)len);
+
+		if (lws_handshake_client(wsi, &buf, len))
+			goto bail;
+
+		last_char = buf;
+		if (lws_handshake_server(context, wsi, &buf, len))
+			/* Handshake indicates this session is done. */
+			goto bail;
+
+		/* It's possible that we've exhausted our data already, but
+		 * lws_handshake_server doesn't update len for us. Figure out how
+		 * much was read, so that we can proceed appropriately: */
+		len -= (buf - last_char);
+
+		if (!wsi->hdr_parsing_completed)
+			/* More header content on the way */
+			goto read_ok;
+
+		switch (wsi->state) {
+			case WSI_STATE_HTTP:
+			case WSI_STATE_HTTP_HEADERS:
+				goto http_complete;
+			case WSI_STATE_HTTP_ISSUING_FILE:
+				goto read_ok;
+			case WSI_STATE_HTTP_BODY:
+				wsi->u.http.content_remain = wsi->u.http.content_length;
+				goto http_postbody;
+			default:
+				break;
+		}
+		break;
+
+	case WSI_STATE_HTTP_BODY:
+http_postbody:
+		while (len && wsi->u.http.content_remain) {
+			/* Copy as much as possible, up to the limit of:
+			 * what we have in the read buffer (len)
+			 * remaining portion of the POST body (content_remain)
+			 */
+			body_chunk_len = min(wsi->u.http.content_remain,len);
+			wsi->u.http.content_remain -= body_chunk_len;
+			len -= body_chunk_len;
+
+			if (wsi->protocol->callback) {
+				n = wsi->protocol->callback(
+					wsi->protocol->owning_server, wsi,
+					LWS_CALLBACK_HTTP_BODY, wsi->user_space,
+					buf, body_chunk_len);
+				if (n)
+					goto bail;
+			}
+			buf += body_chunk_len;
+
+			if (!wsi->u.http.content_remain)  {
+				/* he sent the content in time */
+				libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+				if (wsi->protocol->callback) {
+					n = wsi->protocol->callback(
+						wsi->protocol->owning_server, wsi,
+						LWS_CALLBACK_HTTP_BODY_COMPLETION,
+						wsi->user_space, NULL, 0);
+					if (n)
+						goto bail;
+				}
+				goto http_complete;
+			} else
+				libwebsocket_set_timeout(wsi,
+					PENDING_TIMEOUT_HTTP_CONTENT,
+					AWAITING_TIMEOUT);
+		}
+		break;
+
+	case WSI_STATE_ESTABLISHED:
+	case WSI_STATE_AWAITING_CLOSE_ACK:
+		if (lws_handshake_client(wsi, &buf, len))
+			goto bail;
+		switch (wsi->mode) {
+		case LWS_CONNMODE_WS_SERVING:
+
+			if (libwebsocket_interpret_incoming_packet(wsi, buf, len) < 0) {
+				lwsl_info("interpret_incoming_packet has bailed\n");
+				goto bail;
+			}
+			break;
+		}
+		break;
+	default:
+		lwsl_err("libwebsocket_read: Unhandled state\n");
+		break;
+	}
+
+read_ok:
+	/* Nothing more to do for now. */
+	lwsl_debug("libwebsocket_read: read_ok\n");
+
+	return 0;
+
+http_complete:
+	lwsl_debug("libwebsocket_read: http_complete\n");
+
+	/* Did the client want to keep the HTTP connection going? */
+
+	if (wsi->u.http.connection_type == HTTP_CONNECTION_KEEP_ALIVE) {
+		lwsl_debug("libwebsocket_read: keep-alive\n");
+		wsi->state = WSI_STATE_HTTP;
+		wsi->mode = LWS_CONNMODE_HTTP_SERVING;
+
+		/* He asked for it to stay alive indefinitely */
+		libwebsocket_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
+
+		if (lws_allocate_header_table(wsi))
+			goto bail;
+
+		/* If we're (re)starting on headers, need other implied init */
+		wsi->u.hdr.ues = URIES_IDLE;
+
+		/* If we have more data, loop back around: */
+		if (len)
+			goto http_new;
+
+		return 0;
+	}
+
+bail:
+	lwsl_debug("closing connection at libwebsocket_read bail:\n");
+
+	libwebsocket_close_and_free_session(context, wsi,
+						     LWS_CLOSE_STATUS_NOSTATUS);
+
+	return -1;
+}