diff mbox series

[V3,2/2] mongoose: set V1 or V2 at runtime

Message ID 1520420366-6564-2-git-send-email-sbabic@denx.de
State Changes Requested
Headers show
Series [V3,1/2] mongoose: split upload_handler | expand

Commit Message

Stefano Babic March 7, 2018, 10:59 a.m. UTC
V1 version of REST-API is still more suitable for M2M
updates together with the SWU forwarder handler.
However, it is not currently possible to switch
between them and the API must be selected at compile time,
and this requires different binaries.

Let the user decides which version of API should run
with a command line parameter.

Signed-off-by: Stefano Babic <sbabic@denx.de>
CC: Sami Hartikainen <sami.hartikainen@teleste.com>
---

Changes since V2:
	- use enum for API
	- drop V1 website support and let just the two URLs:
		handle_post_request
		getstatus.json
	this to guarantee the compatibility with SWU forwarder and
	proprietary applications using (or abusing of..) the REST-API
	For the Webserver itself, just V2 should be used.
Changes since V1:
	- Drop MONGOOSE_WEB_API_V1 and MONGOOSE_WEB_API_V2
	- Add help for "api"
	- Add "api" parameter to configuration file
	- "/upload" URL just in case of v2
	- print API version when Webserver is started

 mongoose/Config.in            |  18 --
 mongoose/Makefile             |   2 -
 mongoose/mongoose_interface.c | 414 ++++++++++++++++++++----------------------
 3 files changed, 193 insertions(+), 241 deletions(-)

Comments

Stefan Herbrechtsmeier March 7, 2018, 7:33 p.m. UTC | #1
Hi Stefano,

Am 07.03.2018 um 11:59 schrieb Stefano Babic:
> V1 version of REST-API is still more suitable for M2M
> updates together with the SWU forwarder handler.
> However, it is not currently possible to switch
> between them and the API must be selected at compile time,
> and this requires different binaries.
>
> Let the user decides which version of API should run
> with a command line parameter.
>
> Signed-off-by: Stefano Babic <sbabic@denx.de>
> CC: Sami Hartikainen <sami.hartikainen@teleste.com>
> ---
>
> Changes since V2:
> 	- use enum for API
> 	- drop V1 website support and let just the two URLs:
> 		handle_post_request
> 		getstatus.json
> 	this to guarantee the compatibility with SWU forwarder and
> 	proprietary applications using (or abusing of..) the REST-API
> 	For the Webserver itself, just V2 should be used.
> Changes since V1:
> 	- Drop MONGOOSE_WEB_API_V1 and MONGOOSE_WEB_API_V2
> 	- Add help for "api"
> 	- Add "api" parameter to configuration file
> 	- "/upload" URL just in case of v2
> 	- print API version when Webserver is started
>
>   mongoose/Config.in            |  18 --
>   mongoose/Makefile             |   2 -
>   mongoose/mongoose_interface.c | 414 ++++++++++++++++++++----------------------
>   3 files changed, 193 insertions(+), 241 deletions(-)
>
> diff --git a/mongoose/Config.in b/mongoose/Config.in
> index a001247..29cac90 100644
> --- a/mongoose/Config.in
> +++ b/mongoose/Config.in
> @@ -18,24 +18,6 @@ config MONGOOSE
>   
>   endchoice
>   
> -choice
> -	prompt "Web Application Interface"
> -	default MONGOOSE_WEB_API_V1
> -	help
> -	  Choose the bootloader
> -
> -config MONGOOSE_WEB_API_V1
> -	bool "Version 1 (deprecated)"
> -	help
> -	  Support for version 1
> -
> -config MONGOOSE_WEB_API_V2
> -	bool "Version 2"
> -	help
> -	  Support for version 2
> -
> -endchoice
> -
>   config MONGOOSEIPV6
>   	bool "IPv6 support"
>   	default y
> diff --git a/mongoose/Makefile b/mongoose/Makefile
> index 77a616c..dc2d3d3 100644
> --- a/mongoose/Makefile
> +++ b/mongoose/Makefile
> @@ -1,9 +1,7 @@
>   ifneq ($(CONFIG_WEBSERVER),)
>   ifneq ($(CONFIG_MONGOOSE),)
>   KBUILD_CFLAGS += -DMG_ENABLE_HTTP_STREAMING_MULTIPART=1
> -ifneq ($(CONFIG_MONGOOSE_WEB_API_V2),)
>   KBUILD_CFLAGS += -DMG_ENABLE_HTTP_WEBSOCKET=1 -DMG_ENABLE_THREADS=1
> -endif
>   ifneq ($(CONFIG_MONGOOSEIPV6),)
>   KBUILD_CFLAGS += -DMG_ENABLE_IPV6=1
>   endif
> diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c
> index 0e22671..9ef9070 100644
> --- a/mongoose/mongoose_interface.c
> +++ b/mongoose/mongoose_interface.c
> @@ -32,6 +32,11 @@
>   #define MG_PORT "8080"
>   #define MG_ROOT "."
>   
> +enum MONGOOSE_API_VERSION {
> +	MONGOOSE_API_V1,
> +	MONGOOSE_API_V2
> +};
> +
>   struct mongoose_options {
>   	char *root;
>   	char *listing;
> @@ -40,6 +45,7 @@ struct mongoose_options {
>   	char *ssl_cert;
>   	char *ssl_key;
>   #endif
> +	enum MONGOOSE_API_VERSION api_version;
>   };
>   
>   struct file_upload_state {
> @@ -50,7 +56,9 @@ struct file_upload_state {
>   static struct mg_serve_http_opts s_http_server_opts;
>   static void upload_handler(struct mg_connection *nc, int ev, void *p);
>   
> -#if defined(CONFIG_MONGOOSE_WEB_API_V2)
> +/*
> + * These functions are for V2 of the protocol
> + */
>   #define enum_string(x)	[x] = #x
>   static const char *get_status_string(unsigned int status)
>   {
> @@ -111,210 +119,7 @@ static size_t snescape(char *dst, size_t n, const char *src)
>   
>   	return len;
>   }
> -#endif
> -
> -#if defined(CONFIG_MONGOOSE_WEB_API_V1)
> -static void upload_handler_v1(struct mg_connection *nc, int ev, void *p)
> -{
> -	struct mg_str *filename, *data;
> -	struct http_message *hm;
> -	size_t length;
> -	char buf[16];
> -	int fd;
> -
> -	switch (ev) {
> -	case MG_EV_HTTP_REQUEST:
> -		hm = (struct http_message *) p;
> -
> -		filename = mg_get_http_header(hm, "X_FILENAME");
> -		if (filename == NULL) {
> -			mg_http_send_error(nc, 403, NULL);
> -			return;
> -		}
> -
> -		data = mg_get_http_header(hm, "Content-length");
> -		if (data == NULL || data->len >= ARRAY_SIZE(buf)) {
> -			mg_http_send_error(nc, 403, NULL);
> -			return;
> -		}
> -
> -		memcpy(buf, data->p, data->len);
> -		buf[data->len] = '\0';
> -		length = strtoul(data->p, NULL, 10);
> -		if (length == 0) {
> -			mg_http_send_error(nc, 403, NULL);
> -			return;
> -		}
> -
> -		fd = ipc_inst_start_ext(SOURCE_WEBSERVER, filename->len, filename->p);
> -		ipc_send_data(fd, (char *) hm->body.p, hm->body.len);
> -		ipc_end(fd);
> -
> -		mg_send_response_line(nc, 200,
> -			"Content-Type: text/plain\r\n"
> -			"Connection: close");
> -		mg_send(nc, "\r\n", 2);
> -		mg_printf(nc, "Ok, %.*s - %d bytes.\r\n", (int) filename->len, filename->p, (int) length);
> -		nc->flags |= MG_F_SEND_AND_CLOSE;
> -		break;
> -	default:
> -		upload_handler(nc, ev, p);
> -		break;
> -	}
> -}
> -#endif
> -
> -static void upload_handler(struct mg_connection *nc, int ev, void *p)
> -{
> -	struct mg_http_multipart_part *mp;
> -	struct file_upload_state *fus;
> -
> -	switch (ev) {
> -	case MG_EV_HTTP_PART_BEGIN:
> -		mp = (struct mg_http_multipart_part *) p;
> -
> -		fus = (struct file_upload_state *) calloc(1, sizeof(*fus));
> -		if (fus == NULL) {
> -			mg_http_send_error(nc, 500, "Out of memory");
> -			break;
> -		}
> -
> -		fus->fd = ipc_inst_start_ext(SOURCE_WEBSERVER, strlen(mp->file_name), mp->file_name);
> -		if (fus->fd < 0) {
> -			mg_http_send_error(nc, 500, "Failed to queue command");
> -			free(fus);
> -			break;
> -		}
> -
> -		mp->user_data = fus;
> -
> -		break;
> -
> -	case MG_EV_HTTP_PART_DATA:
> -		mp = (struct mg_http_multipart_part *) p;
> -		fus = (struct file_upload_state *) mp->user_data;
> -
> -		if (!fus)
> -			break;
> -
> -		ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len);
> -		fus->len += mp->data.len;
> -
> -		break;
> -
> -	case MG_EV_HTTP_PART_END:
> -		mp = (struct mg_http_multipart_part *) p;
> -		fus = (struct file_upload_state *) mp->user_data;
> -
> -		if (!fus)
> -			break;
> -
> -		ipc_end(fus->fd);
> -
> -		mg_send_response_line(nc, 200,
> -			"Content-Type: text/plain\r\n"
> -			"Connection: close");
> -		mg_send(nc, "\r\n", 2);
> -		mg_printf(nc, "Ok, %s - %d bytes.\r\n", mp->file_name, (int) fus->len);
> -		nc->flags |= MG_F_SEND_AND_CLOSE;
> -
> -		mp->user_data = NULL;
> -		free(fus);
> -		break;
> -	}
> -}
>   
> -#if defined(CONFIG_MONGOOSE_WEB_API_V1)
> -static void recovery_status(struct mg_connection *nc, int ev, void *ev_data)
> -{
> -	ipc_message ipc;
> -	int ret;
> -	char buf[4096];
> -
> -	(void)ev;
> -	(void)ev_data;
> -
> -	ret = ipc_get_status(&ipc);
> -
> -	if (ret) {
> -		mg_http_send_error(nc, 500, NULL);
> -		return;
> -	}
> -
> -	snprintf(buf, sizeof(buf),
> -		"{\r\n"
> -		"\t\"Status\" : \"%d\",\r\n"
> -		"\t\"Msg\" : \"%s\",\r\n"
> -		"\t\"Error\" : \"%d\",\r\n"
> -		"\t\"LastResult\" : \"%d\"\r\n"
> -		"}\r\n",
> -		ipc.data.status.current,
> -		strlen(ipc.data.status.desc) ? ipc.data.status.desc : "",
> -		ipc.data.status.error,
> -		ipc.data.status.last_result);
> -
> -	mg_send_head(nc, 200, strlen(buf),
> -		"Cache: no-cache\r\n"
> -		"Content-Type: text/plain");
> -
> -	mg_send(nc, buf, strlen(buf));
> -
> -	nc->flags |= MG_F_SEND_AND_CLOSE;
> -}
> -
> -static void reboot_target(struct mg_connection *nc, int ev, void *ev_data)
> -{
> -	struct http_message *hm = (struct http_message *) ev_data;
> -	int ret;
> -
> -	(void)ev;
> -
> -	if(mg_vcasecmp(&hm->method, "POST") == 0) {
> -		ret = system("reboot");
> -		if (ret) {
> -			mg_http_send_error(nc, 500,
> -				"Device cannot be reboot, internal fault.");
> -			return;
> -		}
> -
> -		mg_http_send_error(nc, 200, "Device will reboot now.");
> -	}
> -	else {
> -		mg_send_response_line(nc, 200,
> -			"Content-Type: text/html\r\n"
> -			"Connection: close");
> -		mg_send(nc, "\r\n", 2);
> -		mg_printf(nc,
> -			"<form method='POST' action=''>"
> -			"<input type='submit' value='Reboot'>"
> -			"</form>");
> -		nc->flags |= MG_F_SEND_AND_CLOSE;
> -	}
> -}
> -
> -static void post_update_cmd(struct mg_connection *nc, int ev, void *ev_data)
> -{
> -	ipc_message msg = {};
> -
> -	(void)ev;
> -	(void)ev_data;
> -
> -	int ret = ipc_postupdate(&msg);
> -	mg_send_response_line(nc, 200, "Content-Type: application/json");
> -	mg_send(nc, "\r\n", 2);
> -	mg_printf(nc,
> -		"{\r\n"
> -		"\t\"code\": %d,\r\n"
> -		"\t\"error\": \"%s\",\r\n"
> -		"\t\"detail\": \"%s\"\r\n"
> -		"}",
> -		(ret == 0) ? 200 : 501,
> -		(ret == 0) ? "" : "Internal server error",
> -		(ret == 0) ? "" : "Failed to queue command");
> -
> -	nc->flags |= MG_F_SEND_AND_CLOSE;
> -}
> -#elif defined(CONFIG_MONGOOSE_WEB_API_V2)
>   static void restart_handler(struct mg_connection *nc, int ev, void *ev_data)
>   {
>   	struct http_message *hm = (struct http_message *) ev_data;
> @@ -470,7 +275,158 @@ static void *broadcast_progress_thread(void *data)
>   
>   	return NULL;
>   }
> -#endif
> +
> +/*
> + * These functions are for V1 of the protocol
> + */
> +static void upload_handler_v1(struct mg_connection *nc, int ev, void *p)
> +{
> +	struct mg_str *filename, *data;
> +	struct http_message *hm;
> +	size_t length;
> +	char buf[16];
> +	int fd;
> +
> +	switch (ev) {
> +	case MG_EV_HTTP_REQUEST:
> +		hm = (struct http_message *) p;
> +
> +		filename = mg_get_http_header(hm, "X_FILENAME");
> +		if (filename == NULL) {
> +			mg_http_send_error(nc, 403, NULL);
> +			return;
> +		}
> +
> +		data = mg_get_http_header(hm, "Content-length");
> +		if (data == NULL || data->len >= ARRAY_SIZE(buf)) {
> +			mg_http_send_error(nc, 403, NULL);
> +			return;
> +		}
> +
> +		memcpy(buf, data->p, data->len);
> +		buf[data->len] = '\0';
> +		length = strtoul(data->p, NULL, 10);
> +		if (length == 0) {
> +			mg_http_send_error(nc, 403, NULL);
> +			return;
> +		}
> +
> +		fd = ipc_inst_start_ext(SOURCE_WEBSERVER, filename->len, filename->p);
> +		ipc_send_data(fd, (char *) hm->body.p, hm->body.len);
> +		ipc_end(fd);
> +
> +		mg_send_response_line(nc, 200,
> +			"Content-Type: text/plain\r\n"
> +			"Connection: close");
> +		mg_send(nc, "\r\n", 2);
> +		mg_printf(nc, "Ok, %.*s - %d bytes.\r\n", (int) filename->len, filename->p, (int) length);
> +		nc->flags |= MG_F_SEND_AND_CLOSE;
> +		break;
> +	default:
> +		upload_handler(nc, ev, p);
> +		break;
> +	}
> +}
> +
> +static void recovery_status(struct mg_connection *nc, int ev, void *ev_data)
> +{
> +	ipc_message ipc;
> +	int ret;
> +	char buf[4096];
> +
> +	(void)ev;
> +	(void)ev_data;
> +
> +	ret = ipc_get_status(&ipc);
> +
> +	if (ret) {
> +		mg_http_send_error(nc, 500, NULL);
> +		return;
> +	}
> +
> +	snprintf(buf, sizeof(buf),
> +		"{\r\n"
> +		"\t\"Status\" : \"%d\",\r\n"
> +		"\t\"Msg\" : \"%s\",\r\n"
> +		"\t\"Error\" : \"%d\",\r\n"
> +		"\t\"LastResult\" : \"%d\"\r\n"
> +		"}\r\n",
> +		ipc.data.status.current,
> +		strlen(ipc.data.status.desc) ? ipc.data.status.desc : "",
> +		ipc.data.status.error,
> +		ipc.data.status.last_result);
> +
> +	mg_send_head(nc, 200, strlen(buf),
> +		"Cache: no-cache\r\n"
> +		"Content-Type: text/plain");
> +
> +	mg_send(nc, buf, strlen(buf));
> +
> +	nc->flags |= MG_F_SEND_AND_CLOSE;
> +}
> +
> +/*
> + * Code common to V1 and V2
> + */
> +static void upload_handler(struct mg_connection *nc, int ev, void *p)
> +{
> +	struct mg_http_multipart_part *mp;
> +	struct file_upload_state *fus;
> +
> +	switch (ev) {
> +	case MG_EV_HTTP_PART_BEGIN:
> +		mp = (struct mg_http_multipart_part *) p;
> +
> +		fus = (struct file_upload_state *) calloc(1, sizeof(*fus));
> +		if (fus == NULL) {
> +			mg_http_send_error(nc, 500, "Out of memory");
> +			break;
> +		}
> +
> +		fus->fd = ipc_inst_start_ext(SOURCE_WEBSERVER, strlen(mp->file_name), mp->file_name);
> +		if (fus->fd < 0) {
> +			mg_http_send_error(nc, 500, "Failed to queue command");
> +			free(fus);
> +			break;
> +		}
> +
> +		mp->user_data = fus;
> +
> +		break;
> +
> +	case MG_EV_HTTP_PART_DATA:
> +		mp = (struct mg_http_multipart_part *) p;
> +		fus = (struct file_upload_state *) mp->user_data;
> +
> +		if (!fus)
> +			break;
> +
> +		ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len);
> +		fus->len += mp->data.len;
> +
> +		break;
> +
> +	case MG_EV_HTTP_PART_END:
> +		mp = (struct mg_http_multipart_part *) p;
> +		fus = (struct file_upload_state *) mp->user_data;
> +
> +		if (!fus)
> +			break;
> +
> +		ipc_end(fus->fd);
> +
> +		mg_send_response_line(nc, 200,
> +			"Content-Type: text/plain\r\n"
> +			"Connection: close");
> +		mg_send(nc, "\r\n", 2);
> +		mg_printf(nc, "Ok, %s - %d bytes.\r\n", mp->file_name, (int) fus->len);
> +		nc->flags |= MG_F_SEND_AND_CLOSE;
> +
> +		mp->user_data = NULL;
> +		free(fus);
> +		break;
> +	}
> +}
>   
>   static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
>   {
> @@ -510,6 +466,12 @@ static int mongoose_settings(void *elem, void  __attribute__ ((__unused__)) *dat
>   		opts->ssl_key = strdup(tmp);
>   	}
>   #endif
> +	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "api", tmp);
> +	if (strlen(tmp)) {
> +		opts->api_version = (!strcmp(tmp, "1")) ?
> +					MONGOOSE_API_V1 :
> +					MONGOOSE_API_V2;
> +	}
>   	return 0;
>   }
>   
> @@ -523,6 +485,7 @@ static struct option long_options[] = {
>   	{"ssl-key", required_argument, NULL, 'K'},
>   #endif
>   	{"document-root", required_argument, NULL, 'r'},
> +	{"api-version", required_argument, NULL, 'a'},
>   	{NULL, 0, NULL, 0}
>   };
>   
> @@ -538,7 +501,8 @@ void mongoose_print_help(void)
>   		"\t  -C, --ssl-cert <cert>          : ssl certificate to present to clients\n"
>   		"\t  -K, --ssl-key <key>            : key corresponding to the ssl certificate\n"
>   #endif
> -		"\t  -r, --document-root <path>     : path to document root directory (default: %s)\n",
> +		"\t  -r, --document-root <path>     : path to document root directory (default: %s)\n"
> +		"\t  -a, --api-version [1|2]        : set Web protocol API to v1 (legacy) or v2 (default v2)\n",
>   		MG_LISTING, MG_PORT, MG_ROOT);
>   }
>   
> @@ -556,12 +520,14 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[])
>   	int choice = 0;
>   
>   	memset(&opts, 0, sizeof(opts));
> +	/* Set default API version */
> +	opts.api_version = MONGOOSE_API_V2;
>   	if (cfgfname) {
>   		read_module_settings(cfgfname, "webserver", mongoose_settings, &opts);
>   	}
>   
>   	optind = 1;
> -	while ((choice = getopt_long(argc, argv, "lp:sC:K:r:",
> +	while ((choice = getopt_long(argc, argv, "lp:sC:K:r:a:",
>   				     long_options, NULL)) != -1) {
>   		switch (choice) {
>   		case 'l':
> @@ -589,6 +555,11 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[])
>   			free(opts.root);
>   			opts.root = strdup(optarg);
>   			break;
> +		case 'a':
> +			opts.api_version = (!strcmp(optarg, "1")) ?
> +						MONGOOSE_API_V1 :
> +						MONGOOSE_API_V2;
> +			break;
>   		case '?':
>   		default:
>   			return -EINVAL;
> @@ -619,22 +590,23 @@ int start_mongoose(const char *cfgfname, int argc, char *argv[])
>   	}
>   
>   	mg_set_protocol_http_websocket(nc);
> -	mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL));
> -#if defined(CONFIG_MONGOOSE_WEB_API_V1)
> -	mg_register_http_endpoint(nc, "/handle_post_request", MG_CB(upload_handler_v1, NULL));
> -	mg_register_http_endpoint(nc, "/getstatus.json", MG_CB(recovery_status, NULL));
> -	mg_register_http_endpoint(nc, "/rebootTarget", MG_CB(reboot_target, NULL));
> -	mg_register_http_endpoint(nc, "/postUpdateCommand", MG_CB(post_update_cmd, NULL));
> -#endif
> -#if defined(CONFIG_MONGOOSE_WEB_API_V2)
> -	mg_register_http_endpoint(nc, "/restart", restart_handler);
> -	mg_start_thread(broadcast_message_thread, &mgr);
> -	mg_start_thread(broadcast_progress_thread, &mgr);
> -#endif
> +	switch (opts.api_version) {
> +	case MONGOOSE_API_V1:
> +		mg_register_http_endpoint(nc, "/handle_post_request", MG_CB(upload_handler_v1, NULL));
> +		mg_register_http_endpoint(nc, "/getstatus.json", MG_CB(recovery_status, NULL));
> +		break;
> +	case MONGOOSE_API_V2:
> +		mg_register_http_endpoint(nc, "/restart", restart_handler);
> +		mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL));
> +		mg_start_thread(broadcast_message_thread, &mgr);
> +		mg_start_thread(broadcast_progress_thread, &mgr);
> +		break;
> +	}
>   
> -	printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s]\n",
> +	printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s] and API %s\n",
>   		MG_VERSION, getpid(), s_http_port,
> -		s_http_server_opts.document_root);
> +		s_http_server_opts.document_root,
> +		(opts.api_version  == MONGOOSE_API_V1) ? "v1" : "v2");
>   
>   	for (;;) {
>   		mg_mgr_poll(&mgr, 100);

If you like you could disable the http file server for version 1. 
Therefore you have to skip the mg_serve_http function in the ev_handler 
function or add an empty ev_handler_v1 function.

Best regards
   Stefan
Stefano Babic March 7, 2018, 10:10 p.m. UTC | #2
Hi Stefan,

On 07/03/2018 20:33, Stefan Herbrechtsmeier wrote:
> Hi Stefano,
> 

[snip]

>>  	for (;;) {
>>  		mg_mgr_poll(&mgr, 100);
> 
> If you like you could disable the http file server for version 1.

I like it, it is a good idea, thanks for the tip !

> Therefore you have to skip the mg_serve_http function in the ev_handler
> function or add an empty ev_handler_v1 function.

I'll do and I post a V4.

Best regards,
Stefano
diff mbox series

Patch

diff --git a/mongoose/Config.in b/mongoose/Config.in
index a001247..29cac90 100644
--- a/mongoose/Config.in
+++ b/mongoose/Config.in
@@ -18,24 +18,6 @@  config MONGOOSE
 
 endchoice
 
-choice
-	prompt "Web Application Interface"
-	default MONGOOSE_WEB_API_V1
-	help
-	  Choose the bootloader
-
-config MONGOOSE_WEB_API_V1
-	bool "Version 1 (deprecated)"
-	help
-	  Support for version 1
-
-config MONGOOSE_WEB_API_V2
-	bool "Version 2"
-	help
-	  Support for version 2
-
-endchoice
-
 config MONGOOSEIPV6
 	bool "IPv6 support"
 	default y
diff --git a/mongoose/Makefile b/mongoose/Makefile
index 77a616c..dc2d3d3 100644
--- a/mongoose/Makefile
+++ b/mongoose/Makefile
@@ -1,9 +1,7 @@ 
 ifneq ($(CONFIG_WEBSERVER),)
 ifneq ($(CONFIG_MONGOOSE),)
 KBUILD_CFLAGS += -DMG_ENABLE_HTTP_STREAMING_MULTIPART=1
-ifneq ($(CONFIG_MONGOOSE_WEB_API_V2),)
 KBUILD_CFLAGS += -DMG_ENABLE_HTTP_WEBSOCKET=1 -DMG_ENABLE_THREADS=1
-endif
 ifneq ($(CONFIG_MONGOOSEIPV6),)
 KBUILD_CFLAGS += -DMG_ENABLE_IPV6=1
 endif
diff --git a/mongoose/mongoose_interface.c b/mongoose/mongoose_interface.c
index 0e22671..9ef9070 100644
--- a/mongoose/mongoose_interface.c
+++ b/mongoose/mongoose_interface.c
@@ -32,6 +32,11 @@ 
 #define MG_PORT "8080"
 #define MG_ROOT "."
 
+enum MONGOOSE_API_VERSION {
+	MONGOOSE_API_V1,
+	MONGOOSE_API_V2
+};
+
 struct mongoose_options {
 	char *root;
 	char *listing;
@@ -40,6 +45,7 @@  struct mongoose_options {
 	char *ssl_cert;
 	char *ssl_key;
 #endif
+	enum MONGOOSE_API_VERSION api_version;
 };
 
 struct file_upload_state {
@@ -50,7 +56,9 @@  struct file_upload_state {
 static struct mg_serve_http_opts s_http_server_opts;
 static void upload_handler(struct mg_connection *nc, int ev, void *p);
 
-#if defined(CONFIG_MONGOOSE_WEB_API_V2)
+/*
+ * These functions are for V2 of the protocol
+ */
 #define enum_string(x)	[x] = #x
 static const char *get_status_string(unsigned int status)
 {
@@ -111,210 +119,7 @@  static size_t snescape(char *dst, size_t n, const char *src)
 
 	return len;
 }
-#endif
-
-#if defined(CONFIG_MONGOOSE_WEB_API_V1)
-static void upload_handler_v1(struct mg_connection *nc, int ev, void *p)
-{
-	struct mg_str *filename, *data;
-	struct http_message *hm;
-	size_t length;
-	char buf[16];
-	int fd;
-
-	switch (ev) {
-	case MG_EV_HTTP_REQUEST:
-		hm = (struct http_message *) p;
-
-		filename = mg_get_http_header(hm, "X_FILENAME");
-		if (filename == NULL) {
-			mg_http_send_error(nc, 403, NULL);
-			return;
-		}
-
-		data = mg_get_http_header(hm, "Content-length");
-		if (data == NULL || data->len >= ARRAY_SIZE(buf)) {
-			mg_http_send_error(nc, 403, NULL);
-			return;
-		}
-
-		memcpy(buf, data->p, data->len);
-		buf[data->len] = '\0';
-		length = strtoul(data->p, NULL, 10);
-		if (length == 0) {
-			mg_http_send_error(nc, 403, NULL);
-			return;
-		}
-
-		fd = ipc_inst_start_ext(SOURCE_WEBSERVER, filename->len, filename->p);
-		ipc_send_data(fd, (char *) hm->body.p, hm->body.len);
-		ipc_end(fd);
-
-		mg_send_response_line(nc, 200,
-			"Content-Type: text/plain\r\n"
-			"Connection: close");
-		mg_send(nc, "\r\n", 2);
-		mg_printf(nc, "Ok, %.*s - %d bytes.\r\n", (int) filename->len, filename->p, (int) length);
-		nc->flags |= MG_F_SEND_AND_CLOSE;
-		break;
-	default:
-		upload_handler(nc, ev, p);
-		break;
-	}
-}
-#endif
-
-static void upload_handler(struct mg_connection *nc, int ev, void *p)
-{
-	struct mg_http_multipart_part *mp;
-	struct file_upload_state *fus;
-
-	switch (ev) {
-	case MG_EV_HTTP_PART_BEGIN:
-		mp = (struct mg_http_multipart_part *) p;
-
-		fus = (struct file_upload_state *) calloc(1, sizeof(*fus));
-		if (fus == NULL) {
-			mg_http_send_error(nc, 500, "Out of memory");
-			break;
-		}
-
-		fus->fd = ipc_inst_start_ext(SOURCE_WEBSERVER, strlen(mp->file_name), mp->file_name);
-		if (fus->fd < 0) {
-			mg_http_send_error(nc, 500, "Failed to queue command");
-			free(fus);
-			break;
-		}
-
-		mp->user_data = fus;
-
-		break;
-
-	case MG_EV_HTTP_PART_DATA:
-		mp = (struct mg_http_multipart_part *) p;
-		fus = (struct file_upload_state *) mp->user_data;
-
-		if (!fus)
-			break;
-
-		ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len);
-		fus->len += mp->data.len;
-
-		break;
-
-	case MG_EV_HTTP_PART_END:
-		mp = (struct mg_http_multipart_part *) p;
-		fus = (struct file_upload_state *) mp->user_data;
-
-		if (!fus)
-			break;
-
-		ipc_end(fus->fd);
-
-		mg_send_response_line(nc, 200,
-			"Content-Type: text/plain\r\n"
-			"Connection: close");
-		mg_send(nc, "\r\n", 2);
-		mg_printf(nc, "Ok, %s - %d bytes.\r\n", mp->file_name, (int) fus->len);
-		nc->flags |= MG_F_SEND_AND_CLOSE;
-
-		mp->user_data = NULL;
-		free(fus);
-		break;
-	}
-}
 
-#if defined(CONFIG_MONGOOSE_WEB_API_V1)
-static void recovery_status(struct mg_connection *nc, int ev, void *ev_data)
-{
-	ipc_message ipc;
-	int ret;
-	char buf[4096];
-
-	(void)ev;
-	(void)ev_data;
-
-	ret = ipc_get_status(&ipc);
-
-	if (ret) {
-		mg_http_send_error(nc, 500, NULL);
-		return;
-	}
-
-	snprintf(buf, sizeof(buf),
-		"{\r\n"
-		"\t\"Status\" : \"%d\",\r\n"
-		"\t\"Msg\" : \"%s\",\r\n"
-		"\t\"Error\" : \"%d\",\r\n"
-		"\t\"LastResult\" : \"%d\"\r\n"
-		"}\r\n",
-		ipc.data.status.current,
-		strlen(ipc.data.status.desc) ? ipc.data.status.desc : "",
-		ipc.data.status.error,
-		ipc.data.status.last_result);
-
-	mg_send_head(nc, 200, strlen(buf),
-		"Cache: no-cache\r\n"
-		"Content-Type: text/plain");
-
-	mg_send(nc, buf, strlen(buf));
-
-	nc->flags |= MG_F_SEND_AND_CLOSE;
-}
-
-static void reboot_target(struct mg_connection *nc, int ev, void *ev_data)
-{
-	struct http_message *hm = (struct http_message *) ev_data;
-	int ret;
-
-	(void)ev;
-
-	if(mg_vcasecmp(&hm->method, "POST") == 0) {
-		ret = system("reboot");
-		if (ret) {
-			mg_http_send_error(nc, 500,
-				"Device cannot be reboot, internal fault.");
-			return;
-		}
-
-		mg_http_send_error(nc, 200, "Device will reboot now.");
-	}
-	else {
-		mg_send_response_line(nc, 200,
-			"Content-Type: text/html\r\n"
-			"Connection: close");
-		mg_send(nc, "\r\n", 2);
-		mg_printf(nc,
-			"<form method='POST' action=''>"
-			"<input type='submit' value='Reboot'>"
-			"</form>");
-		nc->flags |= MG_F_SEND_AND_CLOSE;
-	}
-}
-
-static void post_update_cmd(struct mg_connection *nc, int ev, void *ev_data)
-{
-	ipc_message msg = {};
-
-	(void)ev;
-	(void)ev_data;
-
-	int ret = ipc_postupdate(&msg);
-	mg_send_response_line(nc, 200, "Content-Type: application/json");
-	mg_send(nc, "\r\n", 2);
-	mg_printf(nc,
-		"{\r\n"
-		"\t\"code\": %d,\r\n"
-		"\t\"error\": \"%s\",\r\n"
-		"\t\"detail\": \"%s\"\r\n"
-		"}",
-		(ret == 0) ? 200 : 501,
-		(ret == 0) ? "" : "Internal server error",
-		(ret == 0) ? "" : "Failed to queue command");
-
-	nc->flags |= MG_F_SEND_AND_CLOSE;
-}
-#elif defined(CONFIG_MONGOOSE_WEB_API_V2)
 static void restart_handler(struct mg_connection *nc, int ev, void *ev_data)
 {
 	struct http_message *hm = (struct http_message *) ev_data;
@@ -470,7 +275,158 @@  static void *broadcast_progress_thread(void *data)
 
 	return NULL;
 }
-#endif
+
+/*
+ * These functions are for V1 of the protocol
+ */
+static void upload_handler_v1(struct mg_connection *nc, int ev, void *p)
+{
+	struct mg_str *filename, *data;
+	struct http_message *hm;
+	size_t length;
+	char buf[16];
+	int fd;
+
+	switch (ev) {
+	case MG_EV_HTTP_REQUEST:
+		hm = (struct http_message *) p;
+
+		filename = mg_get_http_header(hm, "X_FILENAME");
+		if (filename == NULL) {
+			mg_http_send_error(nc, 403, NULL);
+			return;
+		}
+
+		data = mg_get_http_header(hm, "Content-length");
+		if (data == NULL || data->len >= ARRAY_SIZE(buf)) {
+			mg_http_send_error(nc, 403, NULL);
+			return;
+		}
+
+		memcpy(buf, data->p, data->len);
+		buf[data->len] = '\0';
+		length = strtoul(data->p, NULL, 10);
+		if (length == 0) {
+			mg_http_send_error(nc, 403, NULL);
+			return;
+		}
+
+		fd = ipc_inst_start_ext(SOURCE_WEBSERVER, filename->len, filename->p);
+		ipc_send_data(fd, (char *) hm->body.p, hm->body.len);
+		ipc_end(fd);
+
+		mg_send_response_line(nc, 200,
+			"Content-Type: text/plain\r\n"
+			"Connection: close");
+		mg_send(nc, "\r\n", 2);
+		mg_printf(nc, "Ok, %.*s - %d bytes.\r\n", (int) filename->len, filename->p, (int) length);
+		nc->flags |= MG_F_SEND_AND_CLOSE;
+		break;
+	default:
+		upload_handler(nc, ev, p);
+		break;
+	}
+}
+
+static void recovery_status(struct mg_connection *nc, int ev, void *ev_data)
+{
+	ipc_message ipc;
+	int ret;
+	char buf[4096];
+
+	(void)ev;
+	(void)ev_data;
+
+	ret = ipc_get_status(&ipc);
+
+	if (ret) {
+		mg_http_send_error(nc, 500, NULL);
+		return;
+	}
+
+	snprintf(buf, sizeof(buf),
+		"{\r\n"
+		"\t\"Status\" : \"%d\",\r\n"
+		"\t\"Msg\" : \"%s\",\r\n"
+		"\t\"Error\" : \"%d\",\r\n"
+		"\t\"LastResult\" : \"%d\"\r\n"
+		"}\r\n",
+		ipc.data.status.current,
+		strlen(ipc.data.status.desc) ? ipc.data.status.desc : "",
+		ipc.data.status.error,
+		ipc.data.status.last_result);
+
+	mg_send_head(nc, 200, strlen(buf),
+		"Cache: no-cache\r\n"
+		"Content-Type: text/plain");
+
+	mg_send(nc, buf, strlen(buf));
+
+	nc->flags |= MG_F_SEND_AND_CLOSE;
+}
+
+/*
+ * Code common to V1 and V2
+ */
+static void upload_handler(struct mg_connection *nc, int ev, void *p)
+{
+	struct mg_http_multipart_part *mp;
+	struct file_upload_state *fus;
+
+	switch (ev) {
+	case MG_EV_HTTP_PART_BEGIN:
+		mp = (struct mg_http_multipart_part *) p;
+
+		fus = (struct file_upload_state *) calloc(1, sizeof(*fus));
+		if (fus == NULL) {
+			mg_http_send_error(nc, 500, "Out of memory");
+			break;
+		}
+
+		fus->fd = ipc_inst_start_ext(SOURCE_WEBSERVER, strlen(mp->file_name), mp->file_name);
+		if (fus->fd < 0) {
+			mg_http_send_error(nc, 500, "Failed to queue command");
+			free(fus);
+			break;
+		}
+
+		mp->user_data = fus;
+
+		break;
+
+	case MG_EV_HTTP_PART_DATA:
+		mp = (struct mg_http_multipart_part *) p;
+		fus = (struct file_upload_state *) mp->user_data;
+
+		if (!fus)
+			break;
+
+		ipc_send_data(fus->fd, (char *) mp->data.p, mp->data.len);
+		fus->len += mp->data.len;
+
+		break;
+
+	case MG_EV_HTTP_PART_END:
+		mp = (struct mg_http_multipart_part *) p;
+		fus = (struct file_upload_state *) mp->user_data;
+
+		if (!fus)
+			break;
+
+		ipc_end(fus->fd);
+
+		mg_send_response_line(nc, 200,
+			"Content-Type: text/plain\r\n"
+			"Connection: close");
+		mg_send(nc, "\r\n", 2);
+		mg_printf(nc, "Ok, %s - %d bytes.\r\n", mp->file_name, (int) fus->len);
+		nc->flags |= MG_F_SEND_AND_CLOSE;
+
+		mp->user_data = NULL;
+		free(fus);
+		break;
+	}
+}
 
 static void ev_handler(struct mg_connection *nc, int ev, void *ev_data)
 {
@@ -510,6 +466,12 @@  static int mongoose_settings(void *elem, void  __attribute__ ((__unused__)) *dat
 		opts->ssl_key = strdup(tmp);
 	}
 #endif
+	GET_FIELD_STRING_RESET(LIBCFG_PARSER, elem, "api", tmp);
+	if (strlen(tmp)) {
+		opts->api_version = (!strcmp(tmp, "1")) ?
+					MONGOOSE_API_V1 :
+					MONGOOSE_API_V2;
+	}
 	return 0;
 }
 
@@ -523,6 +485,7 @@  static struct option long_options[] = {
 	{"ssl-key", required_argument, NULL, 'K'},
 #endif
 	{"document-root", required_argument, NULL, 'r'},
+	{"api-version", required_argument, NULL, 'a'},
 	{NULL, 0, NULL, 0}
 };
 
@@ -538,7 +501,8 @@  void mongoose_print_help(void)
 		"\t  -C, --ssl-cert <cert>          : ssl certificate to present to clients\n"
 		"\t  -K, --ssl-key <key>            : key corresponding to the ssl certificate\n"
 #endif
-		"\t  -r, --document-root <path>     : path to document root directory (default: %s)\n",
+		"\t  -r, --document-root <path>     : path to document root directory (default: %s)\n"
+		"\t  -a, --api-version [1|2]        : set Web protocol API to v1 (legacy) or v2 (default v2)\n",
 		MG_LISTING, MG_PORT, MG_ROOT);
 }
 
@@ -556,12 +520,14 @@  int start_mongoose(const char *cfgfname, int argc, char *argv[])
 	int choice = 0;
 
 	memset(&opts, 0, sizeof(opts));
+	/* Set default API version */
+	opts.api_version = MONGOOSE_API_V2;
 	if (cfgfname) {
 		read_module_settings(cfgfname, "webserver", mongoose_settings, &opts);
 	}
 
 	optind = 1;
-	while ((choice = getopt_long(argc, argv, "lp:sC:K:r:",
+	while ((choice = getopt_long(argc, argv, "lp:sC:K:r:a:",
 				     long_options, NULL)) != -1) {
 		switch (choice) {
 		case 'l':
@@ -589,6 +555,11 @@  int start_mongoose(const char *cfgfname, int argc, char *argv[])
 			free(opts.root);
 			opts.root = strdup(optarg);
 			break;
+		case 'a':
+			opts.api_version = (!strcmp(optarg, "1")) ?
+						MONGOOSE_API_V1 :
+						MONGOOSE_API_V2;
+			break;
 		case '?':
 		default:
 			return -EINVAL;
@@ -619,22 +590,23 @@  int start_mongoose(const char *cfgfname, int argc, char *argv[])
 	}
 
 	mg_set_protocol_http_websocket(nc);
-	mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL));
-#if defined(CONFIG_MONGOOSE_WEB_API_V1)
-	mg_register_http_endpoint(nc, "/handle_post_request", MG_CB(upload_handler_v1, NULL));
-	mg_register_http_endpoint(nc, "/getstatus.json", MG_CB(recovery_status, NULL));
-	mg_register_http_endpoint(nc, "/rebootTarget", MG_CB(reboot_target, NULL));
-	mg_register_http_endpoint(nc, "/postUpdateCommand", MG_CB(post_update_cmd, NULL));
-#endif
-#if defined(CONFIG_MONGOOSE_WEB_API_V2)
-	mg_register_http_endpoint(nc, "/restart", restart_handler);
-	mg_start_thread(broadcast_message_thread, &mgr);
-	mg_start_thread(broadcast_progress_thread, &mgr);
-#endif
+	switch (opts.api_version) {
+	case MONGOOSE_API_V1:
+		mg_register_http_endpoint(nc, "/handle_post_request", MG_CB(upload_handler_v1, NULL));
+		mg_register_http_endpoint(nc, "/getstatus.json", MG_CB(recovery_status, NULL));
+		break;
+	case MONGOOSE_API_V2:
+		mg_register_http_endpoint(nc, "/restart", restart_handler);
+		mg_register_http_endpoint(nc, "/upload", MG_CB(upload_handler, NULL));
+		mg_start_thread(broadcast_message_thread, &mgr);
+		mg_start_thread(broadcast_progress_thread, &mgr);
+		break;
+	}
 
-	printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s]\n",
+	printf("Mongoose web server version %s with pid %d started on port(s) %s with web root [%s] and API %s\n",
 		MG_VERSION, getpid(), s_http_port,
-		s_http_server_opts.document_root);
+		s_http_server_opts.document_root,
+		(opts.api_version  == MONGOOSE_API_V1) ? "v1" : "v2");
 
 	for (;;) {
 		mg_mgr_poll(&mgr, 100);