ss: multipart without processing
Change the default to not process multipart mime at SS layer.
If it's desired, then set "http_multipart_ss_in" true in the policy on the streamtype.
To test, use lws-minimal-secure-streams-avs, which uses SS processing as it is.
To check it without the processing, change #if 1 to #if 0 around the policy for
"http_multipart_ss_in" in both places in avs.c, and also enable the hexdump in ss_avs_metadata_rx()
also in avs.c, and observe the multipart framing is passed through unchanged.
diff --git a/include/libwebsockets/lws-secure-streams-policy.h b/include/libwebsockets/lws-secure-streams-policy.h
index 41d2a96..0337d72 100644
--- a/include/libwebsockets/lws-secure-streams-policy.h
+++ b/include/libwebsockets/lws-secure-streams-policy.h
@@ -126,6 +126,8 @@
/**< we listen on a socket as a server */
LWSSSPOLF_ALLOW_REDIRECTS = (1 << 16),
/**< follow redirects */
+ LWSSSPOLF_HTTP_MULTIPART_IN = (1 << 17),
+ /**< handle inbound multipart mime at SS level */
};
typedef struct lws_ss_trust_store {
diff --git a/lib/secure-streams/README.md b/lib/secure-streams/README.md
index 5d064e7..d4050b8 100644
--- a/lib/secure-streams/README.md
+++ b/lib/secure-streams/README.md
@@ -403,6 +403,10 @@
Set this to `true` if the peer server has the quirk it sends an maximum initial tx credit
of 0x7fffffff and then later increments it illegally.
+### `http_multipart_ss_in`
+
+Indicates that SS should parse any incoming multipart mime on this stream
+
### `http_multipart_name`
Indicates this stream goes out using multipart mime, and provides the name part of the
diff --git a/lib/secure-streams/policy-json.c b/lib/secure-streams/policy-json.c
index 1a6bc29..718e6c4 100644
--- a/lib/secure-streams/policy-json.c
+++ b/lib/secure-streams/policy-json.c
@@ -80,6 +80,7 @@
"s[].*.http_www_form_urlencoded",
"s[].*.http_expect",
"s[].*.http_fail_redirect",
+ "s[].*.http_multipart_ss_in",
"s[].*.ws_subprotocol",
"s[].*.ws_binary",
"s[].*.local_sink",
@@ -151,6 +152,7 @@
LSSPPT_HTTP_WWW_FORM_URLENCODED,
LSSPPT_HTTP_EXPECT,
LSSPPT_HTTP_FAIL_REDIRECT,
+ LSSPPT_HTTP_MULTIPART_SS_IN,
LSSPPT_WS_SUBPROTOCOL,
LSSPPT_WS_BINARY,
LSSPPT_LOCAL_SINK,
@@ -584,6 +586,11 @@
a->curr[LTY_POLICY].p->flags |=
LWSSSPOLF_ALLOW_REDIRECTS;
break;
+ case LSSPPT_HTTP_MULTIPART_SS_IN:
+ if (reason == LEJPCB_VAL_TRUE)
+ a->curr[LTY_POLICY].p->flags |=
+ LWSSSPOLF_HTTP_MULTIPART_IN;
+ return 0;
case LSSPPT_RETRYPTR:
bot = a->heads[LTY_BACKOFF].b;
diff --git a/lib/secure-streams/protocols/ss-h1.c b/lib/secure-streams/protocols/ss-h1.c
index 3fef534..9f6e1d9 100644
--- a/lib/secure-streams/protocols/ss-h1.c
+++ b/lib/secure-streams/protocols/ss-h1.c
@@ -318,7 +318,11 @@
#if defined(LWS_WITH_SS_RIDESHARE)
/*
- * We should only especially process multipart ourselves if
+ * There are two ways we might want to deal with multipart,
+ * one is pass it through raw (although the user code needs
+ * a helping hand for learning the boundary), and the other
+ * is to deframe it and provide basically submessages in the
+ * different parts.
*/
if (lws_hdr_copy(wsi, (char *)buf, sizeof(buf),
@@ -367,7 +371,8 @@
/* inform the ss that a related message group begins */
- if (h->u.http.boundary[0])
+ if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
+ h->u.http.boundary[0])
h->info.rx(ss_to_userobj(h), NULL, 0,
LWSSS_FLAG_RELATED_START);
@@ -460,7 +465,8 @@
return 0;
#if defined(LWS_WITH_SS_RIDESHARE)
- if (h->u.http.boundary[0])
+ if ((h->policy->flags & LWSSSPOLF_HTTP_MULTIPART_IN) &&
+ h->u.http.boundary[0])
return ss_http_multipart_parser(h, in, len);
#endif
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c b/minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c
index d498b42..02f7ba0 100644
--- a/minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c
+++ b/minimal-examples/secure-streams/minimal-secure-streams-alexa/main.c
@@ -203,6 +203,7 @@
"\"h2q_oflow_txcr\":" "true,"
"\"http_auth_header\":" "\"authorization:\","
"\"http_auth_preamble\":" "\"Bearer \","
+ "\"http_multipart_ss_in\":" "true,"
"\"nailed_up\":" "true,"
"\"long_poll\":" "true,"
"\"retry\":" "\"default\","
@@ -229,6 +230,7 @@
"\"http_multipart_name\":" "\"metadata\","
"\"http_mime_content_type\":" "\"application/json; charset=UTF-8\","
"\"http_no_content_length\":" "true,"
+ "\"http_multipart_ss_in\":" "true,"
"\"rideshare\":" "\"avs_audio\","
"\"retry\":" "\"default\","
"\"plugins\":" "[],"
@@ -246,6 +248,7 @@
"\"h2q_oflow_txcr\":" "true,"
"\"http_auth_header\":" "\"authorization:\","
"\"http_auth_preamble\":" "\"Bearer \","
+ "\"http_multipart_ss_in\":" "true,"
"\"http_multipart_name\":" "\"audio\","
"\"http_mime_content_type\":" "\"application/octet-stream\","
"\"http_no_content_length\":" "true,"
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c b/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c
index 0121d67..49e6ca1 100644
--- a/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c
+++ b/minimal-examples/secure-streams/minimal-secure-streams-avs/avs.c
@@ -120,7 +120,9 @@
lwsl_notice("%s: rideshare %s, len %d, flags 0x%x\n", __func__,
lws_ss_rideshare(m->ss), (int)len, flags);
- // lwsl_hexdump_warn(buf, len);
+#if 0
+ lwsl_hexdump_warn(buf, len);
+#endif
n = sizeof(m->buf) - ((m->head - m->tail) % sizeof(m->buf));
lwsl_info("%s: len %d, buf h %d, t %d, space %d\n", __func__,
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-avs/main.c b/minimal-examples/secure-streams/minimal-secure-streams-avs/main.c
index fc15432..9bae7d5 100644
--- a/minimal-examples/secure-streams/minimal-secure-streams-avs/main.c
+++ b/minimal-examples/secure-streams/minimal-secure-streams-avs/main.c
@@ -195,6 +195,9 @@
"\"http_auth_preamble\":" "\"Bearer \","
"\"http_multipart_name\":" "\"metadata\","
"\"http_mime_content_type\":" "\"application/json; charset=UTF-8\","
+#if 1
+ "\"http_multipart_ss_in\":" "true,"
+#endif
"\"rideshare\":" "\"avs_audio\","
"\"retry\":" "\"default\","
"\"plugins\":" "[],"
@@ -211,6 +214,9 @@
"\"plugins\":" "[],"
"\"tls\":" "true,"
"\"h2q_oflow_txcr\":" "true,"
+#if 1
+ "\"http_multipart_ss_in\":" "true,"
+#endif
"\"http_auth_header\":" "\"authorization:\","
"\"http_auth_preamble\":" "\"Bearer \","
"\"http_multipart_name\":" "\"audio\","
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/main.c b/minimal-examples/secure-streams/minimal-secure-streams-server/main.c
index 78363e7..1c244c2 100644
--- a/minimal-examples/secure-streams/minimal-secure-streams-server/main.c
+++ b/minimal-examples/secure-streams/minimal-secure-streams-server/main.c
@@ -14,7 +14,7 @@
extern const lws_ss_info_t ssi_client, ssi_server;
static struct lws_context *context;
-int interrupted, bad = 1;
+int interrupted, bad = 1, multipart;
static const char * const default_ss_policy =
"{"
"\"release\":" "\"01234567\","
@@ -302,6 +302,10 @@
memset(&info, 0, sizeof info); /* otherwise uninitialized garbage */
lws_cmdline_option_handle_builtin(argc, argv, &info);
+
+ if (lws_cmdline_option(argc, argv, "-m"))
+ multipart = 1;
+
lwsl_user("LWS Secure Streams Server\n");
info.options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS |
diff --git a/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c b/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c
index 716f3e1..5c2c2c1 100644
--- a/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c
+++ b/minimal-examples/secure-streams/minimal-secure-streams-server/ss-server.c
@@ -10,9 +10,10 @@
#include <libwebsockets.h>
#include <assert.h>
-extern int interrupted, bad;
+extern int interrupted, bad, multipart;
static const char *html =
+ /* normally we serve this... */
"<head><meta content=\"text/html;charset=utf-8\" "
"http-equiv=\"Content-Type\"><script>"
" var ws = new WebSocket(\"wss://localhost:7681\", \"mywsprotocol\");"
@@ -25,7 +26,23 @@
"</script></head><html><body>"
"Hello from the web server<br>"
"<div id=\"wsd\"></div>"
- "</body></html>";
+ "</body></html>",
+
+*multipart_html =
+ /*
+ * If you use -m commandline switch we send this instead, as
+ * multipart/form-data
+ */
+ "--aBoundaryString\r\n"
+ "Content-Disposition: form-data; name=\"myFile\"; filename=\"xxx.txt\"\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "The file contents\r\n"
+ "--aBoundaryString\r\n"
+ "Content-Disposition: form-data; name=\"myField\"\r\n"
+ "\r\n"
+ "(data)\r\n"
+ "--aBoundaryString--\r\n";
typedef struct myss {
@@ -68,14 +85,18 @@
int *flags)
{
myss_srv_t *m = (myss_srv_t *)userobj;
+ const char *send = html;
if (m->upgraded)
return LWSSSSRET_TX_DONT_SEND;
+ if (multipart)
+ send = multipart_html;
+
*flags = LWSSS_FLAG_SOM | LWSSS_FLAG_EOM;
- lws_strncpy((char *)buf, html, *len);
- *len = strlen(html);
+ lws_strncpy((char *)buf, send, *len);
+ *len = strlen(send);
return 0;
}
@@ -168,13 +189,18 @@
*/
lws_ss_server_ack(m->ss, 0);
/*
- * ... it's going to be text/html...
+ * ... it's going to be either text/html or multipart ...
*/
- lws_ss_set_metadata(m->ss, "mime", "text/html", 9);
+ if (multipart)
+ lws_ss_set_metadata(m->ss, "mime",
+ "multipart/form-data; boundary=aBoundaryString", 45);
+ else
+ lws_ss_set_metadata(m->ss, "mime", "text/html", 9);
/*
- * ...it's going to be 128 byte (and request tx)
+ * ...it's going to be whatever size it is (and request tx)
*/
- lws_ss_request_tx_len(m->ss, strlen(html));
+ lws_ss_request_tx_len(m->ss, multipart ? strlen(multipart_html) :
+ strlen(html));
break;
case LWSSSCS_SERVER_UPGRADE: