Skip to content
This repository was archived by the owner on Jan 21, 2025. It is now read-only.

Commit f0402e5

Browse files
committed
Close #77: Allow modification of hardcoded headers
1 parent 504231c commit f0402e5

File tree

4 files changed

+61
-14
lines changed

4 files changed

+61
-14
lines changed

examples/SimpleServer/SimpleServer.ino

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,27 @@ void setup() {
6161
request->send(LittleFS, "/index.html");
6262
});
6363

64+
/*
65+
❯ curl -I -X HEAD http://192.168.4.1/download
66+
HTTP/1.1 200 OK
67+
Content-Length: 1024
68+
Content-Type: application/octet-stream
69+
Connection: close
70+
Accept-Ranges: bytes
71+
*/
72+
// Ref: https://github.com/mathieucarbou/ESPAsyncWebServer/pull/80
73+
server.on("/download", HTTP_HEAD | HTTP_GET, [](AsyncWebServerRequest* request) {
74+
if (request->method() == HTTP_HEAD) {
75+
AsyncWebServerResponse* response = request->beginResponse(200, "application/octet-stream");
76+
response->setContentLength(1024); // myFile.getSize()
77+
response->addHeader("Accept-Ranges", "bytes");
78+
// ...
79+
request->send(response);
80+
} else {
81+
// ...
82+
}
83+
});
84+
6485
// Send a GET request to <IP>/get?message=<message>
6586
server.on("/get", HTTP_GET, [](AsyncWebServerRequest* request) {
6687
String message;

src/ESPAsyncWebServer.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -581,8 +581,9 @@ class AsyncWebServerResponse {
581581
virtual void setContentLength(size_t len);
582582
void setContentType(const String& type) { setContentType(type.c_str()); }
583583
virtual void setContentType(const char* type);
584-
virtual void addHeader(const char* name, const char* value);
585-
void addHeader(const String& name, const String& value) { addHeader(name.c_str(), value.c_str()); }
584+
virtual bool addHeader(const char* name, const char* value, bool replaceExisting = true);
585+
bool addHeader(const String& name, const String& value, bool replaceExisting = true) { return addHeader(name.c_str(), value.c_str(), replaceExisting); }
586+
virtual bool removeHeader(const char* name);
586587
virtual String _assembleHead(uint8_t version);
587588
virtual bool _started() const;
588589
virtual bool _finished() const;

src/WebResponses.cpp

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -239,18 +239,43 @@ void AsyncWebServerResponse::setContentType(const char* type) {
239239
_contentType = type;
240240
}
241241

242-
void AsyncWebServerResponse::addHeader(const char* name, const char* value) {
242+
bool AsyncWebServerResponse::removeHeader(const char* name) {
243+
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
244+
if (i->name().equalsIgnoreCase(name)) {
245+
_headers.erase(i);
246+
return true;
247+
}
248+
}
249+
return false;
250+
}
251+
252+
bool AsyncWebServerResponse::addHeader(const char* name, const char* value, bool replaceExisting) {
253+
for (auto i = _headers.begin(); i != _headers.end(); ++i) {
254+
if (i->name().equalsIgnoreCase(name)) {
255+
// header already set
256+
if (replaceExisting) {
257+
// remove, break and add the new one
258+
_headers.erase(i);
259+
break;
260+
} else {
261+
// do not update
262+
return false;
263+
}
264+
}
265+
}
266+
// header was not found found, or existing one was removed
243267
_headers.emplace_back(name, value);
268+
return true;
244269
}
245270

246271
String AsyncWebServerResponse::_assembleHead(uint8_t version) {
247272
if (version) {
248-
addHeader(T_Accept_Ranges, T_none);
273+
addHeader(T_Accept_Ranges, T_none, false);
249274
if (_chunked)
250-
addHeader(Transfer_Encoding, T_chunked);
275+
addHeader(T_Transfer_Encoding, T_chunked, false);
251276
}
252277
String out;
253-
int bufSize = 300;
278+
constexpr size_t bufSize = 300;
254279
char buf[bufSize];
255280

256281
#ifndef ESP8266
@@ -307,7 +332,7 @@ AsyncBasicResponse::AsyncBasicResponse(int code, const char* contentType, const
307332
if (!_contentType.length())
308333
_contentType = T_text_plain;
309334
}
310-
addHeader(T_Connection, T_close);
335+
addHeader(T_Connection, T_close, false);
311336
}
312337

313338
void AsyncBasicResponse::_respond(AsyncWebServerRequest* request) {
@@ -385,7 +410,7 @@ AsyncAbstractResponse::AsyncAbstractResponse(AwsTemplateProcessor callback) : _c
385410
}
386411

387412
void AsyncAbstractResponse::_respond(AsyncWebServerRequest* request) {
388-
addHeader(T_Connection, T_close);
413+
addHeader(T_Connection, T_close, false);
389414
_head = _assembleHead(request->version());
390415
_state = RESPONSE_HEADERS;
391416
_ack(request, 0, 0);
@@ -663,7 +688,7 @@ AsyncFileResponse::AsyncFileResponse(FS& fs, const String& path, const char* con
663688

664689
if (!download && !fs.exists(_path) && fs.exists(_path + T__gz)) {
665690
_path = _path + T__gz;
666-
addHeader(T_Content_Encoding, T_gzip);
691+
addHeader(T_Content_Encoding, T_gzip, false);
667692
_callback = nullptr; // Unable to process zipped templates
668693
_sendContentLength = true;
669694
_chunked = false;
@@ -688,15 +713,15 @@ AsyncFileResponse::AsyncFileResponse(FS& fs, const String& path, const char* con
688713
// set filename and force rendering
689714
snprintf_P(buf, sizeof(buf), PSTR("inline"));
690715
}
691-
addHeader(T_Content_Disposition, buf);
716+
addHeader(T_Content_Disposition, buf, false);
692717
}
693718

694719
AsyncFileResponse::AsyncFileResponse(File content, const String& path, const char* contentType, bool download, AwsTemplateProcessor callback) : AsyncAbstractResponse(callback) {
695720
_code = 200;
696721
_path = path;
697722

698723
if (!download && String(content.name()).endsWith(T__gz) && !path.endsWith(T__gz)) {
699-
addHeader(T_Content_Encoding, T_gzip);
724+
addHeader(T_Content_Encoding, T_gzip, false);
700725
_callback = nullptr; // Unable to process gzipped templates
701726
_sendContentLength = true;
702727
_chunked = false;
@@ -719,7 +744,7 @@ AsyncFileResponse::AsyncFileResponse(File content, const String& path, const cha
719744
} else {
720745
snprintf_P(buf, sizeof(buf), PSTR("inline"));
721746
}
722-
addHeader(T_Content_Disposition, buf);
747+
addHeader(T_Content_Disposition, buf, false);
723748
}
724749

725750
size_t AsyncFileResponse::_fillBuffer(uint8_t* data, size_t len) {

src/literals.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ static constexpr const char* T_none = "none";
4141
static constexpr const char* T_UPGRADE = "Upgrade";
4242
static constexpr const char* T_WS = "websocket";
4343
static constexpr const char* T_WWW_AUTH = "WWW-Authenticate";
44-
static constexpr const char* Transfer_Encoding = "Transfer-Encoding";
44+
static constexpr const char* T_Transfer_Encoding = "Transfer-Encoding";
4545

4646
// HTTP Methods
4747
static constexpr const char* T_ANY = "ANY";
@@ -210,7 +210,7 @@ static const char T_none[] PROGMEM = "none";
210210
static const char T_UPGRADE[] PROGMEM = "Upgrade";
211211
static const char T_WS[] PROGMEM = "websocket";
212212
static const char T_WWW_AUTH[] PROGMEM = "WWW-Authenticate";
213-
static const char Transfer_Encoding[] PROGMEM = "Transfer-Encoding";
213+
static const char T_Transfer_Encoding[] PROGMEM = "Transfer-Encoding";
214214

215215
// HTTP Methods
216216
static const char T_ANY[] PROGMEM = "ANY";

0 commit comments

Comments
 (0)