Skip to content

Commit e1bd972

Browse files
authored
Merge pull request #413 from ESP32Async/requestmethod-typing
Review HTTP method enum definition to avoid collisions with plaforms ones
2 parents c515c2a + 8234c1c commit e1bd972

File tree

11 files changed

+422
-126
lines changed

11 files changed

+422
-126
lines changed

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)