Skip to content

Commit 03a07e8

Browse files
committed
dox(examples): Added Upload example for text upload, binary upload and file upload
1 parent b8275a8 commit 03a07e8

File tree

2 files changed

+172
-0
lines changed

2 files changed

+172
-0
lines changed

examples/Upload/Upload.ino

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright 2016-2025 Hristo Gochkov, Mathieu Carbou, Emil Muratov
3+
4+
//
5+
// Demo text, binary and file upload
6+
//
7+
8+
#include <Arduino.h>
9+
#ifdef ESP32
10+
#include <AsyncTCP.h>
11+
#include <WiFi.h>
12+
#elif defined(ESP8266)
13+
#include <ESP8266WiFi.h>
14+
#include <ESPAsyncTCP.h>
15+
#elif defined(TARGET_RP2040)
16+
#include <WebServer.h>
17+
#include <WiFi.h>
18+
#endif
19+
20+
#include <ESPAsyncWebServer.h>
21+
#include <StreamString.h>
22+
#include <LittleFS.h>
23+
24+
static AsyncWebServer server(80);
25+
26+
void setup() {
27+
Serial.begin(115200);
28+
29+
if (!LittleFS.begin()) {
30+
LittleFS.format();
31+
LittleFS.begin();
32+
}
33+
34+
#ifndef CONFIG_IDF_TARGET_ESP32H2
35+
WiFi.mode(WIFI_AP);
36+
WiFi.softAP("esp-captive");
37+
#endif
38+
39+
// 1. Generate a Lorem_ipsum.txt file of about 20KB of text
40+
//
41+
// 3. Run: curl -v -F "data=@Lorem_ipsum.txt" http://192.168.4.1/upload/text
42+
//
43+
server.on(
44+
"/upload/text", HTTP_POST,
45+
[](AsyncWebServerRequest *request) {
46+
if (!request->_tempObject) {
47+
return request->send(400, "text/plain", "Nothing uploaded");
48+
}
49+
StreamString *buffer = reinterpret_cast<StreamString *>(request->_tempObject);
50+
Serial.printf("Text uploaded:\n%s\n", buffer->c_str());
51+
delete buffer;
52+
request->_tempObject = nullptr;
53+
request->send(200, "text/plain", "OK");
54+
},
55+
[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
56+
Serial.printf("Upload[%s]: start=%u, len=%u, final=%d\n", filename.c_str(), index, len, final);
57+
58+
if (!index) {
59+
// first pass
60+
StreamString *buffer = new StreamString();
61+
size_t size = std::max(4094l, request->header("Content-Length").toInt());
62+
Serial.printf("Allocating string buffer of %u bytes\n", size);
63+
if (!buffer->reserve(size)) {
64+
delete buffer;
65+
request->abort();
66+
}
67+
request->_tempObject = buffer;
68+
}
69+
70+
if (len) {
71+
reinterpret_cast<StreamString *>(request->_tempObject)->write(data, len);
72+
}
73+
}
74+
);
75+
76+
// 1. Generate a Lorem_ipsum.txt file of about 20KB of text
77+
//
78+
// 3. Run: curl -v -F "data=@Lorem_ipsum.txt" http://192.168.4.1/upload/file
79+
//
80+
server.on(
81+
"/upload/file", HTTP_POST,
82+
[](AsyncWebServerRequest *request) {
83+
if (request->getResponse()) {
84+
// 400 File not available for writing
85+
return;
86+
}
87+
88+
if (!LittleFS.exists("/my_file.txt")) {
89+
return request->send(400, "text/plain", "Nothing uploaded");
90+
}
91+
92+
// sends back the uploaded file
93+
request->send(LittleFS, "/my_file.txt", "text/plain");
94+
},
95+
[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
96+
Serial.printf("Upload[%s]: start=%u, len=%u, final=%d\n", filename.c_str(), index, len, final);
97+
98+
if (!index) {
99+
request->_tempFile = LittleFS.open("/my_file.txt", "w");
100+
101+
if (!request->_tempFile) {
102+
request->send(400, "text/plain", "File not available for writing");
103+
}
104+
}
105+
if (len) {
106+
request->_tempFile.write(data, len);
107+
}
108+
if (final) {
109+
request->_tempFile.close();
110+
}
111+
}
112+
);
113+
114+
//
115+
// Upload a binary file: curl -v -F "[email protected]" http://192.168.4.1/upload/binary
116+
//
117+
server.on(
118+
"/upload/binary", HTTP_POST,
119+
[](AsyncWebServerRequest *request) {
120+
// response already set ?
121+
if (request->getResponse()) {
122+
// 400 No Content-Length
123+
return;
124+
}
125+
126+
// nothing uploaded ?
127+
if (!request->_tempObject) {
128+
return request->send(400, "text/plain", "Nothing uploaded");
129+
}
130+
131+
uint8_t *buffer = reinterpret_cast<uint8_t *>(request->_tempObject);
132+
// process the buffer
133+
134+
delete buffer;
135+
request->_tempObject = nullptr;
136+
137+
request->send(200, "text/plain", "OK");
138+
},
139+
[](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
140+
Serial.printf("Upload[%s]: start=%u, len=%u, final=%d\n", filename.c_str(), index, len, final);
141+
142+
// first pass ?
143+
if (!index) {
144+
size_t size = request->header("Content-Length").toInt();
145+
if (!size) {
146+
request->send(400, "text/plain", "No Content-Length");
147+
} else {
148+
Serial.printf("Allocating buffer of %u bytes\n", size);
149+
uint8_t *buffer = new (std::nothrow) uint8_t[size];
150+
if (!buffer) {
151+
// not enough memory
152+
request->abort();
153+
} else {
154+
request->_tempObject = buffer;
155+
}
156+
}
157+
}
158+
159+
if (len) {
160+
memcpy(reinterpret_cast<uint8_t *>(request->_tempObject) + index, data, len);
161+
}
162+
}
163+
);
164+
165+
server.begin();
166+
}
167+
168+
// not needed
169+
void loop() {
170+
delay(100);
171+
}

platformio.ini

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ src_dir = examples/PerfTests
2828
; src_dir = examples/SlowChunkResponse
2929
; src_dir = examples/StaticFile
3030
; src_dir = examples/Templates
31+
; src_dir = examples/Upload
3132
; src_dir = examples/WebSocket
3233

3334
[env]

0 commit comments

Comments
 (0)