diff mbox series

[v6,12/12] net/httpd-upload: an example web-server implementation for file uploading

Message ID 20240909222720.2563118-13-mikhail.kshevetskiy@iopsys.eu
State Superseded
Delegated to: Ramon Fried
Headers show
Series net: tcp: improve tcp support | expand

Commit Message

Mikhail Kshevetskiy Sept. 9, 2024, 10:27 p.m. UTC
This is an example web-server implementation. It can be used for files
uploading to u-boot using a web-browser. It acts much like tftpget, but no
special servers needs to be installed by the user.

This code can be used as a base for other implementations like firmware
upgrade web-server used by some vendors.

Usage:
  u-boot: start the we-server using the "httpd_upload" command
  PC:     open the "http://your_uboot_ip" link in the browser

Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
---
 cmd/Kconfig                     |  14 ++++
 cmd/net.c                       |  20 ++++++
 include/net/httpd-upload.h      |  12 ++++
 net/Makefile                    |  19 +++++
 net/httpd-upload.c              | 123 ++++++++++++++++++++++++++++++++
 net/httpd_upload/error_400.html |   9 +++
 net/httpd_upload/error_404.html |  10 +++
 net/httpd_upload/index.html     |  14 ++++
 net/httpd_upload/upload_ok.html |   7 ++
 9 files changed, 228 insertions(+)
 create mode 100644 include/net/httpd-upload.h
 create mode 100644 net/httpd-upload.c
 create mode 100644 net/httpd_upload/error_400.html
 create mode 100644 net/httpd_upload/error_404.html
 create mode 100644 net/httpd_upload/index.html
 create mode 100644 net/httpd_upload/upload_ok.html

Comments

Simon Glass Sept. 12, 2024, 12:59 a.m. UTC | #1
Hi Mikhail,

On Mon, 9 Sept 2024 at 16:27, Mikhail Kshevetskiy
<mikhail.kshevetskiy@iopsys.eu> wrote:
>
> This is an example web-server implementation. It can be used for files
> uploading to u-boot using a web-browser. It acts much like tftpget, but no
> special servers needs to be installed by the user.
>
> This code can be used as a base for other implementations like firmware
> upgrade web-server used by some vendors.
>
> Usage:
>   u-boot: start the we-server using the "httpd_upload" command
>   PC:     open the "http://your_uboot_ip" link in the browser
>
> Signed-off-by: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> ---
>  cmd/Kconfig                     |  14 ++++
>  cmd/net.c                       |  20 ++++++
>  include/net/httpd-upload.h      |  12 ++++
>  net/Makefile                    |  19 +++++
>  net/httpd-upload.c              | 123 ++++++++++++++++++++++++++++++++
>  net/httpd_upload/error_400.html |   9 +++
>  net/httpd_upload/error_404.html |  10 +++
>  net/httpd_upload/index.html     |  14 ++++
>  net/httpd_upload/upload_ok.html |   7 ++
>  9 files changed, 228 insertions(+)
>  create mode 100644 include/net/httpd-upload.h
>  create mode 100644 net/httpd-upload.c
>  create mode 100644 net/httpd_upload/error_400.html
>  create mode 100644 net/httpd_upload/error_404.html
>  create mode 100644 net/httpd_upload/index.html
>  create mode 100644 net/httpd_upload/upload_ok.html

Can you just include the strings in the C file?

>
> diff --git a/cmd/Kconfig b/cmd/Kconfig
> index abcd003f7f1..55b9d04f2fa 100644
> --- a/cmd/Kconfig
> +++ b/cmd/Kconfig
> @@ -2014,6 +2014,20 @@ config CMD_NETCAT
>           netcat is a simple command to load/store kernel, or other files,
>           using netcat like manner over TCP.
>
> +config CMD_HTTPD_UPLOAD
> +       bool "an example HTTP server for file uploading"
> +       depends on HTTPD_COMMON
> +       help
> +         HTTP/1.1 compatible server for file uploading.

Please expand help

> +
> +config CMD_HTTPD_UPLOAD_MAX_SIZE
> +       int "Maximum uploading size"
> +       depends on CMD_HTTPD_UPLOAD
> +       default 209715200
> +       help
> +         This sets maximum size of uploaded file. Real transfer will be

sets the maximum

of any uploaded

> +         slightly more than this limit.

Please describe why

> +
>  config CMD_MII
>         bool "mii"
>         imply CMD_MDIO
> diff --git a/cmd/net.c b/cmd/net.c
> index 364139ec5b9..e5fddc8c7c5 100644
> --- a/cmd/net.c
> +++ b/cmd/net.c
> @@ -21,6 +21,9 @@
>  #include <net/udp.h>
>  #include <net/sntp.h>
>  #include <net/ncsi.h>
> +#if defined(CONFIG_CMD_HTTPD_UPLOAD)
> +#include <net/httpd-upload.h>
> +#endif
>
>  static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
>
> @@ -228,6 +231,23 @@ U_BOOT_CMD(
>  );
>  #endif
>
> +#if defined(CONFIG_CMD_HTTPD_UPLOAD)
> +static int do_httpd_upload(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
> +{
> +       if (argc < 2)
> +               return 1;
> +
> +       httpd_upload_prepare();
> +       return netboot_common(HTTPD, cmdtp, argc, argv);
> +}
> +
> +U_BOOT_CMD(
> +       httpd_upload,   2,      1,      do_httpd_upload,
> +       "starts httpd server for file uploading",
> +       "[loadAddress]\n"
> +);
> +#endif
> +
>  static void netboot_update_env(void)
>  {
>         char tmp[46];
> diff --git a/include/net/httpd-upload.h b/include/net/httpd-upload.h
> new file mode 100644
> index 00000000000..a80df214668
> --- /dev/null
> +++ b/include/net/httpd-upload.h
> @@ -0,0 +1,12 @@
> +/* SPDX-License-Identifier: BSD-2-Clause
> + *
> + * httpd-upload include file
> + * Copyright (C) 2024 IOPSYS Software Solutions AB
> + * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> + */
> +#ifndef __NET_HTTPD_UPLOAD_TCP_H__
> +#define __NET_HTTPD_UPLOAD_TCP_H__
> +
> +void httpd_upload_prepare(void);
> +
> +#endif /* __NET_HTTPD_UPLOAD_TCP_H__ */
> diff --git a/net/Makefile b/net/Makefile
> index c1f491fad02..e7cbbc2248e 100644
> --- a/net/Makefile
> +++ b/net/Makefile
> @@ -35,8 +35,27 @@ obj-$(CONFIG_PROT_TCP) += tcp.o
>  obj-$(CONFIG_CMD_WGET) += wget.o
>  obj-$(CONFIG_CMD_NETCAT) += netcat.o
>  obj-$(CONFIG_HTTPD_COMMON) += httpd.o
> +obj-$(CONFIG_CMD_HTTPD_UPLOAD) += httpd-upload.o
>
>  # Disable this warning as it is triggered by:
>  # sprintf(buf, index ? "foo%d" : "foo", index)
>  # and this is intentional usage.
>  CFLAGS_eth_common.o += -Wno-format-extra-args
> +
> +STATIC_SUBST := 's/^\(unsigned char \)/static \1/'
> +SIZE_REMOVE_SUBST := 's/^unsigned int .*//'
> +
> +httpd_upload_generated:
> +       rm -rf $(src)/httpd_upload_generated
> +       mkdir -p $(src)/httpd_upload_generated
> +       cd $(src)/httpd_upload && find . -type f | while read fname; do \
> +               name="$${fname##*/}" && \
> +               name="$${name%%.*}"  && \
> +               set -o pipefail && xxd -i "$${fname##./}" | \
> +                       sed $(STATIC_SUBST) | \
> +                       sed $(SIZE_REMOVE_SUBST) > ../httpd_upload_generated/$${name}.h; \
> +       done
> +
> +.PHONY: httpd_upload_generated
> +
> +net/httpd-upload.o:    httpd_upload_generated
> diff --git a/net/httpd-upload.c b/net/httpd-upload.c
> new file mode 100644
> index 00000000000..1e1e0b1cf75
> --- /dev/null
> +++ b/net/httpd-upload.c
> @@ -0,0 +1,123 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * httpd-upload support driver
> + * Copyright (C) 2024 IOPSYS Software Solutions AB
> + * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
> + */
> +
> +#include <command.h>
> +#include <net.h>
> +#include <net/httpd.h>
> +#include <net/httpd-upload.h>
> +
> +#define MAX_FILE_SIZE  CONFIG_CMD_HTTPD_UPLOAD_MAX_SIZE
> +
> +static enum net_loop_state  httpd_on_stop(void);
> +
> +static enum httpd_req_check httpd_pre_post(void *req_id, const char *url,
> +                                          struct httpd_post_data *post);
> +static struct http_reply    *httpd_get(void *req_id, const char *url);
> +static struct http_reply    *httpd_post(void *req_id, const char *url,
> +                                       struct httpd_post_data *post);
> +static void                 httpd_on_req_end(void *req_id);
> +
> +#include "httpd_upload_generated/error_400.h"
> +#include "httpd_upload_generated/error_404.h"
> +#include "httpd_upload_generated/index.h"
> +#include "httpd_upload_generated/upload_ok.h"
> +
> +static struct http_reply error_400 = {
> +       .code      = 400,
> +       .code_msg  = "Bad Request",
> +       .data_type = "text/html; charset=utf-8",
> +       .data      = error_400_html,
> +       .len       = sizeof(error_400_html)
> +};
> +
> +static struct http_reply error_404 = {
> +       .code      = 404,
> +       .code_msg  = "Not Found",
> +       .data_type = "text/html; charset=utf-8",
> +       .data      = error_404_html,
> +       .len       = sizeof(error_404_html)
> +};
> +
> +static struct http_reply index = {
> +       .code      = 200,
> +       .code_msg  = "OK",
> +       .data_type = "text/html; charset=utf-8",
> +       .data      = index_html,
> +       .len       = sizeof(index_html)
> +};
> +
> +static struct http_reply upload_ok = {
> +       .code      = 200,
> +       .code_msg  = "OK",
> +       .data_type = "text/html; charset=utf-8",
> +       .data      = upload_ok_html,
> +       .len       = sizeof(upload_ok_html)
> +};
> +
> +static struct httpd_config cfg = {
> +       .on_stop    = httpd_on_stop,
> +       .on_req_end = httpd_on_req_end,
> +       .get        = httpd_get,
> +       .post       = httpd_post,
> +       .pre_post   = httpd_pre_post,
> +       .error_400  = &error_400,
> +       .error_404  = &error_404,
> +};
> +
> +static enum net_loop_state     httpd_loop_state;
> +static void                    *post_req_id;
> +
> +void httpd_upload_prepare(void)
> +{
> +       httpd_setup(&cfg);
> +       httpd_loop_state = NETLOOP_FAIL;
> +}
> +
> +static enum httpd_req_check httpd_pre_post(void *req_id, const char *url,
> +                                          struct httpd_post_data *post)
> +{
> +       if (post->size > MAX_FILE_SIZE) {
> +               printf("HTTPD: reset connection, upload file is too large\n");
> +               return HTTPD_CLNT_RST;
> +       }
> +
> +       post_req_id = req_id;
> +       return HTTPD_REQ_OK;
> +}
> +
> +static struct http_reply *httpd_post(void *req_id, const char *url,
> +                                    struct httpd_post_data *post)
> +{
> +       if (strcmp(url, "/file_upload"))
> +               return &error_404;
> +
> +       httpd_loop_state = NETLOOP_SUCCESS;
> +       printf("HTTPD: upload OK\n");
> +       return &upload_ok;
> +}
> +
> +static struct http_reply *httpd_get(void *req_id, const char *url)
> +{
> +       if (!strcmp(url, "/"))
> +               return &index;
> +       if (!strcmp(url, "/index.html"))
> +               return &index;
> +       return &error_404;
> +}
> +
> +static void httpd_on_req_end(void *req_id)
> +{
> +       if (req_id == post_req_id) {
> +               post_req_id = NULL;
> +               httpd_stop();
> +       }
> +}
> +
> +static enum net_loop_state httpd_on_stop(void)
> +{
> +       return httpd_loop_state;
> +}
> diff --git a/net/httpd_upload/error_400.html b/net/httpd_upload/error_400.html
> new file mode 100644
> index 00000000000..de654364edf
> --- /dev/null
> +++ b/net/httpd_upload/error_400.html
> @@ -0,0 +1,9 @@
> +<html>
> +  <head><title>400</title></head>
> +  <body>
> +    <h1>400 - Bad Request</h1>
> +    <p>
> +      Sorry, the request you are trying to do is wrong.
> +    </p>
> +  </body>
> +</html>
> diff --git a/net/httpd_upload/error_404.html b/net/httpd_upload/error_404.html
> new file mode 100644
> index 00000000000..9dac22d497d
> --- /dev/null
> +++ b/net/httpd_upload/error_404.html
> @@ -0,0 +1,10 @@
> +<html>
> +  <head><title>404</title></head>
> +  <body>
> +    <h1>404 - Page not found</h1>
> +    <p>
> +      Sorry, the page you are requesting was not found on this
> +      server.
> +    </p>
> +  </body>
> +</html>
> diff --git a/net/httpd_upload/index.html b/net/httpd_upload/index.html
> new file mode 100644
> index 00000000000..e7d5ac943b6
> --- /dev/null
> +++ b/net/httpd_upload/index.html
> @@ -0,0 +1,14 @@
> +<html>
> +  <head><title>Upload File</title></head>
> +  <body>
> +    <h1>Upload File.</h1>
> +    <p>This will write the uploaded file to the memory arear pointed by ${loadaddr}.
> +      <form method="post" enctype="multipart/form-data" action="file_upload">
> +        File to upload:
> +        <input type="file" name="fileID" size="500" /><br />
> +        <p>&nbsp;&nbsp;<input type="submit" value="upload" />
> +        <p>It takes no more than a second after the file has been uploaded until status OK is shown.
> +      </form>
> +    </p>
> +  </body>
> +</html>
> diff --git a/net/httpd_upload/upload_ok.html b/net/httpd_upload/upload_ok.html
> new file mode 100644
> index 00000000000..8d2e561982f
> --- /dev/null
> +++ b/net/httpd_upload/upload_ok.html
> @@ -0,0 +1,7 @@
> +<html>
> +  <head><title>OK</title></head>
> +  <body>
> +    <h1>Upload OK</h1>
> +    <p>The file was uploaded.</p>
> +  </body>
> +</html>
> --
> 2.45.2
>

REgards,
Simon
diff mbox series

Patch

diff --git a/cmd/Kconfig b/cmd/Kconfig
index abcd003f7f1..55b9d04f2fa 100644
--- a/cmd/Kconfig
+++ b/cmd/Kconfig
@@ -2014,6 +2014,20 @@  config CMD_NETCAT
 	  netcat is a simple command to load/store kernel, or other files,
 	  using netcat like manner over TCP.
 
+config CMD_HTTPD_UPLOAD
+	bool "an example HTTP server for file uploading"
+	depends on HTTPD_COMMON
+	help
+	  HTTP/1.1 compatible server for file uploading.
+
+config CMD_HTTPD_UPLOAD_MAX_SIZE
+	int "Maximum uploading size"
+	depends on CMD_HTTPD_UPLOAD
+	default 209715200
+	help
+	  This sets maximum size of uploaded file. Real transfer will be
+	  slightly more than this limit.
+
 config CMD_MII
 	bool "mii"
 	imply CMD_MDIO
diff --git a/cmd/net.c b/cmd/net.c
index 364139ec5b9..e5fddc8c7c5 100644
--- a/cmd/net.c
+++ b/cmd/net.c
@@ -21,6 +21,9 @@ 
 #include <net/udp.h>
 #include <net/sntp.h>
 #include <net/ncsi.h>
+#if defined(CONFIG_CMD_HTTPD_UPLOAD)
+#include <net/httpd-upload.h>
+#endif
 
 static int netboot_common(enum proto_t, struct cmd_tbl *, int, char * const []);
 
@@ -228,6 +231,23 @@  U_BOOT_CMD(
 );
 #endif
 
+#if defined(CONFIG_CMD_HTTPD_UPLOAD)
+static int do_httpd_upload(struct cmd_tbl *cmdtp, int flag, int argc, char *const argv[])
+{
+	if (argc < 2)
+		return 1;
+
+	httpd_upload_prepare();
+	return netboot_common(HTTPD, cmdtp, argc, argv);
+}
+
+U_BOOT_CMD(
+	httpd_upload,   2,      1,      do_httpd_upload,
+	"starts httpd server for file uploading",
+	"[loadAddress]\n"
+);
+#endif
+
 static void netboot_update_env(void)
 {
 	char tmp[46];
diff --git a/include/net/httpd-upload.h b/include/net/httpd-upload.h
new file mode 100644
index 00000000000..a80df214668
--- /dev/null
+++ b/include/net/httpd-upload.h
@@ -0,0 +1,12 @@ 
+/* SPDX-License-Identifier: BSD-2-Clause
+ *
+ * httpd-upload include file
+ * Copyright (C) 2024 IOPSYS Software Solutions AB
+ * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+ */
+#ifndef __NET_HTTPD_UPLOAD_TCP_H__
+#define __NET_HTTPD_UPLOAD_TCP_H__
+
+void httpd_upload_prepare(void);
+
+#endif /* __NET_HTTPD_UPLOAD_TCP_H__ */
diff --git a/net/Makefile b/net/Makefile
index c1f491fad02..e7cbbc2248e 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -35,8 +35,27 @@  obj-$(CONFIG_PROT_TCP) += tcp.o
 obj-$(CONFIG_CMD_WGET) += wget.o
 obj-$(CONFIG_CMD_NETCAT) += netcat.o
 obj-$(CONFIG_HTTPD_COMMON) += httpd.o
+obj-$(CONFIG_CMD_HTTPD_UPLOAD) += httpd-upload.o
 
 # Disable this warning as it is triggered by:
 # sprintf(buf, index ? "foo%d" : "foo", index)
 # and this is intentional usage.
 CFLAGS_eth_common.o += -Wno-format-extra-args
+
+STATIC_SUBST := 's/^\(unsigned char \)/static \1/'
+SIZE_REMOVE_SUBST := 's/^unsigned int .*//'
+
+httpd_upload_generated:
+	rm -rf $(src)/httpd_upload_generated
+	mkdir -p $(src)/httpd_upload_generated
+	cd $(src)/httpd_upload && find . -type f | while read fname; do \
+		name="$${fname##*/}" && \
+		name="$${name%%.*}"  && \
+		set -o pipefail && xxd -i "$${fname##./}" | \
+			sed $(STATIC_SUBST) | \
+			sed $(SIZE_REMOVE_SUBST) > ../httpd_upload_generated/$${name}.h; \
+	done
+
+.PHONY: httpd_upload_generated
+
+net/httpd-upload.o:	httpd_upload_generated
diff --git a/net/httpd-upload.c b/net/httpd-upload.c
new file mode 100644
index 00000000000..1e1e0b1cf75
--- /dev/null
+++ b/net/httpd-upload.c
@@ -0,0 +1,123 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * httpd-upload support driver
+ * Copyright (C) 2024 IOPSYS Software Solutions AB
+ * Author: Mikhail Kshevetskiy <mikhail.kshevetskiy@iopsys.eu>
+ */
+
+#include <command.h>
+#include <net.h>
+#include <net/httpd.h>
+#include <net/httpd-upload.h>
+
+#define MAX_FILE_SIZE	CONFIG_CMD_HTTPD_UPLOAD_MAX_SIZE
+
+static enum net_loop_state  httpd_on_stop(void);
+
+static enum httpd_req_check httpd_pre_post(void *req_id, const char *url,
+					   struct httpd_post_data *post);
+static struct http_reply    *httpd_get(void *req_id, const char *url);
+static struct http_reply    *httpd_post(void *req_id, const char *url,
+					struct httpd_post_data *post);
+static void		     httpd_on_req_end(void *req_id);
+
+#include "httpd_upload_generated/error_400.h"
+#include "httpd_upload_generated/error_404.h"
+#include "httpd_upload_generated/index.h"
+#include "httpd_upload_generated/upload_ok.h"
+
+static struct http_reply error_400 = {
+	.code      = 400,
+	.code_msg  = "Bad Request",
+	.data_type = "text/html; charset=utf-8",
+	.data      = error_400_html,
+	.len       = sizeof(error_400_html)
+};
+
+static struct http_reply error_404 = {
+	.code      = 404,
+	.code_msg  = "Not Found",
+	.data_type = "text/html; charset=utf-8",
+	.data      = error_404_html,
+	.len       = sizeof(error_404_html)
+};
+
+static struct http_reply index = {
+	.code      = 200,
+	.code_msg  = "OK",
+	.data_type = "text/html; charset=utf-8",
+	.data      = index_html,
+	.len       = sizeof(index_html)
+};
+
+static struct http_reply upload_ok = {
+	.code      = 200,
+	.code_msg  = "OK",
+	.data_type = "text/html; charset=utf-8",
+	.data      = upload_ok_html,
+	.len       = sizeof(upload_ok_html)
+};
+
+static struct httpd_config cfg = {
+	.on_stop    = httpd_on_stop,
+	.on_req_end = httpd_on_req_end,
+	.get        = httpd_get,
+	.post       = httpd_post,
+	.pre_post   = httpd_pre_post,
+	.error_400  = &error_400,
+	.error_404  = &error_404,
+};
+
+static enum net_loop_state	httpd_loop_state;
+static void			*post_req_id;
+
+void httpd_upload_prepare(void)
+{
+	httpd_setup(&cfg);
+	httpd_loop_state = NETLOOP_FAIL;
+}
+
+static enum httpd_req_check httpd_pre_post(void *req_id, const char *url,
+					   struct httpd_post_data *post)
+{
+	if (post->size > MAX_FILE_SIZE) {
+		printf("HTTPD: reset connection, upload file is too large\n");
+		return HTTPD_CLNT_RST;
+	}
+
+	post_req_id = req_id;
+	return HTTPD_REQ_OK;
+}
+
+static struct http_reply *httpd_post(void *req_id, const char *url,
+				     struct httpd_post_data *post)
+{
+	if (strcmp(url, "/file_upload"))
+		return &error_404;
+
+	httpd_loop_state = NETLOOP_SUCCESS;
+	printf("HTTPD: upload OK\n");
+	return &upload_ok;
+}
+
+static struct http_reply *httpd_get(void *req_id, const char *url)
+{
+	if (!strcmp(url, "/"))
+		return &index;
+	if (!strcmp(url, "/index.html"))
+		return &index;
+	return &error_404;
+}
+
+static void httpd_on_req_end(void *req_id)
+{
+	if (req_id == post_req_id) {
+		post_req_id = NULL;
+		httpd_stop();
+	}
+}
+
+static enum net_loop_state httpd_on_stop(void)
+{
+	return httpd_loop_state;
+}
diff --git a/net/httpd_upload/error_400.html b/net/httpd_upload/error_400.html
new file mode 100644
index 00000000000..de654364edf
--- /dev/null
+++ b/net/httpd_upload/error_400.html
@@ -0,0 +1,9 @@ 
+<html>
+  <head><title>400</title></head>
+  <body>
+    <h1>400 - Bad Request</h1>
+    <p>
+      Sorry, the request you are trying to do is wrong.
+    </p>
+  </body>
+</html>
diff --git a/net/httpd_upload/error_404.html b/net/httpd_upload/error_404.html
new file mode 100644
index 00000000000..9dac22d497d
--- /dev/null
+++ b/net/httpd_upload/error_404.html
@@ -0,0 +1,10 @@ 
+<html>
+  <head><title>404</title></head>
+  <body>
+    <h1>404 - Page not found</h1>
+    <p>
+      Sorry, the page you are requesting was not found on this
+      server.
+    </p>
+  </body>
+</html>
diff --git a/net/httpd_upload/index.html b/net/httpd_upload/index.html
new file mode 100644
index 00000000000..e7d5ac943b6
--- /dev/null
+++ b/net/httpd_upload/index.html
@@ -0,0 +1,14 @@ 
+<html>
+  <head><title>Upload File</title></head>
+  <body>
+    <h1>Upload File.</h1>
+    <p>This will write the uploaded file to the memory arear pointed by ${loadaddr}.
+      <form method="post" enctype="multipart/form-data" action="file_upload">
+        File to upload:
+        <input type="file" name="fileID" size="500" /><br />
+        <p>&nbsp;&nbsp;<input type="submit" value="upload" />
+        <p>It takes no more than a second after the file has been uploaded until status OK is shown.
+      </form>
+    </p>
+  </body>
+</html>
diff --git a/net/httpd_upload/upload_ok.html b/net/httpd_upload/upload_ok.html
new file mode 100644
index 00000000000..8d2e561982f
--- /dev/null
+++ b/net/httpd_upload/upload_ok.html
@@ -0,0 +1,7 @@ 
+<html>
+  <head><title>OK</title></head>
+  <body>
+    <h1>Upload OK</h1>
+    <p>The file was uploaded.</p>
+  </body>
+</html>