
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 Reviewed-by: Simon Glass sjg@chromium.org --- cmd/Kconfig | 25 ++++++ cmd/net.c | 20 +++++ include/net/httpd-upload.h | 12 +++ net/Makefile | 1 + net/httpd-upload.c | 170 +++++++++++++++++++++++++++++++++++++ 5 files changed, 228 insertions(+) create mode 100644 include/net/httpd-upload.h create mode 100644 net/httpd-upload.c
diff --git a/cmd/Kconfig b/cmd/Kconfig index cfdc53e494a..b7749525ae3 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -2017,6 +2017,31 @@ config CMD_NETCAT will be lost or reordered. Any netcat implementation should work, but openbsd one was tested only.
+config CMD_HTTPD_UPLOAD + bool "an example HTTP server for file uploading" + depends on HTTPD_COMMON + help + An example HTTP/1.1 compatible web-server implementation for file + uploading. It acts much like tftpboot command: put user data to a + specified memory location, but no special tools needs to be installed + on the user side. The only required tool is browser. + + Start 'httpd_upload' command, open a browser, connect to the board IP, + select file to upload and press 'Upload' button. This is enougth. + + There is no big profit from this code, but it can be used as a + reference for other web-server implementations (ex: web-based + firmware upgrade/recovery used by some router vendors) + +config CMD_HTTPD_UPLOAD_MAX_SIZE + int "Maximum uploading size" + depends on CMD_HTTPD_UPLOAD + default 209715200 + help + This option sets the resriction on the size of any uploaded file. + Please reserve 2--4 Kb more space due to additional space required + for storing of multipart/form-data header and footer. + config CMD_MII bool "mii" imply CMD_MDIO diff --git a/cmd/net.c b/cmd/net.c index 79bb126dbd4..f2df1eed2ef 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 []);
@@ -229,6 +232,23 @@ U_BOOT_CMD_WITH_SUBCMDS(netcat, U_BOOT_SUBCMD_MKENT(save, 3, 0, do_netcat_save)); #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..c1b41240aab 100644 --- a/net/Makefile +++ b/net/Makefile @@ -35,6 +35,7 @@ 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) diff --git a/net/httpd-upload.c b/net/httpd-upload.c new file mode 100644 index 00000000000..8e43860fa74 --- /dev/null +++ b/net/httpd-upload.c @@ -0,0 +1,170 @@ +// 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); + +static unsigned char error_400_html[] = + "<html>\n" + " <head><title>Bad request</title></head>\n" + " <body>\n" + " <h1>400 - Bad Request</h1>\n" + " <p>The request you are trying to do is wrong!</p>\n" + " </body>\n" + "</html>\n"; + +static unsigned char error_404_html[] = + "<html>\n" + " <head><title>Page not found</title></head>\n" + " <body>\n" + " <h1>404 - Page not found</h1>\n" + " <p>The page you were looking for doesn't exist!</p>\n" + " </body>\n" + "</html>\n"; + +static unsigned char index_html[] = + "<html>\n" + " <head><title>Upload File</title></head>\n" + " <body>\n" + " <h1>Upload File.</h1>\n" + " <p>\n" + " This will write the uploaded file to the memory area pointed\n" + " by ${loadaddr}.\n" + " <form method="post"\n" + " enctype="multipart/form-data"\n" + " action="file_upload">\n" + " File to upload:\n" + " <input type="file" name="fileID" size="500" />\n" + " <p>\n" + " <input type="submit" value="upload" />\n" + " </p>\n" + " <p>\n" + " It takes no more than a second after the file has been\n" + " uploaded until status OK is shown.\n" + " </p>\n" + " </form>\n" + " </p>\n" + " </body>\n" + "</html>\n"; + +static unsigned char upload_ok_html[] = + "<html>\n" + " <head><title>OK</title></head>\n" + " <body>\n" + " <h1>Upload OK</h1>\n" + " <p>The file was uploaded.</p>\n" + " </body>\n" + "</html>\n"; + +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; +}