diff --git a/changelog b/changelog
index 6d883e582b53d93296f86cdf1e8530dd49e51550..9a34696c5f7c40711a4ffea84b327f4da14e080e 100644
--- a/changelog
+++ b/changelog
@@ -162,6 +162,10 @@ LWS_SERVER_OPTION_SSL_ECD
 
 to build in support and select it at runtime.
 
+6) There's a new api lws_parse_uri() that simplies chopping up
+https://xxx:yyy/zzz uris into parts nicely.  The test client now uses this
+to allow proper uris.
+
 
 User api changes
 ----------------
diff --git a/lib/client-handshake.c b/lib/client-handshake.c
index d6f637bcb26bfb16d35f4294af946b6a481f9500..259dcbaed95ea8dba95d14528616945d158d621c 100644
--- a/lib/client-handshake.c
+++ b/lib/client-handshake.c
@@ -313,6 +313,56 @@ failed:
 
 	return NULL;
 }
+
+/**
+ * lws_client_reset() - retarget a connected wsi to start over with a new connection (ie, redirect)
+ *			this only works if still in HTTP, ie, not upgraded yet
+ * wsi:		connection to reset
+ * address:	network address of the new server
+ * port:	port to connect to
+ * path:	uri path to connect to on the new server
+ * host:	host header to send to the new server
+ */
+LWS_VISIBLE struct lws *
+lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host)
+{
+	if (wsi->u.hdr.redirects == 3) {
+		lwsl_err("%s: Too many redirects\n", __func__);
+		return NULL;
+	}
+	wsi->u.hdr.redirects++;
+
+#ifdef LWS_OPENSSL_SUPPORT
+	wsi->use_ssl = ssl;
+#else
+	if (ssl) {
+		lwsl_err("%s: not configured for ssl\n", __func__);
+		return NULL;
+	}
+#endif
+
+	lwsl_notice("redirect ads='%s', port=%d, path='%s'\n", address, port, path);
+
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_PEER_ADDRESS, address))
+		return NULL;
+
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_URI, path))
+		return NULL;
+
+	if (lws_hdr_simple_create(wsi, _WSI_TOKEN_CLIENT_HOST, host))
+		return NULL;
+
+	close(wsi->sock);
+	remove_wsi_socket_from_fds(wsi);
+	wsi->sock = LWS_SOCK_INVALID;
+	wsi->state = LWSS_CLIENT_UNCONNECTED;
+	wsi->protocol = NULL;
+	wsi->pending_timeout = NO_PENDING_TIMEOUT;
+	wsi->u.hdr.ah->c_port = port;
+
+	return lws_client_connect_2(wsi);
+}
+
 /**
  * lws_client_connect_via_info() - Connect to another websocket server
  * @i:pointer to lws_client_connect_info struct
diff --git a/lib/client.c b/lib/client.c
index a8f36738c4e70223545a2a258c443e61c7a4fc5b..bd84015c2f227fe95cf92e8b5a129a6eeb9ecefa 100644
--- a/lib/client.c
+++ b/lib/client.c
@@ -509,8 +509,8 @@ lws_client_interpret_server_handshake(struct lws *wsi)
 {
 	struct lws_context *context = wsi->context;
 	int close_reason = LWS_CLOSE_STATUS_PROTOCOL_ERR;
-	int n, len, okay = 0, isErrorCodeReceived = 0;
-	const char *pc;
+	int n, len, okay = 0, isErrorCodeReceived = 0, port = 0, ssl = 0;
+	const char *pc, *prot, *ads = NULL, *path;
 	char *p;
 #ifndef LWS_NO_EXTENSIONS
 	const struct lws_extension *ext;
@@ -532,7 +532,24 @@ lws_client_interpret_server_handshake(struct lws *wsi)
 		lwsl_info("no URI\n");
 		goto bail3;
 	}
+	n = atoi(p);
+	if (n == 301 || n == 302 || n == 303 || n == 307 || n == 308) {
+		p = lws_hdr_simple_ptr(wsi, WSI_TOKEN_HTTP_LOCATION);
+		if (!p)
+			goto bail3;
+
+		if (lws_parse_uri(p, &prot, &ads, &port, &path))
+			goto bail3;
+
+		if (!strcmp(prot, "wss://") || !strcmp(prot, "https://"))
+			ssl = 1;
 
+		if (lws_client_reset(wsi, ssl, ads, port, path, ads)) {
+			lwsl_err("Redirect failed\n");
+			goto bail3;
+		}
+		return 0;
+	}
 	if (lws_hdr_total_length(wsi, WSI_TOKEN_ACCEPT) == 0) {
 		lwsl_info("no ACCEPT\n");
 		isErrorCodeReceived = 1;
diff --git a/lib/libwebsockets.c b/lib/libwebsockets.c
index bd2bc0da365f2d1faffb4dffb0cae65555712338..d1d958076e6cbb45d85ec81d34b62706a9cda2a4 100644
--- a/lib/libwebsockets.c
+++ b/lib/libwebsockets.c
@@ -1096,6 +1096,17 @@ lws_check_utf8(unsigned char *state, unsigned char *buf, size_t len)
 	return 0;
 }
 
+/**
+ * lws_parse_uri:	cut up https:/xxx:yyy/zzz into pieces
+ *			Notice it does so by dropping '\0' into input string
+ *
+ * @p:			incoming uri string.. will get written to
+ * @prot:		result pointer for protocol part (https://)
+ * @ads:		result pointer for address part
+ * @port:		result pointer for port part
+ * @path:		result pointer for path part
+ */
+
 LWS_VISIBLE LWS_EXTERN int
 lws_parse_uri(char *p, const char **prot, const char **ads, int *port, const char **path)
 {
diff --git a/lib/private-libwebsockets.h b/lib/private-libwebsockets.h
index d7f069cd4cfe105057716507b17ba561ba7a2fa8..77e37c13f972ab3bc23943c8fde1a32c7c1b19b2 100644
--- a/lib/private-libwebsockets.h
+++ b/lib/private-libwebsockets.h
@@ -836,6 +836,7 @@ struct _lws_header_related {
 	char esc_stash;
 	char post_literal_equal;
 	unsigned char parser_state; /* enum lws_token_indexes */
+	char redirects;
 };
 
 struct _lws_websocket_related {
@@ -1034,6 +1035,10 @@ lws_service_timeout_check(struct lws *wsi, unsigned int sec);
 LWS_EXTERN struct lws *
 lws_client_connect_2(struct lws *wsi);
 
+LWS_VISIBLE struct lws *
+lws_client_reset(struct lws *wsi, int ssl, const char *address, int port, const char *path, const char *host);
+
+
 LWS_EXTERN struct lws *
 lws_create_new_server_wsi(struct lws_context *context);
 
diff --git a/test-server/test-client.c b/test-server/test-client.c
index 475b8b14a2cfd4cbee9f8526279a09fd1c6f8ffc..1458d22d1b36beac4a43dc4209a51617b515e541 100644
--- a/test-server/test-client.c
+++ b/test-server/test-client.c
@@ -274,7 +274,7 @@ int main(int argc, char **argv)
 	struct lws_context_creation_info info;
 	struct lws_client_connect_info i;
 	struct lws_context *context;
-	const char *address;
+	const char *prot;
 
 	memset(&info, 0, sizeof info);
 
@@ -321,7 +321,16 @@ int main(int argc, char **argv)
 
 	signal(SIGINT, sighandler);
 
-	address = argv[optind];
+	memset(&i, 0, sizeof(i));
+
+	i.port = port;
+	if (lws_parse_uri(argv[optind], &prot, &i.address, &i.port, &i.path))
+		goto usage;
+
+	if (!strcmp(prot, "http://") || !strcmp(prot, "ws://"))
+		use_ssl = 0;
+	if (!strcmp(prot, "https://") || !strcmp(prot, "wss://"))
+		use_ssl = 1;
 
 	/*
 	 * create the websockets context.  This tracks open connections and
@@ -342,15 +351,10 @@ int main(int argc, char **argv)
 		return 1;
 	}
 
-	memset(&i, 0, sizeof(i));
-
 	i.context = context;
-	i.address = address;
-	i.port = port;
 	i.ssl_connection = use_ssl;
-	i.path = "/";
-	i.host = argv[optind];
-	i.origin = argv[optind];
+	i.host = i.address;
+	i.origin = i.address;
 	i.ietf_version_or_minus_one = ietf_version;
 	i.client_exts = exts;
 	/*