client convert to new headers scheme eliminating mallocs

This removes all the direct wsi members specific to clients,
most of them are moved to being fake headers in the next 3-layer
header scheme, c_port moves to being a member of the u.hdr
unionized struct.

It gets rid of a lot of fiddly mallocs and frees(), despite it
adds a small internal API to create the fake headers, actually
the patch deletes more than it adds...

Signed-off-by: Andy Green <andy.green@linaro.org>
diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index 01aae4d..1a0d362 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -9,6 +9,7 @@
 	struct sockaddr_in server_addr;
 	int n;
 	int plen = 0;
+	const char *ads;
 
 	lwsl_client("__libwebsocket_client_connect_2\n");
 
@@ -21,25 +22,29 @@
 			"CONNECT %s:%u HTTP/1.0\x0d\x0a"
 			"User-agent: libwebsockets\x0d\x0a"
 /*Proxy-authorization: basic aGVsbG86d29ybGQ= */
-			"\x0d\x0a", wsi->c_address, wsi->c_port);
+			"\x0d\x0a",
+			lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS),
+			wsi->u.hdr.c_port);
 
-		/* OK from now on we talk via the proxy */
+		/* OK from now on we talk via the proxy, so connect to that */
 
-		free(wsi->c_address);
-		wsi->c_address = strdup(context->http_proxy_address);
-		wsi->c_port = context->http_proxy_port;
+		/* (will overwrite existing pointer, leaving old string/frag there but unreferenced) */
+		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, context->http_proxy_address))
+			goto oom4;
+		wsi->u.hdr.c_port = context->http_proxy_port;
 	}
 
 	/*
 	 * prepare the actual connection (to the proxy, if any)
 	 */
 
-	lwsl_client("__libwebsocket_client_connect_2: address %s\n",
-								wsi->c_address);
+	ads = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS);
 
-	server_hostent = gethostbyname(wsi->c_address);
+	lwsl_client("__libwebsocket_client_connect_2: address %s\n", ads);
+
+	server_hostent = gethostbyname(ads);
 	if (server_hostent == NULL) {
-		lwsl_err("Unable to get host name from %s\n", wsi->c_address);
+		lwsl_err("Unable to get host name from %s\n", ads);
 		goto oom4;
 	}
 
@@ -51,7 +56,7 @@
 	}
 
 	server_addr.sin_family = AF_INET;
-	server_addr.sin_port = htons(wsi->c_port);
+	server_addr.sin_port = htons(wsi->u.hdr.c_port);
 	server_addr.sin_addr = *((struct in_addr *)server_hostent->h_addr);
 	bzero(&server_addr.sin_zero, 8);
 
@@ -119,15 +124,7 @@
 	return wsi;
 
 oom4:
-	if (wsi->c_protocol)
-		free(wsi->c_protocol);
-
-	if (wsi->c_origin)
-		free(wsi->c_origin);
-
-	free(wsi->c_host);
-	free(wsi->c_path);
-
+	free(wsi->u.hdr.ah);
 bail1:
 	free(wsi);
 
@@ -203,58 +200,37 @@
 	wsi->use_ssl = ssl_connection;
 #endif
 
-	wsi->c_port = port;
-	wsi->c_address = strdup(address);
-
-	/* copy parameters over so state machine has access */
-
-	wsi->c_path = (char *)malloc(strlen(path) + 1);
-	if (wsi->c_path == NULL)
-		goto bail1;
-	strcpy(wsi->c_path, path);
-
-	wsi->c_host = (char *)malloc(strlen(host) + 1);
-	if (wsi->c_host == NULL)
-		goto oom1;
-	strcpy(wsi->c_host, host);
-
-	if (origin) {
-		wsi->c_origin = (char *)malloc(strlen(origin) + 1);
-		if (wsi->c_origin == NULL)
-			goto oom2;
-		strcpy(wsi->c_origin, origin);
-	} else
-		wsi->c_origin = NULL;
-
-	wsi->c_callback = NULL;
-	if (protocol) {
-		const char *pc;
-		struct libwebsocket_protocols *pp;
-
-		wsi->c_protocol = (char *)malloc(strlen(protocol) + 1);
-		if (wsi->c_protocol == NULL)
-			goto oom3;
-
-		strcpy(wsi->c_protocol, protocol);
-
-		pc = protocol;
-		while (*pc && *pc != ',')
-			pc++;
-		n = pc - protocol;
-		pp = context->protocols;
-		while (pp->name && !wsi->c_callback) {
-			if (!strncmp(protocol, pp->name, n))
-				wsi->c_callback = pp->callback;
-			pp++;
-		}
-	} else
-		wsi->c_protocol = NULL;
-
-	if (!wsi->c_callback)
-		wsi->c_callback = context->protocols[0].callback;
-
 	if (lws_allocate_header_table(wsi))
-		goto oom3;
+		goto bail;
+
+	/*
+	 * we're not necessarily in a position to action these right away,
+	 * stash them... we only need during connect phase so u.hdr is fine
+	 */
+	wsi->u.hdr.c_port = port;
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
+		goto bail1;
+
+	/* these only need u.hdr lifetime as well */
+
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
+		goto bail1;
+
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
+		goto bail1;
+
+	if (origin)
+		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_ORIGIN, origin))
+			goto bail1;
+	/*
+	 * this is a list of protocols we tell the server we're okay with
+	 * stash it for later when we compare server response with it
+	 */
+	if (protocol)
+		if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS, protocol))
+			goto bail1;
+
+	wsi->protocol = &context->protocols[0];
 
 #ifndef LWS_NO_EXTENSIONS
 	/*
@@ -293,17 +269,9 @@
 
 	return __libwebsocket_client_connect_2(context, wsi);
 
-oom3:
-	if (wsi->c_origin)
-		free(wsi->c_origin);
-
-oom2:
-	free(wsi->c_host);
-
-oom1:
-	free(wsi->c_path);
-
 bail1:
+	free(wsi->u.hdr.ah);
+bail:
 	free(wsi);
 
 	return NULL;
diff --git a/lib/client.c b/lib/client.c
index 200b3ad..c9c6274 100644
--- a/lib/client.c
+++ b/lib/client.c
@@ -309,8 +309,6 @@
 		return lws_client_interpret_server_handshake(context, wsi);
 
 bail3:
-		if (wsi->c_protocol)
-			free(wsi->c_protocol);
 		lwsl_info("closing connection at LWS_CONNMODE_WS_CLIENT_WAITING_SERVER_REPLY\n");
 		libwebsocket_close_and_free_session(context, wsi,
 						    LWS_CLOSE_STATUS_NOSTATUS);
@@ -398,7 +396,7 @@
 		goto bail3;
 	}
 
-	pc = wsi->c_protocol;
+	pc = lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS);
 	if (pc == NULL)
 		lwsl_parser("lws_client_interpret_server_handshake: "
 							  "NULL c_protocol\n");
@@ -421,9 +419,6 @@
 		 * default to first protocol
 		 */
 		wsi->protocol = &context->protocols[0];
-		wsi->c_callback = wsi->protocol->callback;
-		free(wsi->c_protocol);
-
 		goto check_extensions;
 	}
 
@@ -441,11 +436,6 @@
 			pc++;
 	}
 
-	/* done with him now */
-
-	if (wsi->c_protocol)
-		free(wsi->c_protocol);
-
 	if (!okay) {
 		lwsl_err("libwebsocket_client_handshake server "
 					"sent bad protocol '%s'\n", p);
@@ -460,7 +450,6 @@
 	while (context->protocols[n].callback && !wsi->protocol) {
 		if (strcmp(p, context->protocols[n].name) == 0) {
 			wsi->protocol = &context->protocols[n];
-			wsi->c_callback = wsi->protocol->callback;
 			break;
 		}
 		n++;
@@ -659,12 +648,10 @@
 	return 0;
 
 bail3:
-	if (wsi->c_protocol)
-		free(wsi->c_protocol);
 
 bail2:
-	if (wsi->c_callback)
-		wsi->c_callback(context, wsi,
+	if (wsi->protocol)
+		wsi->protocol->callback(context, wsi,
 			LWS_CALLBACK_CLIENT_CONNECTION_ERROR,
 						      wsi->user_space, NULL, 0);
 
@@ -707,12 +694,6 @@
 	if (n != 16) {
 		lwsl_err("Unable to read from random dev %s\n",
 						SYSTEM_RANDOM_FILEPATH);
-		free(wsi->c_path);
-		free(wsi->c_host);
-		if (wsi->c_origin)
-			free(wsi->c_origin);
-		if (wsi->c_protocol)
-			free(wsi->c_protocol);
 		libwebsocket_close_and_free_session(context, wsi,
 					     LWS_CLOSE_STATUS_NOSTATUS);
 		return NULL;
@@ -746,28 +727,24 @@
 	 * Sec-WebSocket-Version: 4
 	 */
 
-	p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", wsi->c_path);
+	p += sprintf(p, "GET %s HTTP/1.1\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_URI));
 
 	p += sprintf(p, "Pragma: no-cache\x0d\x0a"
 					"Cache-Control: no-cache\x0d\x0a");
 
-	p += sprintf(p, "Host: %s\x0d\x0a", wsi->c_host);
+	p += sprintf(p, "Host: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_HOST));
 	p += sprintf(p, "Upgrade: websocket\x0d\x0a"
 					"Connection: Upgrade\x0d\x0a"
 					"Sec-WebSocket-Key: ");
 	strcpy(p, key_b64);
 	p += strlen(key_b64);
 	p += sprintf(p, "\x0d\x0a");
-	if (wsi->c_origin) {
-	        if (wsi->ietf_spec_revision == 13)
-			p += sprintf(p, "Origin: %s\x0d\x0a", wsi->c_origin);
-	        else
-			p += sprintf(p, "Sec-WebSocket-Origin: %s\x0d\x0a",
-							 wsi->c_origin);
-	}
-	if (wsi->c_protocol)
+	if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN))
+		p += sprintf(p, "Origin: %s\x0d\x0a", lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_ORIGIN));
+
+	if (lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS))
 		p += sprintf(p, "Sec-WebSocket-Protocol: %s\x0d\x0a",
-						       wsi->c_protocol);
+				lws_hdr_simple_ptr(wsi, _WSI_TOKEN_CLIENT_SENT_PROTOCOLS));
 
 	/* tell the server what extensions we could support */
 
@@ -843,13 +820,6 @@
 			wsi->u.hdr.initial_handshake_hash_base64,
 			     sizeof wsi->u.hdr.initial_handshake_hash_base64);
 
-	/* done with these now */
-
-	free(wsi->c_path);
-	free(wsi->c_host);
-	if (wsi->c_origin)
-		free(wsi->c_origin);
-
 	return p;
 }
 
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 4d0f474..d8abe7e 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -358,10 +358,6 @@
 	}
 #endif
 
-#ifndef LWS_NO_CLIENT
-	if (wsi->c_address)
-		free(wsi->c_address);
-#endif
 	if (wsi->u.ws.rxflow_buffer)
 		free(wsi->u.ws.rxflow_buffer);
 
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index 8ead410..98c76c0 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -240,6 +240,14 @@
 	WSI_TOKEN_HTTP,
 	WSI_TOKEN_MUXURL,
 
+	/* use token storage to stash these */
+
+	_WSI_TOKEN_CLIENT_SENT_PROTOCOLS,
+	_WSI_TOKEN_CLIENT_PEER_ADDRESS,
+	_WSI_TOKEN_CLIENT_URI,
+	_WSI_TOKEN_CLIENT_HOST,
+	_WSI_TOKEN_CLIENT_ORIGIN,
+
 	/* always last real token index*/
 	WSI_TOKEN_COUNT,
 	/* parser state additions */
diff --git a/lib/parsers.c b/lib/parsers.c
index e445aac..dcd5383 100644
--- a/lib/parsers.c
+++ b/lib/parsers.c
@@ -370,6 +370,33 @@
 	return &wsi->u.hdr.ah->data[wsi->u.hdr.ah->frags[n].offset];
 }
 
+int lws_hdr_simple_create(struct libwebsocket *wsi, enum lws_token_indexes h, const char *s)
+{
+	wsi->u.hdr.ah->next_frag_index++;
+	if (wsi->u.hdr.ah->next_frag_index == sizeof(wsi->u.hdr.ah->frags) / sizeof(wsi->u.hdr.ah->frags[0])) {
+		lwsl_warn("More header fragments than we can deal with, dropping\n");
+		return -1;
+	}
+
+	wsi->u.hdr.ah->frag_index[h] = wsi->u.hdr.ah->next_frag_index;
+
+	wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].offset = wsi->u.hdr.ah->pos;
+	wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len = 0;
+	wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].next_frag_index = 0;
+
+	do {
+		if (wsi->u.hdr.ah->pos == sizeof wsi->u.hdr.ah->data) {
+			lwsl_err("Ran out of header data space\n");
+			return -1;
+		}
+		wsi->u.hdr.ah->data[wsi->u.hdr.ah->pos++] = *s;
+		if (*s)
+			wsi->u.hdr.ah->frags[wsi->u.hdr.ah->next_frag_index].len++;
+	} while (*s++);
+
+	return 0;
+}
+
 int libwebsocket_parse(struct libwebsocket *wsi, unsigned char c)
 {
 	int n;
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index a24d584..3ab20c9 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -330,6 +330,7 @@
 	int current_alloc_len;
 #ifndef LWS_NO_CLIENT
 	char initial_handshake_hash_base64[30];
+	unsigned short c_port;
 #endif
 };
 
@@ -391,17 +392,6 @@
 		struct _lws_websocket_related ws;
 	} u;
 
-#ifndef LWS_NO_CLIENT
-	char *c_path;
-	char *c_host;
-	char *c_origin;
-	char *c_protocol;
-	callback_function *c_callback;
-
-	char *c_address;
-	unsigned short c_port;
-#endif
-
 #ifdef LWS_OPENSSL_SUPPORT
 	SSL *ssl;
 	BIO *client_bio;
@@ -504,6 +494,9 @@
 extern char *
 lws_hdr_simple_ptr(struct libwebsocket *wsi, enum lws_token_indexes h);
 
+extern int
+lws_hdr_simple_create(struct libwebsocket *wsi, enum lws_token_indexes h, const char *s);
+
 #ifndef LWS_OPENSSL_SUPPORT
 
 unsigned char *