|
45 | 45 | #error Platform not supported |
46 | 46 | #endif |
47 | 47 |
|
| 48 | +// HTTP method enum from the underlying http_parser library. |
| 49 | +// All supported TCP libraries (AsyncTCP, ESPAsyncTCP, RPAsyncTCP) are built on |
| 50 | +// http_parser, so http_method is available on all supported platforms. |
| 51 | +// Using the platform's enum avoids redefining HTTP_GET, HTTP_POST, etc. ourselves, |
| 52 | +// which eliminates name conflicts with other libraries (e.g., Arduino WebServer.h). |
| 53 | +#if __has_include(<http_parser.h>) |
| 54 | +# include <http_parser.h> |
| 55 | +#else |
| 56 | +// Fallback definition matching the llhttp/http_parser spec (used by all platforms). |
| 57 | +// This is provided only for toolchains that do not expose http_parser.h directly. |
| 58 | +typedef enum { |
| 59 | + HTTP_DELETE = 0, HTTP_GET = 1, HTTP_HEAD = 2, HTTP_POST = 3, HTTP_PUT = 4, |
| 60 | + HTTP_CONNECT = 5, HTTP_OPTIONS = 6, HTTP_TRACE = 7, HTTP_COPY = 8, HTTP_LOCK = 9, |
| 61 | + HTTP_MKCOL = 10, HTTP_MOVE = 11, HTTP_PROPFIND = 12, HTTP_PROPPATCH = 13, |
| 62 | + HTTP_SEARCH = 14, HTTP_UNLOCK = 15, HTTP_BIND = 16, HTTP_REBIND = 17, |
| 63 | + HTTP_UNBIND = 18, HTTP_ACL = 19, HTTP_REPORT = 20, HTTP_MKACTIVITY = 21, |
| 64 | + HTTP_CHECKOUT = 22, HTTP_MERGE = 23, HTTP_MSEARCH = 24, HTTP_NOTIFY = 25, |
| 65 | + HTTP_SUBSCRIBE = 26, HTTP_UNSUBSCRIBE = 27, HTTP_PATCH = 28, HTTP_PURGE = 29, |
| 66 | + HTTP_MKCALENDAR = 30, HTTP_LINK = 31, HTTP_UNLINK = 32, |
| 67 | +} http_method; |
| 68 | +#endif |
| 69 | + |
48 | 70 | #include "AsyncWebServerVersion.h" |
49 | 71 | #define ASYNCWEBSERVER_FORK_ESP32Async |
50 | 72 |
|
@@ -78,61 +100,94 @@ class AsyncCallbackWebHandler; |
78 | 100 | class AsyncResponseStream; |
79 | 101 | class AsyncMiddlewareChain; |
80 | 102 |
|
81 | | -// Namespace for web request method defines |
82 | | -namespace AsyncWebRequestMethod { |
83 | | -// The long name here is because we sometimes include this in the global namespace |
84 | | -enum AsyncWebRequestMethodType { |
85 | | - HTTP_GET = 0b0000000000000001, |
86 | | - HTTP_POST = 0b0000000000000010, |
87 | | - HTTP_DELETE = 0b0000000000000100, |
88 | | - HTTP_PUT = 0b0000000000001000, |
89 | | - HTTP_PATCH = 0b0000000000010000, |
90 | | - HTTP_HEAD = 0b0000000000100000, |
91 | | - HTTP_OPTIONS = 0b0000000001000000, |
92 | | - HTTP_PROPFIND = 0b0000000010000000, |
93 | | - HTTP_LOCK = 0b0000000100000000, |
94 | | - HTTP_UNLOCK = 0b0000001000000000, |
95 | | - HTTP_PROPPATCH = 0b0000010000000000, |
96 | | - HTTP_MKCOL = 0b0000100000000000, |
97 | | - HTTP_MOVE = 0b0001000000000000, |
98 | | - HTTP_COPY = 0b0010000000000000, |
99 | | - HTTP_RESERVED = 0b0100000000000000, |
100 | | - HTTP_ALL = 0b0111111111111111, |
101 | | -}; |
102 | | -}; // namespace AsyncWebRequestMethod |
| 103 | +// WebRequestMethod: a single HTTP request method, taken directly from the |
| 104 | +// platform's http_parser enum. HTTP_GET, HTTP_POST, HTTP_DELETE, HTTP_PUT, |
| 105 | +// HTTP_PATCH, HTTP_HEAD, HTTP_OPTIONS, HTTP_PROPFIND, HTTP_LOCK, HTTP_UNLOCK, |
| 106 | +// HTTP_PROPPATCH, HTTP_MKCOL, HTTP_MOVE, HTTP_COPY and many others are already |
| 107 | +// defined globally by <http_parser.h> above — no redefinition needed here. |
| 108 | +typedef http_method WebRequestMethod; |
| 109 | + |
| 110 | +// WebRequestMethodComposite: an ordered list of HTTP methods that a handler |
| 111 | +// accepts. An empty composite matches *any* method (HTTP_ANY / HTTP_ALL |
| 112 | +// semantics). Using a list avoids bitmask arithmetic on the platform enum's |
| 113 | +// non-power-of-two sequential values. |
| 114 | +class WebRequestMethodComposite { |
| 115 | +public: |
| 116 | + // Maximum number of methods that can be listed. In practice, handlers |
| 117 | + // accept at most a handful of methods; use the empty composite (HTTP_ALL) |
| 118 | + // when you want to match any method. |
| 119 | + static const uint8_t MAX_METHODS = 8; |
103 | 120 |
|
104 | | -typedef AsyncWebRequestMethod::AsyncWebRequestMethodType WebRequestMethod; |
105 | | -typedef uint16_t WebRequestMethodComposite; |
| 121 | + // Empty composite = match any method. |
| 122 | + WebRequestMethodComposite() : _count(0) {} |
106 | 123 |
|
107 | | -// Type-safe helper functions for composite methods |
108 | | -extern constexpr inline WebRequestMethodComposite operator|(WebRequestMethodComposite l, WebRequestMethod r) { |
109 | | - return l | static_cast<WebRequestMethodComposite>(r); |
110 | | -}; |
111 | | -extern constexpr inline WebRequestMethodComposite operator|(WebRequestMethod l, WebRequestMethod r) { |
112 | | - return static_cast<WebRequestMethodComposite>(l) | r; |
113 | | -}; |
| 124 | + // Single-method composite. Intentionally implicit so that a bare |
| 125 | + // WebRequestMethod (e.g. HTTP_GET) is accepted wherever a composite is |
| 126 | + // expected. |
| 127 | + WebRequestMethodComposite(WebRequestMethod m) : _count(1) { |
| 128 | + _methods[0] = m; |
| 129 | + } |
114 | 130 |
|
115 | | -// HTTP_ANY is commonly defined as a macro in Arduino core HTTP client libraries (e.g., ESP8266 HTTPClient.h). |
116 | | -// Macros are expanded by the preprocessor before C++ namespace resolution, so even a namespace-qualified |
117 | | -// reference like AsyncWebRequestMethod::HTTP_ANY would be incorrectly expanded to AsyncWebRequestMethod::0. |
118 | | -// To avoid this conflict, HTTP_ANY is provided here as a C++ constexpr (not a macro), after undefining |
119 | | -// any previously defined HTTP_ANY macro. Use HTTP_ALL as the canonical non-conflicting name. |
120 | | -// To suppress this behavior entirely (keeping any pre-existing HTTP_ANY macro and not providing the alias), |
121 | | -// define ASYNCWEBSERVER_NO_HTTP_ANY before including this header. |
122 | | -#if !defined(ASYNCWEBSERVER_NO_HTTP_ANY) |
123 | | -#ifdef HTTP_ANY |
124 | | -#warning \ |
125 | | - "HTTP_ANY macro is already defined and will be undefined to avoid conflicts with ESPAsyncWebServer. To suppress this and keep the original macro, define ASYNCWEBSERVER_NO_HTTP_ANY and use AsyncWebRequestMethod::HTTP_ALL instead." |
126 | | -#undef HTTP_ANY |
127 | | -#endif |
128 | | -namespace AsyncWebRequestMethod { |
129 | | -static constexpr AsyncWebRequestMethodType HTTP_ANY = HTTP_ALL; |
130 | | -} // namespace AsyncWebRequestMethod |
131 | | -#endif |
| 131 | + // Append a method; silently ignores the call once MAX_METHODS is reached. |
| 132 | + WebRequestMethodComposite &add(WebRequestMethod m) { |
| 133 | + if (_count < MAX_METHODS) { |
| 134 | + _methods[_count++] = m; |
| 135 | + } |
| 136 | + return *this; |
| 137 | + } |
| 138 | + |
| 139 | + // Returns true when this composite contains (or should match) the given |
| 140 | + // method. An empty composite matches any method. |
| 141 | + bool contains(WebRequestMethod m) const { |
| 142 | + if (_count == 0) return true; |
| 143 | + for (uint8_t i = 0; i < _count; i++) { |
| 144 | + if (_methods[i] == m) return true; |
| 145 | + } |
| 146 | + return false; |
| 147 | + } |
| 148 | + |
| 149 | + // Equality: true when the composite holds exactly this one method. |
| 150 | + bool operator==(WebRequestMethod m) const { |
| 151 | + return _count == 1 && _methods[0] == m; |
| 152 | + } |
| 153 | + bool operator!=(WebRequestMethod m) const { return !(*this == m); } |
| 154 | + |
| 155 | + // True when this is an empty (match-any) composite. |
| 156 | + bool empty() const { return _count == 0; } |
| 157 | + |
| 158 | +private: |
| 159 | + WebRequestMethod _methods[MAX_METHODS]; |
| 160 | + uint8_t _count; |
| 161 | +}; |
132 | 162 |
|
133 | | -#if !defined(ASYNCWEBSERVER_NO_GLOBAL_HTTP_METHODS) |
134 | | -// Import the method enum values to the global namespace |
135 | | -using namespace AsyncWebRequestMethod; |
| 163 | +// Build a composite from two individual methods: HTTP_GET | HTTP_POST |
| 164 | +inline WebRequestMethodComposite operator|(WebRequestMethod l, WebRequestMethod r) { |
| 165 | + WebRequestMethodComposite c; |
| 166 | + c.add(l).add(r); |
| 167 | + return c; |
| 168 | +} |
| 169 | + |
| 170 | +// Extend a composite with one more method: (HTTP_GET | HTTP_POST) | HTTP_PUT |
| 171 | +inline WebRequestMethodComposite operator|(WebRequestMethodComposite c, WebRequestMethod r) { |
| 172 | + c.add(r); |
| 173 | + return c; |
| 174 | +} |
| 175 | + |
| 176 | +// Membership test: returns true when composite c contains method m. |
| 177 | +// Usage: if (handler._method ^ request->method()) { /* matched */ } |
| 178 | +inline bool operator^(const WebRequestMethodComposite &c, WebRequestMethod m) { |
| 179 | + return c.contains(m); |
| 180 | +} |
| 181 | + |
| 182 | +// HTTP_ALL: empty composite — matches any HTTP method. |
| 183 | +// HTTP_ANY: backward-compatible alias for HTTP_ALL. |
| 184 | +// HTTP_ANY is only defined here when external headers have not already defined |
| 185 | +// it as a macro (e.g., Arduino core may define HTTP_ANY as an integer). When |
| 186 | +// an external macro is present the name remains an integer; user code should |
| 187 | +// migrate to HTTP_ALL which is always safe. |
| 188 | +#define HTTP_ALL WebRequestMethodComposite() |
| 189 | +#ifndef HTTP_ANY |
| 190 | +#define HTTP_ANY WebRequestMethodComposite() |
136 | 191 | #endif |
137 | 192 |
|
138 | 193 | #ifndef HAVE_FS_FILE_OPEN_MODE |
@@ -283,7 +338,7 @@ class AsyncWebServerRequest { |
283 | 338 | uint8_t _parseState; |
284 | 339 |
|
285 | 340 | uint8_t _version; |
286 | | - WebRequestMethodComposite _method; |
| 341 | + WebRequestMethod _method; |
287 | 342 | String _url; |
288 | 343 | String _host; |
289 | 344 | String _contentType; |
@@ -373,7 +428,7 @@ class AsyncWebServerRequest { |
373 | 428 | uint8_t version() const { |
374 | 429 | return _version; |
375 | 430 | } |
376 | | - WebRequestMethodComposite method() const { |
| 431 | + WebRequestMethod method() const { |
377 | 432 | return _method; |
378 | 433 | } |
379 | 434 | const String &url() const { |
@@ -401,10 +456,10 @@ class AsyncWebServerRequest { |
401 | 456 | bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED) |
402 | 457 | const; |
403 | 458 | bool isWebSocketUpgrade() const { |
404 | | - return _method == AsyncWebRequestMethod::HTTP_GET && isExpectedRequestedConnType(RCT_WS); |
| 459 | + return _method == HTTP_GET && isExpectedRequestedConnType(RCT_WS); |
405 | 460 | } |
406 | 461 | bool isSSE() const { |
407 | | - return _method == AsyncWebRequestMethod::HTTP_GET && isExpectedRequestedConnType(RCT_EVENT); |
| 462 | + return _method == HTTP_GET && isExpectedRequestedConnType(RCT_EVENT); |
408 | 463 | } |
409 | 464 | bool isHTTP() const { |
410 | 465 | return isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP); |
@@ -1574,7 +1629,7 @@ class AsyncWebServer : public AsyncMiddlewareChain { |
1574 | 1629 | bool removeHandler(AsyncWebHandler *handler); |
1575 | 1630 |
|
1576 | 1631 | AsyncCallbackWebHandler &on(AsyncURIMatcher uri, ArRequestHandlerFunction onRequest) { |
1577 | | - return on(std::move(uri), AsyncWebRequestMethod::HTTP_ALL, onRequest); |
| 1632 | + return on(std::move(uri), HTTP_ALL, onRequest); |
1578 | 1633 | } |
1579 | 1634 | AsyncCallbackWebHandler &on( |
1580 | 1635 | AsyncURIMatcher uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload = nullptr, |
|
0 commit comments