Home / References / ESP32 Library / WebServer Library
Description
The ESP32 WebServer
library includes robust features for handling HTTP file uploads. When a client sends a file through an HTML form (using the POST method with enctype="multipart/form-data"
– which is crucial for file uploads), the library automatically parses the incoming request.
Instead of loading the entire file into memory, the library processes the uploaded file in chunks. It provides access to information about the file (like name, type, size) and the data chunks as they arrive via a special HTTPUpload
structure. This streaming approach makes it possible to handle large file uploads efficiently, even on memory-constrained devices like the ESP32, by writing data directly to storage (like SPIFFS/LittleFS) or processing it on the fly.
The library typically uses a buffer of 1460 bytes for each chunk, optimized for ESP32’s network stack. File upload handling involves setting up specific request handlers that are triggered at different stages of the upload process: start, data chunks, completion, or abortion.
Syntax and Usage
File upload handling is configured when defining routes using the server.on()
method. The recommended approach utilizes a dedicated upload handler function that processes file data chunks.
– Registering an Upload Handler:
This syntax registers two functions for a specific URI (e.g., “/upload”) that expects a POST request containing file data. The first function (replyFn
) is called only after the entire upload process is finished (successfully or not). The second function (uploadFn
) is called repeatedly for each chunk of file data received.
// Registers handlers for POST requests on the specified URI
server.on(URI, HTTP_POST, replyFn, uploadFn);
Where:
URI
: The path that the HTML form posts to (e.g., “/upload”).HTTP_POST
: Specifies that this handler is for POST requests.replyFn
: A function (e.g.,void myReplyFunction()
) called once after the upload finishes to send a response to the client.uploadFn
: A function (e.g.,void myUploadFunction()
) called multiple times during the upload process (start, writing chunks, end, abort). This is where you process the file data.
– Upload Process Flow:
The upload handler (uploadFn
) follows a predictable sequence:
– Accessing Upload Information within the Upload Handler (`uploadFn`):
Inside the function designated as uploadFn
, you access details about the current state and data chunk of the upload using server.upload()
.
void myUploadFunction() {
// Get a reference to the upload details structure
HTTPUpload& upload = server.upload();
// Check the status and process accordingly
if (upload.status == UPLOAD_FILE_START) {
// Code to handle the start of a file upload
// e.g., open a file using upload.filename
Serial.printf("Upload Start: %s\n", upload.filename.c_str());
} else if (upload.status == UPLOAD_FILE_WRITE) {
// Code to handle a chunk of file data
// e.g., write upload.buf (containing upload.currentSize bytes) to the opened file
Serial.printf("Upload Write: %d bytes\n", upload.currentSize);
} else if (upload.status == UPLOAD_FILE_END) {
// Code to handle the end of a file upload
// e.g., close the file
Serial.printf("Upload End: %d bytes\n", upload.totalSize);
} else if (upload.status == UPLOAD_FILE_ABORTED) {
// Code to handle an aborted upload
Serial.println("Upload Aborted");
}
}
Argument(s) / Upload Information
While there isn’t a single “upload” method with arguments in the traditional sense, the core of file upload handling involves accessing information provided by the library through the HTTPUpload
structure obtained via server.upload()
within the dedicated upload handler function (uploadFn
). This structure contains the following key members:
status
: An enum indicating the current stage of the upload. Possible values include:UPLOAD_FILE_START
: First chunk of a new file is received.UPLOAD_FILE_WRITE
: A data chunk is being received.UPLOAD_FILE_END
: The file upload is complete.UPLOAD_FILE_ABORTED
: The upload was interrupted or failed.
filename
: (String) The original name of the file as sent by the client’s browser.name
: (String) The value of the ‘name’ attribute of the HTML<input type="file" name="...">
element used for the upload.type
: (String) The MIME type of the uploaded file (e.g., “image/jpeg”, “text/plain”, “application/pdf”).size
: (size_t) The total declared size of the file (from the request headers). May not always be available depending on the client.totalSize
: (size_t) The total number of bytes received for the file so far. Available primarily when `status == UPLOAD_FILE_END`.currentSize
: (size_t) The number of bytes in the current data chunk available in the buffer.buf
: (uint8_t*) A pointer to the buffer holding the current chunk of file data. You read `currentSize` bytes starting from this address. **Note:** This buffer is managed by the WebServer library and is reused; copy the data you need before the function returns.
Return Value
The relevant function here is server.upload()
, which is called inside the upload handler function (`uploadFn`).
server.upload()
: Returns a reference (HTTPUpload&
) to the internalHTTPUpload
structure containing the details and data buffer for the current upload chunk/status update.
The handler functions themselves (replyFn
and uploadFn
passed to server.on()
) are typically defined with a void
return type, as the library does not expect a return value from them.
Security and Best Practices
When implementing file upload functionality, consider these important security and reliability measures:
- File Type Validation: Check the
upload.type
MIME type and/or file extension to ensure only expected file types are accepted. - File Size Limits: Implement maximum file size checks using
upload.size
or by monitoringupload.totalSize
during the upload process. - Filename Sanitization: Clean uploaded filenames by removing or replacing potentially dangerous characters, and ensure proper path formatting.
- Storage Space Management: Check available SPIFFS/LittleFS space before accepting large uploads to prevent filesystem corruption.
- Error Handling: Implement robust error handling for file operations, including cleanup of partially uploaded files on abort.
- HTML Form Requirements: Ensure your HTML form uses
method="POST"
andenctype="multipart/form-data"
– both are essential for file uploads to work properly.
Example Codes
This example demonstrates how to set up an ESP32 web server that presents a form for uploading files. Uploaded files are saved to the ESP32’s SPIFFS filesystem. It uses the recommended approach with a dedicated upload handler function.
Explanation of the Code:
- Include necessary libraries:
WiFi.h
,WebServer.h
,FS.h
, andSPIFFS.h
. - Replace placeholder WiFi credentials with your network details.
- Initialize the Serial Monitor and connect to WiFi.
- Crucially, initialize and mount the SPIFFS filesystem using
SPIFFS.begin(true)
. The `true` argument formats SPIFFS if it’s not already mounted. - Create a
WebServer
instance on port 80. - Define
handleRoot
: This function sends an HTML page to the client containing a form. The form usesmethod="post"
,enctype="multipart/form-data"
, and specifiesaction="/upload"
. It includes an input of type “file” named “myFile”. - Define
handleUpload
: This is the upload handler (`uploadFn`). It gets called repeatedly during the upload:- On
UPLOAD_FILE_START
, it opens a file in SPIFFS with the name provided by the client (`upload.filename`). - On
UPLOAD_FILE_WRITE
, it writes the received data chunk (`upload.buf`) to the opened file. - On
UPLOAD_FILE_END
, it closes the file and prints a success message with the total size. - It also handles potential aborts.
- On
- Define
handleFileUploadFinished
: This is the reply handler (`replyFn`). It gets called once after the entire upload process (handled byhandleUpload
) completes. It sends a simple “Upload Successful” message back to the client’s browser. - In
setup()
, register the handlers:server.on("/", handleRoot)
for the main page andserver.on("/upload", HTTP_POST, handleFileUploadFinished, handleUpload)
for handling the file submission. - Start the server using
server.begin()
. - Call
server.handleClient()
continuously in theloop()
. - To run: Upload the sketch, open Serial Monitor (115200 baud). Access the ESP32’s IP address in your browser. Select a small file using the form and click “Upload”. Observe the progress messages in the Serial Monitor. After completion, you should see the success message in your browser. The file will be saved on the ESP32’s SPIFFS.
/*
* Author: Avant Maker
* Date: May 4, 2025
* Version: 1.0
* License: MIT
*
* Description:
* This example demonstrates how to use ESP32 WebServer Library's
* upload() method to set up an ESP32 web server that presents a
* form for uploading files. Uploaded files are saved to the ESP32's
* SPIFFS filesystem.
*
* Code Source:
* This example code is sourced from the Comprehensive Guide
* to the ESP32 Arduino Core Library, accessible on AvantMaker.com.
* For additional code examples and in-depth documentation related to
* the ESP32 Arduino Core Library, please visit:
*
* https://avantmaker.com/home/all-about-esp32-arduino-core-library/
*
* AvantMaker.com, your premier destination for all things
* DIY, AI, IoT, Smart Home, and STEM projects. We are dedicated
* to empowering makers, learners, and enthusiasts with
* the resources they need to bring their innovative ideas to life.
*/
#include <WiFi.h>
#include <WebServer.h>
#include <FS.h>
#include <SPIFFS.h>
// Replace with your network credentials
const char* ssid = "your_SSID"; // Replace with your Wi-Fi SSID
const char* password = "your_PASSWORD"; // Replace with your Wi-Fi password
// Create a WebServer object on port 80
WebServer server(80);
// File object to store the uploaded file
File fsUploadFile;
// HTML for the root page with upload form
const char* htmlHomePage =
"<!DOCTYPE html><html><head><title>ESP32 Upload</title></head><body>"
"<h1>ESP32 File Upload</h1>"
"<form method='POST' action='/upload' enctype='multipart/form-data'>"
"<input type='file' name='myFile'>"
"<input type='submit' value='Upload'>"
"</form>"
"</body></html>";
// Handler for the root page
void handleRoot() {
server.send(200, "text/html", htmlHomePage);
}
// Handler for the file upload process (called for chunks)
void handleUpload() {
HTTPUpload& upload = server.upload();
String filename;
if (upload.status == UPLOAD_FILE_START) {
filename = upload.filename;
if (!filename.startsWith("/")) {
filename = "/" + filename; // Prepend slash for SPIFFS path
}
Serial.print("handleUpload: START, filename: "); Serial.println(filename);
// Delete existing file if it exists (optional)
if (SPIFFS.exists(filename)) {
SPIFFS.remove(filename);
Serial.println("Existing file deleted.");
}
// Open file for writing
fsUploadFile = SPIFFS.open(filename, FILE_WRITE);
if (!fsUploadFile) {
Serial.println("Failed to open file for writing");
// Optionally send an error response here or handle in the reply function
return; // Abort further processing for this upload
}
} else if (upload.status == UPLOAD_FILE_WRITE) {
// Write the received chunk to the file
if (fsUploadFile) {
size_t bytesWritten = fsUploadFile.write(upload.buf, upload.currentSize);
if(bytesWritten != upload.currentSize){
Serial.println("Error writing chunk to file!");
// Handle error, maybe close file and set an error flag
}
Serial.print("handleUpload: WRITE, Bytes: "); Serial.println(upload.currentSize);
}
} else if (upload.status == UPLOAD_FILE_END) {
if (fsUploadFile) {
fsUploadFile.close();
Serial.print("handleUpload: END, Size: "); Serial.println(upload.totalSize);
} else {
Serial.println("handleUpload: END received but file not open.");
}
} else if (upload.status == UPLOAD_FILE_ABORTED) {
Serial.println("handleUpload: Upload Aborted");
if (fsUploadFile) {
fsUploadFile.close(); // Close the file
}
// Optionally delete the partially uploaded file if it exists
filename = upload.filename;
if (!filename.startsWith("/")) filename = "/" + filename;
if (SPIFFS.exists(filename)) {
SPIFFS.remove(filename);
Serial.println("Partial file deleted due to abort.");
}
}
}
// Handler called after the upload is finished
void handleFileUploadFinished() {
if (server.upload().status == UPLOAD_FILE_ABORTED) {
server.send(500, "text/plain", "Upload Aborted");
Serial.println("Reply sent: Upload Aborted");
} else if (server.upload().totalSize > 0) { // Check if any bytes were received
server.send(200, "text/plain", "Upload Successful!");
Serial.println("Reply sent: Upload Successful");
} else {
// This might happen if the file was empty or write failed early
server.send(500, "text/plain", "Upload Failed or Empty File");
Serial.println("Reply sent: Upload Failed/Empty");
}
}
void setup() {
Serial.begin(115200);
delay(100);
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
// Initialize SPIFFS
if (!SPIFFS.begin(true)) {
Serial.println("An Error has occurred while mounting SPIFFS");
return; // Stop execution if SPIFFS fails
}
Serial.println("SPIFFS mounted successfully.");
// List existing files (optional debug)
File root = SPIFFS.open("/");
File file = root.openNextFile();
Serial.println("Files on SPIFFS:");
while(file){
Serial.print(" FILE: "); Serial.println(file.name());
file = root.openNextFile();
}
Serial.println("------------------");
// Register Request Handlers
server.on("/", HTTP_GET, handleRoot); // Serve the upload form
// Set up the handler for the file upload endpoint
// - URI: /upload
// - Method: POST
// - Function to call after upload finishes: handleFileUploadFinished
// - Function to call for each data chunk: handleUpload
server.on("/upload", HTTP_POST, handleFileUploadFinished, handleUpload);
server.onNotFound([](){
server.send(404, "text/plain", "Not found");
});
// Start the server
server.begin();
Serial.println("HTTP server started");
}
void loop() {
server.handleClient(); // Handle client requests
delay(2); // Allow RTOS tasks to run
}
ESP32 Library Index
- ESP32 WiFi Library
- ESP32 WiFiClient Library
- ESP32 HTTPClient Library
- ESP32 WiFiClientSecure Library
- ESP32 WebServer Library
- Server Operation
- Client Hnadling
- Routing and Handlers
- Authentication
- Request Information
- Which ESP32 Boards are Recommended for Learners
- How to Copy Codes from AvantMaker.com
- What is SPIFFS and how to upload files to it?
- What is LIttleFS and how to upload files to it?
Ready to experiment and explore more about ESP32? Visit our website’s All About ESP32 Resources Hub, packed with tutorials, guides, and tools to inspire your maker journey. Experiment, explore, and elevate your skills with everything you need to master this powerful microcontroller platform!