8000 Merge pull request #95 from Eloquence4/WebServerChunks · headcloudmonkey/esp32-snippets@aeaeddf · GitHub
[go: up one dir, main page]

Skip to content

Commit aeaeddf

Browse files
authored
Merge pull request nkolban#95 from Eloquence4/WebServerChunks
Add sending files by chunks support.
2 parents 36bb92c + a78c8cb commit aeaeddf

File tree

2 files changed

+71
-13
lines changed

2 files changed

+71
-13
lines changed

cpp_utils/WebServer.cpp

Lines changed: 62 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,13 @@ static void mongoose_event_handler_web_server(
139139
}
140140
ESP_LOGD(tag, "Event: %s [%d]", mongoose_eventToString(event).c_str(), mgConnection->sock);
141141
switch (event) {
142+
case MG_EV_SEND: {
143+
struct WebServerUserData *pWebServerUserData = (struct WebServerUserData *)mgConnection->user_data;
144+
WebServer *pWebServer = pWebServerUserData->pWebServer;
145+
pWebServer->continueConnection(mgConnection);
146+
break;
147+
}
148+
142149
case MG_EV_HTTP_REQUEST: {
143150
struct http_message *message = (struct http_message *) eventData;
144151
dumpHttpMessage(message);
@@ -315,9 +322,7 @@ void WebServer::addPathHandler(const std::string& method, const std::string& pat
315322
m_pathHandlers.push_back(PathHandler(method, pathExpr, handler));
316323
} // addPathHandler
317324

318-
void WebServer::addPathHandler(std::string&& method, const std::string& pathExpr,
319-
void (* handler)(WebServer::HTTPRequest* pHttpRequest,
320-
WebServer::HTTPResponse* pHttpResponse)) {
325+
void WebServer::addPathHandler(std::string&& method, const std::string& pathExpr, void (* handler)(WebServer::HTTPRequest* pHttpRequest, WebServer::HTTPResponse* pHttpResponse)) {
321326
m_pathHandlers.push_back(PathHandler(std::move(method), pathExpr, handler));
322327
} // addPathHandler
323328

@@ -482,6 +487,27 @@ void WebServer::HTTPResponse::sendData(const char* pData, size_t length) {
482487
sendData((uint8_t*) pData, length);
483488
} // sendData
484489

490+
void WebServer::HTTPResponse::sendChunkHead() {
491+
if(m_dataSent) {
492+
ESP_LOGE(tag, "HTTPResponse: Chunk headers already sent! Attempt to send again/more.");
493+
}
494+
m_dataSent = true;
495+
mg_send_head(m_nc, m_status, -1, m_headers.c_str());
496+
}
497+
498+
void WebServer::HTTPResponse::sendChunk(const char* pData, size_t length) {
499+
mg_send_http_chunk(m_nc, pData, length);
500+
} // sendChunkHead
501+
502+
void WebServer::HTTPResponse::closeConnection() {
503+
m_nc->flags |= MG_F_SEND_AND_CLOSE;
504+
}
505+
506+
507+
void WebServer::HTTPResponse::sendData(const char* pData, size_t length) {
508+
sendData((uint8_t*) pData, length);
509+
}
510+
485511
/**
486512
* @brief Set the headers to be sent in the HTTP response.
487513
* @param [in] headers The complete set of headers to send to the caller.
@@ -564,15 +590,20 @@ void WebServer::processRequest(struct mg_connection *mgConnection, struct http_m
564590
filePath += httpResponse.getRootPath();
565591
filePath.append(message->uri.p, message->uri.len);
566592
ESP_LOGD(tag, "Opening file: %s", filePath.c_str());
567-
FILE *file = fopen(filePath.c_str(), "rb");
593+
FILE* file = fopen(filePath.c_str(), "rb");
568594
if (file != nullptr) {
569-
fseek(file, 0L, SEEK_END);
570-
size_t length = ftell(file);
571-
fseek(file, 0L, SEEK_SET);
572-
uint8_t *pData = (uint8_t *)malloc(length);
573-
fread(pData, length, 1, file);
574-
fclose(file);
575-
httpResponse.sendData(pData, length);
595+
auto pData = (uint8_t*)malloc(MAX_CHUNK_LENGTH);
596+
size_t read = fread(pData, 1, MAX_CHUNK_LENGTH, file);
597+
598+
if(read >= MAX_CHUNK_LENGTH) {
599+
httpResponse.sendChunkHead();
600+
httpResponse.sendChunk((char*)pData, read);
601+
fclose(unfinishedConnection[mgConnection->sock]);
602+
unfinishedConnection[mgConnection->sock] = file;
603+
} else {
604+
fclose(file);
605+
httpResponse.sendData(pData, read);
606+
}
576607
free(pData);
577608
} else {
578609
// Handle unable to open file
@@ -581,6 +612,26 @@ void WebServer::processRequest(struct mg_connection *mgConnection, struct http_m
581612
}
582613
} // processRequest
583614

615+
void WebServer::continueConnection(struct mg_connection* mgConnection) {
616+
if(unfinishedConnection.count(mgConnection->sock) == 0) {
617+
return;
618+
}
619+
620+
HTTPResponse httpResponse = HTTPResponse(mgConnection);
621+
622+
FILE* file = unfinishedConnection[mgConnection->sock];
623+
auto pData = (char*) malloc(MAX_CHUNK_LENGTH);
624+
size_t length = fread(pData, MAX_CHUNK_LENGTH, 1, file);
625+
626+
httpResponse.sendChunk(pData, length);
627+
if(length < MAX_CHUNK_LENGTH) {
628+
fclose(file);
629+
httpResponse.closeConnection();
630+
unfinishedConnection.erase(mgConnection->sock);
631+
}
632+
free(pData);
633+
}
634+
584635

585636
/** 57A6
586637
* @brief Construct an instance of a PathHandler.

cpp_utils/WebServer.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
#include <regex>
1313
#include <map>
1414
#include "sdkconfig.h"
15+
1516
#ifdef CONFIG_MONGOOSE_PRESENT
1617
#include <mongoose.h>
1718

19+
#define MAX_CHUNK_LENGTH 4090 // 4 kilobytes
20+
1821
class WebServer;
1922

2023
/**
@@ -59,6 +62,9 @@ class WebServer {
5962
const std::string& getRootPath() const;
6063
void setRootPath(const std::string& path);
6164
void setRootPath(std::string&& path);
65+
void sendChunkHead();
66+
void sendChunk(const char* pData, size_t length);
67+
void closeConnection();
6268
private:
6369
struct mg_connection *m_nc;
6470
std::string m_rootPath;
@@ -90,8 +96,7 @@ class WebServer {
9096
*/
9197
class HTTPMultiPart {
9298
public:
93-
virtual ~HTTPMultiPart() {
94-
};
99+
virtual ~HTTPMultiPart() = default;
95100
virtual void begin(const std::string& varName, const std::string& fileName);
96101
virtual void end();
97102
virtual void data(const std::string& data);
@@ -191,11 +196,13 @@ class WebServer {
191196
void setWebSocketHandlerFactory(WebSocketHandlerFactory *pWebSocketHandlerFactory);
192197
void start(unsigned short port = 80);
193198
void processRequest(struct mg_connection *mgConnection, struct http_message *message);
199+
void continueConnection(struct mg_connection* mgConnection);
194200
HTTPMultiPartFactory *m_pMultiPartFactory;
195201
WebSocketHandlerFactory *m_pWebSocketHandlerFactory;
196202
private:
197203
std::string m_rootPath;
198204
std::vector<PathHandler> m_pathHandlers;
205+
std::map<sock_t, FILE*> unfinishedConnection;
199206
};
200207

201208
#endif // CONFIG_MONGOOSE_PRESENT

0 commit comments

Comments
 (0)
0