/*
 * SS http-post example
 *
 * Written in 2010-2021 by Andy Green <andy@warmcat.com>
 *
 * This file is made available under the Creative Commons CC0 1.0
 * Universal Public Domain Dedication.
 *
 * Demonstrates http post using the LWS high-level SS apis.
 *
 *  - main.c:              boilerplate to create the lws_context and event loop
 *  - http-post-ss.c:      (this file) the secure stream user code
 *  - example-policy.json: the example policy
 */

#include <libwebsockets.h>
#include <signal.h>

extern int test_result;

static const char * const postbody =
	"--boundary\r\n"
	"Content-Disposition: form-data; name=\"text\"\r\n"
	"\r\n"
	"value1\r\n"
	"--boundary\r\n"
	"Content-Disposition: form-data; "
		"name=\"field2\"; filename=\"example.txt\"\r\n"
	"\r\n"
	"value2\r\n"
	"00-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"01-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"02-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"03-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"04-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"05-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"06-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"07-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"08-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"09-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"0a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"0b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"0c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"0d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"0e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"0f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"10-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"11-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"12-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"13-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"14-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"15-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"16-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"17-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"18-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"19-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"1a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"1b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"1c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"1d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"1e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"1f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"20-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"21-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"22-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"23-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"24-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"25-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"26-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"27-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"28-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"29-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"2a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"2b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"2c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"2d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"2e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"2f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"30-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"31-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"32-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"33-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"34-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"35-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"36-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"37-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"38-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"39-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"3a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"3b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"3c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"3d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"3e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"3f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"40-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"41-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"42-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"43-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"44-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"45-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"46-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"47-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"48-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"49-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"4a-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"4b-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"4c-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"4d-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"4e-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"4f-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"50-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"51-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"52-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"53-0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef\r\n"
	"--boundary--\r\n";

LWS_SS_USER_TYPEDEF
	const char		*payload;
	size_t			size;
	size_t			pos;
} http_post_t;

static lws_ss_state_return_t
http_post_tx(void *userobj, lws_ss_tx_ordinal_t ord, uint8_t *buf, size_t *len,
	     int *flags)
{
	http_post_t *g = (http_post_t *)userobj;
	lws_ss_state_return_t r = LWSSSSRET_OK;

	if (g->size == g->pos)
		return LWSSSSRET_TX_DONT_SEND;

	if (*len > g->size - g->pos)
		*len = g->size - g->pos;

	if (!g->pos)
		*flags |= LWSSS_FLAG_SOM;

	memcpy(buf, g->payload + g->pos, *len);
	g->pos += *len;

	if (g->pos != g->size)
		/* more to do */
		r = lws_ss_request_tx(lws_ss_from_user(g));
	else
		*flags |= LWSSS_FLAG_EOM;

	lwsl_ss_user(lws_ss_from_user(g), "TX %zu, flags 0x%x, r %d", *len,
					  (unsigned int)*flags, (int)r);

	return r;
}

static lws_ss_state_return_t
http_post_rx(void *userobj, const uint8_t *in, size_t len, int flags)
{
	http_post_t *g = (http_post_t *)userobj;

	lwsl_ss_user(lws_ss_from_user(g), "RX %zu, flags 0x%x", len,
					  (unsigned int)flags);

	lwsl_hexdump_notice(in, len);

	if ((flags & LWSSS_FLAG_EOM) == LWSSS_FLAG_EOM)
		/* We received the whole response */
		test_result &= ~2;

	return LWSSSSRET_OK;
}

static lws_ss_state_return_t
http_post_state(void *userobj, void *h_src, lws_ss_constate_t state,
		lws_ss_tx_ordinal_t ack)
{
	http_post_t *g = (http_post_t *)userobj;

	switch ((int)state) {
	case LWSSSCS_CREATING:
		if (lws_ss_set_metadata(lws_ss_from_user(g), "ctype",
				    "multipart/form-data;boundary=\"boundary\"",
				    39))
			return LWSSSSRET_DISCONNECT_ME;

		/* provide a hint about the payload size */
		g->pos = 0;
		g->payload = postbody;
		g->size = strlen(g->payload);

		lwsl_ss_user(lws_ss_from_user(g), "Preparing to send %zu",
						  g->size);

		return lws_ss_request_tx_len(lws_ss_from_user(g),
						(unsigned long)g->size);

	case LWSSSCS_CONNECTED:
		return lws_ss_request_tx(lws_ss_from_user(g));

	case LWSSSCS_QOS_ACK_REMOTE: /* server liked our request */
		test_result &= ~1;
		break;

	case LWSSSCS_DISCONNECTED: /* for our example, disconnect = done */
		lws_default_loop_exit(lws_ss_cx_from_user(g));
		break;
	}

	return LWSSSSRET_OK;
}

LWS_SS_INFO("minpost", http_post_t)
	.tx		= http_post_tx,
	.rx		= http_post_rx,
	.state		= http_post_state,
};