Skip to content

Commit 93448d7

Browse files
nathannaume-no-dev
andauthored
Handle large octet-stream (master branch) (#9440)
* Handle large octet-stream * Add exemple Upload Huge File * Remove unuse function printDirectory * Fix upload path * Simplify and generalize the body parsing. * Create .skip.esp32h2 --------- Co-authored-by: me-no-dev <[email protected]>
1 parent f7b4959 commit 93448d7

File tree

8 files changed

+157
-1
lines changed

8 files changed

+157
-1
lines changed

Diff for: libraries/WebServer/examples/UploadHugeFile/.skip.esp32h2

Whitespace-only changes.
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Upload Huge File To SD Over Http
2+
3+
This project is an example of an HTTP server designed to facilitate the transfer of large files using the PUT method, in accordance with RFC specifications.
4+
5+
### Example cURL Command
6+
7+
```bash
8+
curl -X PUT -T ./my-file.mp3 http://esp-ip/upload/my-file.mp3
9+
```
10+
11+
## Resources
12+
13+
- RFC HTTP/1.0 - Additional Request Methods - PUT : [Link](https://datatracker.ietf.org/doc/html/rfc1945#appendix-D.1.1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <WiFi.h>
2+
#include <WiFiClient.h>
3+
#include <WebServer.h>
4+
#include <uri/UriRegex.h>
5+
#include <SD.h>
6+
7+
const char* ssid = "**********";
8+
const char* password = "**********";
9+
10+
WebServer server(80);
11+
12+
File rawFile;
13+
void handleCreate() {
14+
server.send(200, "text/plain", "");
15+
}
16+
void handleCreateProcess() {
17+
String path = "/" + server.pathArg(0);
18+
HTTPRaw& raw = server.raw();
19+
if (raw.status == RAW_START) {
20+
if (SD.exists((char *)path.c_str())) {
21+
SD.remove((char *)path.c_str());
22+
}
23+
rawFile = SD.open(path.c_str(), FILE_WRITE);
24+
Serial.print("Upload: START, filename: ");
25+
Serial.println(path);
26+
} else if (raw.status == RAW_WRITE) {
27+
if (rawFile) {
28+
rawFile.write(raw.buf, raw.currentSize);
29+
}
30+
Serial.print("Upload: WRITE, Bytes: ");
31+
Serial.println(raw.currentSize);
32+
} else if (raw.status == RAW_END) {
33+
if (rawFile) {
34+
rawFile.close();
35+
}
36+
Serial.print("Upload: END, Size: ");
37+
Serial.println(raw.totalSize);
38+
}
39+
}
40+
41+
void returnFail(String msg) {
42+
server.send(500, "text/plain", msg + "\r\n");
43+
}
44+
45+
void handleNotFound() {
46+
String message = "File Not Found\n\n";
47+
message += "URI: ";
48+
message += server.uri();
49+
message += "\nMethod: ";
50+
message += (server.method() == HTTP_GET) ? "GET" : "POST";
51+
message += "\nArguments: ";
52+
message += server.args();
53+
message += "\n";
54+
for (uint8_t i = 0; i < server.args(); i++) {
55+
message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
56+
}
57+
server.send(404, "text/plain", message);
58+
}
59+
60+
void setup(void) {
61+
Serial.begin(115200);
62+
63+
while (!SD.begin()) delay(1);
64+
Serial.println("SD Card initialized.");
65+
66+
WiFi.mode(WIFI_STA);
67+
WiFi.begin(ssid, password);
68+
69+
while (WiFi.status() != WL_CONNECTED) {
70+
delay(500);
71+
Serial.print(".");
72+
}
73+
Serial.print("Connected to ");
74+
Serial.println(ssid);
75+
Serial.print("IP address: ");
76+
Serial.println(WiFi.localIP());
77+
78+
server.on(UriRegex("/upload/(.*)"), HTTP_PUT, handleCreate, handleCreateProcess);
79+
server.onNotFound(handleNotFound);
80+
server.begin();
81+
Serial.println("HTTP server started");
82+
83+
}
84+
85+
void loop(void) {
86+
server.handleClient();
87+
delay(2);//allow the cpu to switch to other tasks
88+
}

Diff for: libraries/WebServer/src/Parsing.cpp

+24-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,30 @@ bool WebServer::_parseRequest(NetworkClient& client) {
173173
}
174174
}
175175

176-
if (!isForm){
176+
if (!isForm && _currentHandler && _currentHandler->canRaw(_currentUri)){
177+
log_v("Parse raw");
178+
_currentRaw.reset(new HTTPRaw());
179+
_currentRaw->status = RAW_START;
180+
_currentRaw->totalSize = 0;
181+
_currentRaw->currentSize = 0;
182+
log_v("Start Raw");
183+
_currentHandler->raw(*this, _currentUri, *_currentRaw);
184+
_currentRaw->status = RAW_WRITE;
185+
186+
while (_currentRaw->totalSize < _clientContentLength) {
187+
_currentRaw->currentSize = client.readBytes(_currentRaw->buf, HTTP_RAW_BUFLEN);
188+
_currentRaw->totalSize += _currentRaw->currentSize;
189+
if (_currentRaw->currentSize == 0) {
190+
_currentRaw->status = RAW_ABORTED;
191+
_currentHandler->raw(*this, _currentUri, *_currentRaw);
192+
return false;
193+
}
194+
_currentHandler->raw(*this, _currentUri, *_currentRaw);
195+
}
196+
_currentRaw->status = RAW_END;
197+
_currentHandler->raw(*this, _currentUri, *_currentRaw);
198+
log_v("Finish Raw");
199+
} else if (!isForm) {
177200
size_t plainLength;
178201
char* plainBuf = readBytesWithTimeout(client, _clientContentLength, plainLength, HTTP_MAX_POST_WAIT);
179202
if (plainLength < _clientContentLength) {

Diff for: libraries/WebServer/src/WebServer.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ void WebServer::handleClient() {
438438
_currentClient = NetworkClient();
439439
_currentStatus = HC_NONE;
440440
_currentUpload.reset();
441+
_currentRaw.reset();
441442
}
442443

443444
if (callYield) {

Diff for: libraries/WebServer/src/WebServer.h

+16
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END,
3535
UPLOAD_FILE_ABORTED };
36+
enum HTTPRawStatus { RAW_START, RAW_WRITE, RAW_END, RAW_ABORTED };
3637
enum HTTPClientStatus { HC_NONE, HC_WAIT_READ, HC_WAIT_CLOSE };
3738
enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH, OTHER_AUTH };
3839

@@ -42,6 +43,10 @@ enum HTTPAuthMethod { BASIC_AUTH, DIGEST_AUTH, OTHER_AUTH };
4243
#define HTTP_UPLOAD_BUFLEN 1436
4344
#endif
4445

46+
#ifndef HTTP_RAW_BUFLEN
47+
#define HTTP_RAW_BUFLEN 1436
48+
#endif
49+
4550
#define HTTP_MAX_DATA_WAIT 5000 //ms to wait for the client to send the request
4651
#define HTTP_MAX_POST_WAIT 5000 //ms to wait for POST data to arrive
4752
#define HTTP_MAX_SEND_WAIT 5000 //ms to wait for data chunk to be ACKed
@@ -63,6 +68,15 @@ typedef struct {
6368
uint8_t buf[HTTP_UPLOAD_BUFLEN];
6469
} HTTPUpload;
6570

71+
typedef struct
72+
{
73+
HTTPRawStatus status;
74+
size_t totalSize; // content size
75+
size_t currentSize; // size of data currently in buf
76+
uint8_t buf[HTTP_UPLOAD_BUFLEN];
77+
void *data; // additional data
78+
} HTTPRaw;
79+
6680
#include "detail/RequestHandler.h"
6781

6882
namespace fs {
@@ -128,6 +142,7 @@ class WebServer
128142
HTTPMethod method() { return _currentMethod; }
129143
virtual NetworkClient & client() { return _currentClient; }
130144
HTTPUpload& upload() { return *_currentUpload; }
145+
HTTPRaw& raw() { return *_currentRaw; }
131146

132147
String pathArg(unsigned int i); // get request path argument by number
133148
String arg(String name); // get request argument value by name
@@ -232,6 +247,7 @@ class WebServer
232247
RequestArgument* _postArgs;
233248

234249
std::unique_ptr<HTTPUpload> _currentUpload;
250+
std::unique_ptr<HTTPRaw> _currentRaw;
235251

236252
int _headerKeysCount;
237253
RequestArgument* _currentHeaders;

Diff for: libraries/WebServer/src/detail/RequestHandler.h

+2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@ class RequestHandler {
99
virtual ~RequestHandler() { }
1010
virtual bool canHandle(HTTPMethod method, String uri) { (void) method; (void) uri; return false; }
1111
virtual bool canUpload(String uri) { (void) uri; return false; }
12+
virtual bool canRaw(String uri) { (void) uri; return false; }
1213
virtual bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) { (void) server; (void) requestMethod; (void) requestUri; return false; }
1314
virtual void upload(WebServer& server, String requestUri, HTTPUpload& upload) { (void) server; (void) requestUri; (void) upload; }
15+
virtual void raw(WebServer& server, String requestUri, HTTPRaw& raw) { (void) server; (void) requestUri; (void) raw; }
1416

1517
RequestHandler* next() { return _next; }
1618
void next(RequestHandler* r) { _next = r; }

Diff for: libraries/WebServer/src/detail/RequestHandlersImpl.h

+13
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,12 @@ class FunctionRequestHandler : public RequestHandler {
3838

3939
return true;
4040
}
41+
bool canRaw(String requestUri) override {
42+
if (!_ufn || _method == HTTP_GET)
43+
return false;
44+
45+
return true;
46+
}
4147

4248
bool handle(WebServer& server, HTTPMethod requestMethod, String requestUri) override {
4349
(void) server;
@@ -55,6 +61,13 @@ class FunctionRequestHandler : public RequestHandler {
5561
_ufn();
5662
}
5763

64+
void raw(WebServer& server, String requestUri, HTTPRaw& raw) override {
65+
(void)server;
66+
(void)raw;
67+
if (canRaw(requestUri))
68+
_ufn();
69+
}
70+
5871
protected:
5972
WebServer::THandlerFunction _fn;
6073
WebServer::THandlerFunction _ufn;

0 commit comments

Comments
 (0)