diff --git a/changelog b/changelog
index 9be1268402e6d5b9e9c63c125763dc1543b1ec24..8ce86c9febdcdcfe77917db7f079b7aadba715dd 100644
--- a/changelog
+++ b/changelog
@@ -149,6 +149,13 @@ There are 4 new related callbacks
 	LWS_CALLBACK_RECEIVE_CLIENT_HTTP			= 46,
 	LWS_CALLBACK_COMPLETED_CLIENT_HTTP			= 47,
 
+6) struct lws_client_connect_info has a new member
+
+ const char *parent_wsi
+ 
+if non-NULL, the client wsi is set to be a child of parent_wsi.  This ensures
+if parent_wsi closes, then the client child is closed just before.
+
 
 v1.7.0
 ======
diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index d1baa0eb26ada26c22016cba4c6185cb6bee1407..ba7a44afd406520a1fb409e41da19665e39ae9c0 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -407,7 +407,12 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 	if (wsi && !wsi->user_space && i->userdata) {
 		wsi->user_space_externally_allocated = 1;
 		wsi->user_space = i->userdata;
-	}
+	} else
+		/* if we stay in http, we can assign the user space now,
+		 * otherwise do it after the protocol negotiated
+		 */
+		if (i->method)
+			lws_ensure_user_space(wsi);
 
 #ifdef LWS_OPENSSL_SUPPORT
 	wsi->use_ssl = i->ssl_connection;
@@ -417,11 +422,6 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 		goto bail;
 	}
 #endif
-	wsi->protocol = &i->context->protocols[0];
-	if (wsi && !wsi->user_space && i->userdata) {
-		wsi->user_space_externally_allocated = 1;
-		wsi->user_space = i->userdata;
-	}
 
 	/* 2) stash the things from connect_info that we can't process without
 	 * an ah.  Because if no ah, we will go on the ah waiting list and
@@ -469,6 +469,14 @@ lws_client_connect_via_info(struct lws_client_connect_info *i)
 	if (lws_header_table_attach(wsi, 0))
 		lwsl_debug("%s: went on ah wait list\n", __func__);
 
+	if (i->parent_wsi) {
+		lwsl_info("%s: created child %p of parent %p\n", __func__,
+				wsi, i->parent_wsi);
+		wsi->parent = i->parent_wsi;
+		wsi->sibling_list = i->parent_wsi->child_list;
+		i->parent_wsi->child_list = wsi;
+	}
+
 	return wsi;
 
 bail:
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index 056921e96730750bea47b2fcafef795ea7cabea4..72cc2fd7cd8bb37c1dc8bed6cd6a02242e559f85 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -142,10 +142,11 @@ lws_set_timeout(struct lws *wsi, enum pending_timeout reason, int secs)
 void
 lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 {
-	struct lws_context *context;
 	struct lws_context_per_thread *pt;
-	int n, m, ret;
+	struct lws **pwsi, *wsi1, *wsi2;
+	struct lws_context *context;
 	struct lws_tokens eff_buf;
+	int n, m, ret;
 
 	if (!wsi)
 		return;
@@ -153,24 +154,31 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 	context = wsi->context;
 	pt = &context->pt[(int)wsi->tsi];
 
+	/* if we have children, close them first */
+	if (wsi->child_list) {
+		wsi2 = wsi->child_list;
+		while (wsi2) {
+			lwsl_notice("%s: closing %p: close child %p\n",
+					__func__, wsi, wsi2);
+			wsi1 = wsi2->sibling_list;
+			lws_close_free_wsi(wsi2, reason);
+			wsi2 = wsi1;
+		}
+	}
+
 #ifdef LWS_WITH_CGI
 	if (wsi->mode == LWSCM_CGI) {
 		/* we are not a network connection, but a handler for CGI io */
-		assert(wsi->master);
-		assert(wsi->master->cgi);
-		assert(wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] == wsi);
+		if (wsi->parent && wsi->parent->cgi)
 		/* end the binding between us and master */
-		wsi->master->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
-		wsi->master = NULL;
+		wsi->parent->cgi->stdwsi[(int)wsi->cgi_channel] = NULL;
 		wsi->socket_is_permanently_unusable = 1;
 
 		goto just_kill_connection;
 	}
 
 	if (wsi->cgi) {
-		/* we have a cgi going, we must kill it and close the
-		 * related stdin/out/err wsis first
-		 */
+		/* we have a cgi going, we must kill it */
 		wsi->cgi->being_closed = 1;
 		lws_cgi_kill(wsi);
 	}
@@ -327,6 +335,22 @@ lws_close_free_wsi(struct lws *wsi, enum lws_close_status reason)
 	}
 
 just_kill_connection:
+	if (wsi->parent) {
+		/* detach ourselves from parent's child list */
+		pwsi = &wsi->parent->child_list;
+		while (*pwsi) {
+			if (*pwsi == wsi) {
+				lwsl_notice("%s: detach %p from parent %p\n",
+						__func__, wsi, wsi->parent);
+				*pwsi = wsi->sibling_list;
+				break;
+			}
+			pwsi = &(*pwsi)->sibling_list;
+		}
+		if (*pwsi)
+			lwsl_err("%s: failed to detach from parent\n",
+					__func__);
+	}
 
 #if LWS_POSIX
 	/*
@@ -1182,6 +1206,18 @@ lws_wsi_user(struct lws *wsi)
 	return wsi->user_space;
 }
 
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_get_parent(const struct lws *wsi)
+{
+	return wsi->parent;
+}
+
+LWS_VISIBLE LWS_EXTERN struct lws *
+lws_get_child(const struct lws *wsi)
+{
+	return wsi->child_list;
+}
+
 LWS_VISIBLE LWS_EXTERN void
 lws_close_reason(struct lws *wsi, enum lws_close_status status,
 		 unsigned char *buf, size_t len)
@@ -1480,9 +1516,11 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
 	}
 
 	for (n = 0; n < 3; n++) {
-		cgi->stdwsi[n]->master = wsi;
 		if (insert_wsi_socket_into_fds(wsi->context, cgi->stdwsi[n]))
 			goto bail3;
+		cgi->stdwsi[n]->parent = wsi;
+		cgi->stdwsi[n]->sibling_list = wsi->child_list;
+		wsi->child_list = cgi->stdwsi[n];
 	}
 
 	lws_change_pollfd(cgi->stdwsi[LWS_STDIN], LWS_POLLIN, LWS_POLLOUT);
@@ -1496,6 +1534,8 @@ lws_cgi(struct lws *wsi, char * const *exec_array, int timeout_secs)
 
 	lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, timeout_secs);
 
+
+
 	/* add us to the pt list of active cgis */
 	cgi->cgi_list = pt->cgi_list;
 	pt->cgi_list = cgi;
@@ -1633,8 +1673,6 @@ lws_cgi_kill(struct lws *wsi)
 		if (wsi->cgi->pipe_fds[n][!!(n == 0)] >= 0) {
 			close(wsi->cgi->pipe_fds[n][!!(n == 0)]);
 			wsi->cgi->pipe_fds[n][!!(n == 0)] = -1;
-
-			lws_close_free_wsi(wsi->cgi->stdwsi[n], 0);
 		}
 	}
 
diff --git a/lib/libwebsockets.h b/lib/libwebsockets.h
index f38fc567a1f13e9eec6981028b82e9d7ea770dda..3126e847ed8993f4546065f911e854fb55ba1469 100644
--- a/lib/libwebsockets.h
+++ b/lib/libwebsockets.h
@@ -1410,6 +1410,9 @@ struct lws_context_creation_info {
  * @client_exts: array of extensions that may be used on connection
  * @method:	if non-NULL, do this http method instead of ws[s] upgrade.
  *		use "GET" to be a simple http client connection
+ * @parent_wsi:	if another wsi is responsible for this connection, give it here.
+ *		this is used to make sure if the parent closes so do any
+ *		child connections first.
  */
 
 struct lws_client_connect_info {
@@ -1425,6 +1428,7 @@ struct lws_client_connect_info {
 	void *userdata;
 	const struct lws_extension *client_exts;
 	const char *method;
+	struct lws *parent_wsi;
 
 	/* Add new things just above here ---^
 	 * This is part of the ABI, don't needlessly break compatibility
@@ -1847,6 +1851,12 @@ lws_get_context(const struct lws *wsi);
 LWS_VISIBLE LWS_EXTERN int LWS_WARN_UNUSED_RESULT
 lws_get_count_threads(struct lws_context *context);
 
+LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
+lws_get_parent(const struct lws *wsi);
+
+LWS_VISIBLE LWS_EXTERN struct lws * LWS_WARN_UNUSED_RESULT
+lws_get_child(const struct lws *wsi);
+
 #ifdef LWS_WITH_CGI
 enum lws_enum_stdinouterr {
 	LWS_STDIN = 0,
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index 4a9a92b480c50af74ddb0e2d68524d0c0504907b..c93f68885327110a528df61c1c6a951863e27226 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -1075,9 +1075,11 @@ struct lws {
 	/* pointers */
 
 	struct lws_context *context;
+	struct lws *parent; /* points to parent, if any */
+	struct lws *child_list; /* points to first child */
+	struct lws *sibling_list; /* subsequent children at same level */
 #ifdef LWS_WITH_CGI
 	struct lws_cgi *cgi; /* wsi being cgi master have one of these */
-	struct lws *master; /* for stdin/out/err wsi to point to cgi master */
 #endif
 	const struct lws_protocols *protocol;
 	struct lws *timeout_list;
diff --git a/lib/service.c b/lib/service.c
index d27e4e0942b2a5cb6251801f5c5f547bf6769d3d..bec262d92d2cd4a4df58d1d14eae92cdee630de2 100644
--- a/lib/service.c
+++ b/lib/service.c
@@ -871,12 +871,12 @@ handle_pending:
 				}
 
 			args.ch = wsi->cgi_channel;
-			args.stdwsi = &wsi->master->cgi->stdwsi[0];
+			args.stdwsi = &wsi->parent->cgi->stdwsi[0];
 
 			if (user_callback_handle_rxflow(
-					wsi->master->protocol->callback,
-					wsi->master, LWS_CALLBACK_CGI,
-					wsi->master->user_space,
+					wsi->parent->protocol->callback,
+					wsi->parent, LWS_CALLBACK_CGI,
+					wsi->parent->user_space,
 					(void *)&args, 0))
 				return 1;
 
diff --git a/test-server/lws-cgi-test.sh b/test-server/lws-cgi-test.sh
index 90c804e5b9b96788e900bc9209f483c8206351aa..2f5df11781c14c2b9bc263c8c672cd6dd2e95cd1 100755
--- a/test-server/lws-cgi-test.sh
+++ b/test-server/lws-cgi-test.sh
@@ -8,6 +8,8 @@ echo "REQUEST_METHOD=$REQUEST_METHOD"
 if [ "$REQUEST_METHOD" = "POST" ] ; then
 	read line
 	echo "read=\"$line\""
+else
+	cat /proc/meminfo
 fi
 
 echo "done"