Skip to content

Commit 8234c1c

Browse files
committed
Review HTTP method enum definition to avoid collisions with plaforms ones
Formalize operations on WebServerRequestMethod - Requests can be only one method - String operations are free functions - Function for matching composites Handle collisions with other webservers Fix HTTP_ANY macro conflict with Arduino core. Rename the combination value to HTTP_ALL and make it type-safe as a WebRequestMethodComposite. Ensure a warning is generated when conflicts are detected, and add a deprecation alert to our compatibility HTTP_ANY value. Co-authored-by: GitHub Copilot <copilot@github.com> Co-authored-by: mathieucarbou <61346+mathieucarbou@users.noreply.github.com> Fix for #404 Fix name collision warning Added support for standard HTTP methods for WebDAC and REST APIs. Move global utility methods in asyncsrv namespace to avoid conflict with existing usr code Improving example to make sure the old way to match with a bit operator (&) works. Improve external HTTP method integration ci(pre-commit): Apply automatic fixes Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Updated examples to show teh difference between using Arduino Core include and ESP-IDf include
1 parent c515c2a commit 8234c1c

11 files changed

Lines changed: 422 additions & 126 deletions

File tree

docs/backup/wiki.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1887,7 +1887,7 @@ void setup(){
18871887
}, onUpload);
18881888

18891889
// send a file when /index is requested
1890-
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
1890+
server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){
18911891
request->send(SPIFFS, "/index.htm");
18921892
});
18931893

@@ -1974,10 +1974,10 @@ public :
19741974
19751975
void begin(){
19761976
// attach global request handler
1977-
classWebServer.on("/example", HTTP_ANY, handleRequest);
1977+
classWebServer.on("/example", HTTP_ALL, handleRequest);
19781978
19791979
// attach class request handler
1980-
classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
1980+
classWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
19811981
}
19821982
};
19831983
@@ -1986,10 +1986,10 @@ WebClass webClassInstance;
19861986
19871987
void setup() {
19881988
// attach global request handler
1989-
globalWebServer.on("/example", HTTP_ANY, handleRequest);
1989+
globalWebServer.on("/example", HTTP_ALL, handleRequest);
19901990
19911991
// attach class request handler
1992-
globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
1992+
globalWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
19931993
}
19941994
19951995
void loop() {

docs/setup.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,12 @@ void setup(){
7171
}, onUpload);
7272

7373
// send a file when /index is requested (SPIFFS example)
74-
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
74+
server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){
7575
request->send(SPIFFS, "/index.htm");
7676
});
7777

7878
// send a file when /index is requested (LittleFS example)
79-
server.on("/index", HTTP_ANY, [](AsyncWebServerRequest *request){
79+
server.on("/index", HTTP_ALL, [](AsyncWebServerRequest *request){
8080
request->send(LittleFS, "/index.htm");
8181
});
8282

@@ -161,10 +161,10 @@ public :
161161
162162
void begin(){
163163
// attach global request handler
164-
classWebServer.on("/example", HTTP_ANY, handleRequest);
164+
classWebServer.on("/example", HTTP_ALL, handleRequest);
165165
166166
// attach class request handler
167-
classWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
167+
classWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, this, std::placeholders::_1));
168168
}
169169
};
170170
@@ -173,10 +173,10 @@ WebClass webClassInstance;
173173
174174
void setup() {
175175
// attach global request handler
176-
globalWebServer.on("/example", HTTP_ANY, handleRequest);
176+
globalWebServer.on("/example", HTTP_ALL, handleRequest);
177177
178178
// attach class request handler
179-
globalWebServer.on("/example", HTTP_ANY, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
179+
globalWebServer.on("/example", HTTP_ALL, std::bind(&WebClass::classRequest, webClassInstance, std::placeholders::_1));
180180
}
181181
182182
void loop() {

examples/HTTPMethods/HTTPMethods.ino renamed to examples/HTTPMethodsWithArduino/HTTPMethodsWithArduino.ino

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
33

44
//
5-
// HTTP Method usage example and check compatibility with Arduino HTTP Methods
5+
// HTTP Method usage example and check compatibility with Arduino HTTP Methods when HTTP_Method.h is included.
6+
// ESP-IDf enums are imported, and HTTP_ANY is defined by Arduino Core.
7+
// In that case, we cannot use directly asyncws enums: we have to namespace them.
8+
// Also, asycnws HTTP_ANY is not available sine already defined by Arduino as a macro.
9+
// So we have to use AsyncWebRequestMethod::HTTP_ALL instead of HTTP_ANY in that case.
610
//
711

812
#include <Arduino.h>
913

1014
#if !defined(ESP8266)
11-
// simulate asyncws project being used with another library using Arduino HTTP Methods
1215
#include <HTTP_Method.h>
1316
#endif
1417

@@ -42,6 +45,31 @@ static void handlePostTest(AsyncWebServerRequest *req, JsonVariant &json) {
4245
}
4346
#endif
4447

48+
// user defined functions that turns out to have similar signatures to the ones in global header
49+
int stringToMethod(const String &) {
50+
return 0;
51+
}
52+
const char *methodToString(WebRequestMethod) {
53+
return "METHOD";
54+
}
55+
bool methodMatches(WebRequestMethodComposite c, WebRequestMethod m) {
56+
return false;
57+
};
58+
59+
static WebRequestMethodComposite allowed = AsyncWebRequestMethod::HTTP_HEAD | AsyncWebRequestMethod::HTTP_OPTIONS;
60+
61+
class MyRequestHandler : public AsyncWebHandler {
62+
public:
63+
bool canHandle(__unused AsyncWebServerRequest *request) const override {
64+
// Test backward compatibility with previous way of checking if a method is allowed in a composite using a bit operator
65+
return allowed & request->method();
66+
}
67+
68+
void handleRequest(AsyncWebServerRequest *request) override {
69+
request->send(200, "text/plain", "Hello from custom handler");
70+
}
71+
};
72+
4573
void setup() {
4674
Serial.begin(115200);
4775

@@ -56,8 +84,8 @@ void setup() {
5684
request->send(200, "text/plain", "Hello");
5785
});
5886

59-
// curl -v http://192.168.4.1/any
60-
server.on("/any", WebRequestMethod::HTTP_ANY, [](AsyncWebServerRequest *request) {
87+
// curl -v http://192.168.4.1/all
88+
server.on("/all", AsyncWebRequestMethod::HTTP_ALL, [](AsyncWebServerRequest *request) {
6189
request->send(200, "text/plain", "Hello");
6290
});
6391

@@ -68,6 +96,11 @@ void setup() {
6896
server.addHandler(testHandler);
6997
#endif
7098

99+
// curl -v -X HEAD http://192.168.4.1/custom => answers
100+
// curl -v -X OPTIONS http://192.168.4.1/custom => answers
101+
// curl -v -X POST http://192.168.4.1/custom => no answer
102+
server.addHandler(new MyRequestHandler());
103+
71104
server.begin();
72105
}
73106

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
3+
4+
//
5+
// HTTP Method usage example and check compatibility with ESP-IDF HTTP Methods when http_parser.h is included.
6+
// ESP-IDF enums are imported, and HTTP_ANY is NOT defined by ESP-IDF.
7+
// So asyncws is able to define it.
8+
// We cannot use directly other asyncws enums to avoid conflicts with ESP-IDF: we have to namespace them.
9+
//
10+
11+
#include <Arduino.h>
12+
13+
#if !defined(ESP8266)
14+
#include "http_parser.h"
15+
#endif
16+
17+
#if defined(ESP32) || defined(LIBRETINY)
18+
#include <AsyncTCP.h>
19+
#include <WiFi.h>
20+
#elif defined(ESP8266)
21+
#include <ESP8266WiFi.h>
22+
#include <ESPAsyncTCP.h>
23+
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
24+
#include <RPAsyncTCP.h>
25+
#include <WiFi.h>
26+
#endif
27+
28+
#include <ESPAsyncWebServer.h>
29+
30+
static AsyncWebServer server(80);
31+
32+
#if ASYNC_JSON_SUPPORT == 1
33+
// https://github.com/ESP32Async/ESPAsyncWebServer/issues/404
34+
static void handlePostTest(AsyncWebServerRequest *req, JsonVariant &json) {
35+
AsyncWebServerResponse *response;
36+
if (req->method() == WebRequestMethod::HTTP_POST) {
37+
response = req->beginResponse(200, "application/json", "{\"msg\": \"OK\"}");
38+
} else {
39+
response = req->beginResponse(501, "application/json", "{\"msg\": \"Not Implemented\"}");
40+
}
41+
req->send(response);
42+
}
43+
#endif
44+
45+
// user defined functions that turns out to have similar signatures to the ones in global header
46+
int stringToMethod(const String &) {
47+
return 0;
48+
}
49+
const char *methodToString(WebRequestMethod) {
50+
return "METHOD";
51+
}
52+
bool methodMatches(WebRequestMethodComposite c, WebRequestMethod m) {
53+
return false;
54+
};
55+
56+
static WebRequestMethodComposite allowed = AsyncWebRequestMethod::HTTP_HEAD | AsyncWebRequestMethod::HTTP_OPTIONS;
57+
58+
class MyRequestHandler : public AsyncWebHandler {
59+
public:
60+
bool canHandle(__unused AsyncWebServerRequest *request) const override {
61+
// Test backward compatibility with previous way of checking if a method is allowed in a composite using a bit operator
62+
return allowed & request->method();
63+
}
64+
65+
void handleRequest(AsyncWebServerRequest *request) override {
66+
request->send(200, "text/plain", "Hello from custom handler");
67+
}
68+
};
69+
70+
void setup() {
71+
Serial.begin(115200);
72+
73+
#if ASYNCWEBSERVER_WIFI_SUPPORTED
74+
WiFi.mode(WIFI_AP);
75+
WiFi.softAP("esp-captive");
76+
#endif
77+
78+
// curl -v http://192.168.4.1/get-or-post
79+
// curl -v -X POST -d "a=b" http://192.168.4.1/get-or-post
80+
server.on("/get-or-post", AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST, [](AsyncWebServerRequest *request) {
81+
request->send(200, "text/plain", "Hello");
82+
});
83+
84+
// curl -v http://192.168.4.1/all
85+
server.on("/all", AsyncWebRequestMethod::HTTP_ALL, [](AsyncWebServerRequest *request) {
86+
request->send(200, "text/plain", "Hello");
87+
});
88+
89+
// will show a deprecation warning
90+
server.on("/any", AsyncWebRequestMethod::HTTP_ANY, [](AsyncWebServerRequest *request) {
91+
request->send(200, "text/plain", "Hello");
92+
});
93+
94+
#if ASYNC_JSON_SUPPORT == 1
95+
// curl -v http://192.168.4.1/test => Not Implemented
96+
// curl -v -X POST -H 'Content-Type: application/json' -d '{"name":"You"}' http://192.168.4.1/test => OK
97+
AsyncCallbackJsonWebHandler *testHandler = new AsyncCallbackJsonWebHandler("/test", handlePostTest);
98+
server.addHandler(testHandler);
99+
#endif
100+
101+
// curl -v -X HEAD http://192.168.4.1/custom => answers
102+
// curl -v -X OPTIONS http://192.168.4.1/custom => answers
103+
// curl -v -X POST http://192.168.4.1/custom => no answer
104+
server.addHandler(new MyRequestHandler());
105+
106+
server.begin();
107+
}
108+
109+
// not needed
110+
void loop() {
111+
delay(100);
112+
}

platformio.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@ lib_dir = .
1515
; src_dir = examples/FlashResponse
1616
; src_dir = examples/HeaderManipulation
1717
; src_dir = examples/Headers
18-
; src_dir = examples/HTTPMethods
18+
; src_dir = examples/HTTPMethodsWithArduino
19+
; src_dir = examples/HTTPMethodsWithESPIDF
1920
; src_dir = examples/Json
2021
; src_dir = examples/LargeResponse
2122
; src_dir = examples/Logging

src/AsyncJson.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,8 @@ size_t AsyncMessagePackResponse::_fillBuffer(uint8_t *data, size_t len) {
112112
#endif
113113

114114
// Body handler supporting both content types: JSON and MessagePack
115+
constexpr static WebRequestMethodComposite JsonHandlerMethods =
116+
AsyncWebRequestMethod::HTTP_GET | AsyncWebRequestMethod::HTTP_POST | AsyncWebRequestMethod::HTTP_PUT | AsyncWebRequestMethod::HTTP_PATCH;
115117

116118
#if ARDUINOJSON_VERSION_MAJOR == 6
117119
AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(AsyncURIMatcher uri, ArJsonRequestHandlerFunction onRequest, size_t maxJsonBufferSize)
@@ -126,7 +128,7 @@ AsyncCallbackJsonWebHandler::AsyncCallbackJsonWebHandler(AsyncURIMatcher uri, Ar
126128
#endif
127129

128130
bool AsyncCallbackJsonWebHandler::canHandle(AsyncWebServerRequest *request) const {
129-
if (!_onRequest || !request->isHTTP() || !(_method & request->method())) {
131+
if (!_onRequest || !request->isHTTP() || !_method.matches(request->method())) {
130132
return false;
131133
}
132134

0 commit comments

Comments
 (0)