Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose webserver's chunk api #7134

Merged
merged 5 commits into from
Apr 7, 2020
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 22 additions & 5 deletions libraries/ESP8266WebServer/examples/FSBrowser/FSBrowser.ino
Original file line number Diff line number Diff line change
Expand Up @@ -186,12 +186,27 @@ void handleFileList() {
Dir dir = filesystem->openDir(path);
path.clear();

String output = "[";
// 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;
}

// use the same string for every line
String output;
output.reserve(64);
while (dir.next()) {
File entry = dir.openFile("r");
if (output != "[") {
output += ',';

if (output.length()) {
// send string from previous iteration
// as an HTTP chunk
server.sendContent(output);
output = ',';
} else {
output = '[';
}

File entry = dir.openFile("r");
bool isDir = false;
output += "{\"type\":\"";
output += (isDir) ? "dir" : "file";
Expand All @@ -205,8 +220,10 @@ void handleFileList() {
entry.close();
}

// send last string
output += "]";
server.send(200, "text/json", output);
server.sendContent(output);
server.chunkedResponseFinalize();
}

void setup(void) {
Expand Down
22 changes: 20 additions & 2 deletions libraries/ESP8266WebServer/src/ESP8266WebServer.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,18 +149,36 @@ class ESP8266WebServerTemplate
void sendContent(const char *content) { sendContent_P(content); }
void sendContent(const char *content, size_t size) { sendContent_P(content, size); }

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_P(code, content_type, "");
return true;
}
bool chunkedResponseModeStart (int code, const char* content_type) {
return chunkedResponseModeStart_P(code, content_type);
}
bool chunkedResponseModeStart (int code, const String& content_type) {
return chunkedResponseModeStart_P(code, content_type.c_str());
}
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<typename T>
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<typename T>
size_t streamFile(T &file, const String& contentType, HTTPMethod requestMethod) {
size_t contentLength = 0;
Expand Down