From 99740f86d7ffc29cba0b7c772a3664bfdc5819b1 Mon Sep 17 00:00:00 2001 From: David Gauchard Date: Wed, 4 Mar 2020 21:20:51 +0100 Subject: [PATCH 1/3] expose hidden WebServer's chunked API --- .../examples/FSBrowser/FSBrowser.ino | 22 ++++++++++++++----- .../ESP8266WebServer/src/ESP8266WebServer.h | 20 +++++++++++++++-- 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index fb5847d4b0..645d46b137 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -186,12 +186,22 @@ void handleFileList() { Dir dir = filesystem->openDir(path); path.clear(); - String output = "["; + // use chunked response to avoid building a huge temporary string + server.chunkedResponseModeStart(200, "text/json"); + bool first = true; + // use the same string for every line + String output; + output.reserve(64); while (dir.next()) { + + if (output.length()) + // send string from previous iteration + // as an HTTP chunk + server.sendContent(output); + File entry = dir.openFile("r"); - if (output != "[") { - output += ','; - } + output = first? '[': ','; + first = false; bool isDir = false; output += "{\"type\":\""; output += (isDir) ? "dir" : "file"; @@ -205,8 +215,10 @@ void handleFileList() { entry.close(); } + // send last string output += "]"; - server.send(200, "text/json", output); + server.sendContent(output); + server.chunkedResponseFinalize(); } void setup(void) { diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index eefcba2ba3..b3e88a5029 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -149,18 +149,34 @@ class ESP8266WebServerTemplate void sendContent(const char *content) { sendContent_P(content); } void sendContent(const char *content, size_t size) { sendContent_P(content, size); } + bool chunkedResponseModeStart (int code, const char* content_type) { + setContentLength(CONTENT_LENGTH_UNKNOWN); + send(code, content_type, emptyString); + } + bool chunkedResponseModeStart (int code, const String& content_type) { + setContentLength(CONTENT_LENGTH_UNKNOWN); + send(code, content_type, emptyString); + } + bool chunkedResponseModeStart (int code, PGM_P content_type) { + setContentLength(CONTENT_LENGTH_UNKNOWN); + send(code, content_type, emptyString); + } + void chunkedResponseFinalize () { + sendContent(emptyString); + } + static String credentialHash(const String& username, const String& realm, const String& password); static String urlDecode(const String& text); - // Handle a GET request by sending a response header and stream file content to response body + // Handle a GET request by sending a response header and stream file content to response body template size_t streamFile(T &file, const String& contentType) { return streamFile(file, contentType, HTTP_GET); } // Implement GET and HEAD requests for files. - // Stream body on HTTP_GET but not on HTTP_HEAD requests. + // Stream body on HTTP_GET but not on HTTP_HEAD requests. template size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) { size_t contentLength = 0; From fee13076e59711ec8c75b66cd7a45c2455d2d8d6 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 4 Mar 2020 22:17:42 +0100 Subject: [PATCH 2/3] expose hidden WebServer's chunked API --- .../examples/FSBrowser/FSBrowser.ino | 8 ++++++-- .../ESP8266WebServer/src/ESP8266WebServer.h | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index 645d46b137..5503cb001f 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -186,8 +186,12 @@ void handleFileList() { Dir dir = filesystem->openDir(path); path.clear(); - // use chunked response to avoid building a huge temporary string - server.chunkedResponseModeStart(200, "text/json"); + // use HTTP/1.1 Chunked response to avoid building a huge temporary string + if (!server.chunkedResponseModeStart(200, "text/json")) { + server.send(505, FPSTR("text/html"), FPSTR("HTTP1.1 required")); + return; + } + bool first = true; // use the same string for every line String output; diff --git a/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/libraries/ESP8266WebServer/src/ESP8266WebServer.h index b3e88a5029..9e999acadc 100644 --- a/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -149,17 +149,19 @@ class ESP8266WebServerTemplate void sendContent(const char *content) { sendContent_P(content); } void sendContent(const char *content, size_t size) { sendContent_P(content, size); } - bool chunkedResponseModeStart (int code, const char* content_type) { + bool chunkedResponseModeStart_P (int code, PGM_P content_type) { + if (_currentVersion == 0) + // no chunk mode in HTTP/1.0 + return false; setContentLength(CONTENT_LENGTH_UNKNOWN); - send(code, content_type, emptyString); + send_P(code, content_type, ""); + return true; } - bool chunkedResponseModeStart (int code, const String& content_type) { - setContentLength(CONTENT_LENGTH_UNKNOWN); - send(code, content_type, emptyString); + bool chunkedResponseModeStart (int code, const char* content_type) { + return chunkedResponseModeStart_P(code, content_type); } - bool chunkedResponseModeStart (int code, PGM_P content_type) { - setContentLength(CONTENT_LENGTH_UNKNOWN); - send(code, content_type, emptyString); + bool chunkedResponseModeStart (int code, const String& content_type) { + return chunkedResponseModeStart_P(code, content_type.c_str()); } void chunkedResponseFinalize () { sendContent(emptyString); From cc3e01cc180bb86687089af50b449671f34581d6 Mon Sep 17 00:00:00 2001 From: david gauchard Date: Wed, 4 Mar 2020 22:29:41 +0100 Subject: [PATCH 3/3] expose hidden WebServer's chunked API --- .../examples/FSBrowser/FSBrowser.ino | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino index 5503cb001f..bd25fad582 100644 --- a/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino +++ b/libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino @@ -192,20 +192,21 @@ void handleFileList() { return; } - bool first = true; // use the same string for every line String output; output.reserve(64); while (dir.next()) { - if (output.length()) - // send string from previous iteration - // as an HTTP chunk - server.sendContent(output); + if (output.length()) { + // send string from previous iteration + // as an HTTP chunk + server.sendContent(output); + output = ','; + } else { + output = '['; + } File entry = dir.openFile("r"); - output = first? '[': ','; - first = false; bool isDir = false; output += "{\"type\":\""; output += (isDir) ? "dir" : "file";