Subversion Repositories ESP8266_P1_Meter

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 raymond 1
// SPDX-License-Identifier: LGPL-3.0-or-later
2
// Copyright 2016-2026 Hristo Gochkov, Mathieu Carbou, Emil Muratov, Will Miles
3
 
4
#pragma once
5
 
6
#include <Arduino.h>
7
#include <FS.h>
8
 
9
#if !defined(HOST) || __has_include(<lwip/tcpbase.h>)
10
#include <lwip/tcpbase.h>
11
#endif
12
 
13
#include <algorithm>
14
#include <deque>
15
#include <functional>
16
#include <list>
17
#include <memory>
18
#include <tuple>
19
#include <unordered_map>
20
#include <utility>
21
#include <vector>
22
 
23
#define __asyncws_unused __attribute__((unused))
24
 
25
#if __has_include("ArduinoJson.h")
26
#include <ArduinoJson.h>
27
 
28
#if ARDUINOJSON_VERSION_MAJOR >= 5
29
#define ASYNC_JSON_SUPPORT 1
30
#else
31
#define ASYNC_JSON_SUPPORT 0
32
#endif  // ARDUINOJSON_VERSION_MAJOR >= 5
33
 
34
#if ARDUINOJSON_VERSION_MAJOR >= 6
35
#define ASYNC_MSG_PACK_SUPPORT 1
36
#else
37
#define ASYNC_MSG_PACK_SUPPORT 0
38
#endif  // ARDUINOJSON_VERSION_MAJOR >= 6
39
 
40
#endif  // __has_include("ArduinoJson.h")
41
 
42
#if defined(ESP32) || defined(LIBRETINY) || defined(HOST)
43
#include <AsyncTCP.h>
44
#include <assert.h>
45
#elif defined(ESP8266)
46
#include <ESPAsyncTCP.h>
47
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
48
#include <RPAsyncTCP.h>
49
#else
50
#error Platform not supported
51
#endif
52
 
53
#if !defined(ASYNCWEBSERVER_USE_MUTEX)
54
#if defined(ESP32) || defined(HOST)
55
#define ASYNCWEBSERVER_USE_MUTEX 1
56
#else
57
#define ASYNCWEBSERVER_USE_MUTEX 0
58
#endif
59
#endif
60
 
61
#include "AsyncWebServerVersion.h"
62
#define ASYNCWEBSERVER_FORK_ESP32Async
63
 
64
#ifdef ASYNCWEBSERVER_REGEX
65
#include <regex>
66
#endif
67
 
68
#include "./literals.h"
69
 
70
// See https://github.com/ESP32Async/ESPAsyncWebServer/commit/3d3456e9e81502a477f6498c44d0691499dda8f9#diff-646b25b11691c11dce25529e3abce843f0ba4bd07ab75ec9eee7e72b06dbf13fR388-R392
71
// This setting slowdown chunk serving but avoids crashing or deadlocks in the case where slow chunk responses are created, like file serving form SD Card
72
#ifndef ASYNCWEBSERVER_USE_CHUNK_INFLIGHT
73
#define ASYNCWEBSERVER_USE_CHUNK_INFLIGHT 1
74
#endif
75
 
76
#if SOC_WIFI_SUPPORTED || CONFIG_ESP_WIFI_REMOTE_ENABLED || LT_ARD_HAS_WIFI || CONFIG_ESP32_WIFI_ENABLED || defined(ESP8266)
77
#define ASYNCWEBSERVER_WIFI_SUPPORTED 1
78
#else
79
#define ASYNCWEBSERVER_WIFI_SUPPORTED 0
80
#endif
81
 
82
// Enable integration with other HTTP libraries
83
#if defined(HTTP_ANY) || defined(http_parser_h)
84
#define ASYNCWEBSERVER_HTTP_METHOD_INTEGRATION
85
#define ASYNCWEBSERVER_NO_GLOBAL_HTTP_METHODS
86
#endif
87
 
88
class AsyncWebServer;
89
class AsyncWebServerRequest;
90
class AsyncWebServerResponse;
91
class AsyncWebHeader;
92
class AsyncWebParameter;
93
class AsyncWebRewrite;
94
class AsyncWebHandler;
95
class AsyncStaticWebHandler;
96
class AsyncCallbackWebHandler;
97
class AsyncResponseStream;
98
class AsyncMiddlewareChain;
99
 
100
// Namespace for web request method defines
101
namespace AsyncWebRequestMethod {
102
// The long name here is because we sometimes include this in the global namespace
103
enum AsyncWebRequestMethodType : uint32_t {
104
  HTTP_UNKNOWN = 0u,
105
 
106
  HTTP_DELETE = 1u << 0,
107
  HTTP_GET = 1u << 1,
108
  HTTP_HEAD = 1u << 2,
109
  HTTP_POST = 1u << 3,
110
  HTTP_PUT = 1u << 4,
111
 
112
  /* pathological */
113
  HTTP_CONNECT = 1u << 5,
114
  HTTP_OPTIONS = 1u << 6,
115
  HTTP_TRACE = 1u << 7,
116
 
117
  /* WebDAV */
118
  HTTP_COPY = 1u << 8,
119
  HTTP_LOCK = 1u << 9,
120
  HTTP_MKCOL = 1u << 10,
121
  HTTP_MOVE = 1u << 11,
122
  HTTP_PROPFIND = 1u << 12,
123
  HTTP_PROPPATCH = 1u << 13,
124
  HTTP_SEARCH = 1u << 14,
125
  HTTP_UNLOCK = 1u << 15,
126
  HTTP_BIND = 1u << 16,
127
  HTTP_REBIND = 1u << 17,
128
  HTTP_UNBIND = 1u << 18,
129
  HTTP_ACL = 1u << 19,
130
 
131
  /* subversion */
132
  // HTTP_REPORT
133
  // HTTP_MKACTIVITY
134
  // HTTP_CHECKOUT
135
  // HTTP_MERGE
136
 
137
  /* upnp */
138
  // HTTP_MSEARCH
139
  // HTTP_NOTIFY
140
  // HTTP_SUBSCRIBE
141
  // HTTP_UNSUBSCRIBE
142
 
143
  /* RFC-5789 */
144
  HTTP_PATCH = 1u << 20,
145
  HTTP_PURGE = 1u << 21,
146
 
147
  /* CalDAV */
148
  // HTTP_MKCALENDAR
149
 
150
  /* RFC-2068, section 19.6.1.2 */
151
  HTTP_LINK = 1u << 22,
152
  HTTP_UNLINK = 1u << 23,
153
 
154
  /* icecast */
155
  // HTTP_SOURCE
156
 
157
  HTTP_INVALID = 1u << 31  // Sentinel
158
};
159
 
160
};  // namespace AsyncWebRequestMethod
161
 
162
typedef AsyncWebRequestMethod::AsyncWebRequestMethodType WebRequestMethod;
163
class WebRequestMethodComposite {
164
  uint32_t mask;
165
 
166
private:
167
  constexpr WebRequestMethodComposite(uint32_t m) : mask(m){};
168
 
169
public:
170
  // Default constructor: by default, matches nothing
171
  constexpr WebRequestMethodComposite() : mask(0){};
172
 
173
  // Constructor: allows implicit conversion from WebRequestMethod
174
  constexpr WebRequestMethodComposite(WebRequestMethod m) : mask(static_cast<uint32_t>(m)){};
175
 
176
  // Combine composites
177
  constexpr inline WebRequestMethodComposite operator|(const WebRequestMethodComposite &r) const {
178
    return WebRequestMethodComposite(mask | r.mask);
179
  };
180
 
181
  // == operator for composite
182
  constexpr inline bool operator==(const WebRequestMethodComposite &r) const {
183
    return mask == r.mask;
184
  };
185
 
186
  constexpr inline bool operator!=(const WebRequestMethodComposite &r) const {
187
    return mask != r.mask;
188
  };
189
 
190
  // Check for a match
191
  constexpr inline bool matches(WebRequestMethod m) const {
192
    return mask & static_cast<uint32_t>(m);
193
  };
194
 
195
  constexpr inline bool operator&(WebRequestMethod m) const {
196
    return matches(m);
197
  }
198
 
199
  // Super cool feature: integration with platform `http_method` enum
200
#ifdef ASYNCWEBSERVER_HTTP_METHOD_INTEGRATION
201
 
202
// Conversion function for integration with external libraries.
203
// Horrible ternary implementation for C++11 compatibility.
204
#define MAP_EXTERNAL_TERNARY(x) (t == http_method::x) ? static_cast<uint32_t>(WebRequestMethod::x)
205
  constexpr static inline uint32_t map_http_method(http_method t) {
206
    return MAP_EXTERNAL_TERNARY(HTTP_DELETE)
207
      : MAP_EXTERNAL_TERNARY(HTTP_GET)
208
      : MAP_EXTERNAL_TERNARY(HTTP_HEAD)
209
      : MAP_EXTERNAL_TERNARY(HTTP_POST)
210
      : MAP_EXTERNAL_TERNARY(HTTP_PUT)
211
      : MAP_EXTERNAL_TERNARY(HTTP_CONNECT)
212
      : MAP_EXTERNAL_TERNARY(HTTP_OPTIONS)
213
      : MAP_EXTERNAL_TERNARY(HTTP_TRACE)
214
      : MAP_EXTERNAL_TERNARY(HTTP_COPY)
215
      : MAP_EXTERNAL_TERNARY(HTTP_LOCK)
216
      : MAP_EXTERNAL_TERNARY(HTTP_MKCOL)
217
      : MAP_EXTERNAL_TERNARY(HTTP_MOVE)
218
      : MAP_EXTERNAL_TERNARY(HTTP_PROPFIND)
219
      : MAP_EXTERNAL_TERNARY(HTTP_PROPPATCH)
220
      : MAP_EXTERNAL_TERNARY(HTTP_SEARCH)
221
      : MAP_EXTERNAL_TERNARY(HTTP_UNLOCK)
222
      : MAP_EXTERNAL_TERNARY(HTTP_BIND)
223
      : MAP_EXTERNAL_TERNARY(HTTP_REBIND)
224
      : MAP_EXTERNAL_TERNARY(HTTP_UNBIND)
225
      : MAP_EXTERNAL_TERNARY(HTTP_ACL)
226
      : MAP_EXTERNAL_TERNARY(HTTP_PATCH)
227
      : MAP_EXTERNAL_TERNARY(HTTP_PURGE)
228
      : MAP_EXTERNAL_TERNARY(HTTP_LINK)
229
      : MAP_EXTERNAL_TERNARY(HTTP_UNLINK)
230
#if defined(HTTP_ANY)
231
      : (t == HTTP_ANY) ? static_cast<uint32_t>(WebRequestMethod::HTTP_INVALID) - 1
232
#endif
233
                        : static_cast<uint32_t>(WebRequestMethod::HTTP_INVALID);
234
  }
235
#undef MAP_EXTERNAL_TERNARY
236
 
237
  constexpr WebRequestMethodComposite(http_method m) : mask(map_http_method(m)){};
238
#endif
239
};  // WebRequestMethodComposite
240
 
241
// Operator| for WebRequestMethod: combine to a WebRequestMethodComposite
242
constexpr inline WebRequestMethodComposite operator|(WebRequestMethod l, WebRequestMethod r) {
243
  return static_cast<WebRequestMethodComposite>(l) | r;
244
};
245
 
246
namespace AsyncWebRequestMethod {
247
constexpr WebRequestMethodComposite HTTP_ALL = static_cast<WebRequestMethod>(static_cast<uint32_t>(HTTP_INVALID) - 1);
248
 
249
// Support HTTP_ANY if we can
250
#ifndef HTTP_ANY
251
constexpr WebRequestMethodComposite HTTP_ANY = HTTP_ALL;
252
#endif
253
}  // namespace AsyncWebRequestMethod
254
 
255
// WebRequestMethod string conversion functions
256
#if ASYNCWEBSERVER_USE_MUTEX
257
#include <mutex>
258
#endif
259
 
260
namespace asyncsrv {
261
#if ASYNCWEBSERVER_USE_MUTEX
262
typedef std::recursive_mutex mutex_type;
263
typedef std::lock_guard<mutex_type> lock_guard_type;
264
typedef std::unique_lock<mutex_type> unique_lock_type;
265
#else
266
// Do-nothing locks that will evaporate under optimization
267
class null_mutex {
268
public:
269
  void lock() {}
270
  void unlock() {}
271
  bool try_lock() {
272
    return true;
273
  };
274
};
275
typedef null_mutex mutex_type;
276
 
277
class lock_guard_type {
278
public:
279
  lock_guard_type(mutex_type &){};
280
};
281
class unique_lock_type {
282
public:
283
  unique_lock_type(mutex_type &){};
284
  void unlock() {};
285
};
286
#endif
287
 
288
WebRequestMethod stringToMethod(const String &);
289
const char *methodToString(WebRequestMethod);
290
}  // namespace asyncsrv
291
 
292
#if !defined(ASYNCWEBSERVER_NO_GLOBAL_HTTP_METHODS)
293
// Import the method enum values to the global namespace
294
using namespace AsyncWebRequestMethod;
295
#endif
296
 
297
#ifndef HAVE_FS_FILE_OPEN_MODE
298
namespace fs {
299
class FileOpenMode {
300
public:
301
  static const char *read;
302
  static const char *write;
303
  static const char *append;
304
};
305
};  // namespace fs
306
#else
307
#include "FileOpenMode.h"
308
#endif
309
 
310
// if this value is returned when asked for data, packet will not be sent and you will be asked for data again
311
#define RESPONSE_TRY_AGAIN          0xFFFFFFFF
312
#define RESPONSE_STREAM_BUFFER_SIZE 1460
313
 
314
typedef std::function<void(void)> ArDisconnectHandler;
315
 
316
/*
317
 * PARAMETER :: Chainable object to hold GET/POST and FILE parameters
318
 * */
319
 
320
class AsyncWebParameter {
321
private:
322
  String _name;
323
  String _value;
324
  size_t _size;
325
  bool _isForm;
326
  bool _isFile;
327
 
328
public:
329
  AsyncWebParameter(const String &name, const String &value, bool form = false, bool file = false, size_t size = 0)
330
    : _name(name), _value(value), _size(size), _isForm(form), _isFile(file) {}
331
  const String &name() const {
332
    return _name;
333
  }
334
  const String &value() const {
335
    return _value;
336
  }
337
  size_t size() const {
338
    return _size;
339
  }
340
  bool isPost() const {
341
    return _isForm;
342
  }
343
  bool isFile() const {
344
    return _isFile;
345
  }
346
};
347
 
348
/*
349
 * HEADER :: Chainable object to hold the headers
350
 * */
351
 
352
class AsyncWebHeader {
353
private:
354
  String _name;
355
  String _value;
356
 
357
public:
358
  AsyncWebHeader() {}
359
  AsyncWebHeader(const AsyncWebHeader &) = default;
360
  AsyncWebHeader(AsyncWebHeader &&) = default;
361
  AsyncWebHeader(const char *name, const char *value) : _name(name), _value(value) {}
362
  AsyncWebHeader(const String &name, const String &value) : _name(name), _value(value) {}
363
 
364
#ifndef ESP8266
365
  [[deprecated("Use AsyncWebHeader::parse(data) instead")]]
366
#endif
367
  AsyncWebHeader(const String &data)
368
    : AsyncWebHeader(parse(data)){};
369
 
370
  AsyncWebHeader &operator=(const AsyncWebHeader &) = default;
371
  AsyncWebHeader &operator=(AsyncWebHeader &&other) = default;
372
 
373
  const String &name() const {
374
    return _name;
375
  }
376
  const String &value() const {
377
    return _value;
378
  }
379
 
380
  String toString() const;
381
 
382
  // returns true if the header is valid
383
  operator bool() const {
384
    return _name.length();
385
  }
386
 
387
  static const AsyncWebHeader parse(const String &data) {
388
    return parse(data.c_str());
389
  }
390
  static const AsyncWebHeader parse(const char *data);
391
};
392
 
393
/*
394
 * REQUEST :: Each incoming Client is wrapped inside a Request and both live together until disconnect
395
 * */
396
 
397
typedef enum {
398
  RCT_NOT_USED = -1,
399
  RCT_DEFAULT = 0,
400
  RCT_HTTP,
401
  RCT_WS,
402
  RCT_EVENT,
403
  RCT_MAX
404
} RequestedConnectionType;
405
 
406
// this enum is similar to Arduino WebServer's AsyncAuthType and PsychicHttp
407
typedef enum {
408
  AUTH_NONE = 0,  // always allow
409
  AUTH_BASIC = 1,
410
  AUTH_DIGEST = 2,
411
  AUTH_BEARER = 3,
412
  AUTH_OTHER = 4,
413
  AUTH_DENIED = 255,  // always returns 401
414
} AsyncAuthType;
415
 
416
typedef std::function<size_t(uint8_t *, size_t, size_t)> AwsResponseFiller;
417
typedef std::function<String(const String &)> AwsTemplateProcessor;
418
 
419
using AsyncWebServerRequestPtr = std::weak_ptr<AsyncWebServerRequest>;
420
 
421
class AsyncWebServerRequest {
422
  using File = fs::File;
423
  using FS = fs::FS;
424
  friend class AsyncWebServer;
425
  friend class AsyncCallbackWebHandler;
426
  friend class AsyncFileResponse;
427
  friend class AsyncStaticWebHandler;
428
  friend class AsyncURIMatcher;
429
 
430
private:
431
  AsyncClient *_client;
432
  AsyncWebServer *_server;
433
  AsyncWebHandler *_handler;
434
  AsyncWebServerResponse *_response;
435
  ArDisconnectHandler _onDisconnectfn;
436
 
437
  bool _sent = false;                            // response is sent
438
  bool _paused = false;                          // request is paused (request continuation)
439
  std::shared_ptr<AsyncWebServerRequest> _this;  // shared pointer to this request
440
 
441
  String _temp;
442
  uint8_t _parseState;
443
 
444
  uint8_t _version;
445
  WebRequestMethod _method;
446
  String _url;
447
  String _host;
448
  String _contentType;
449
  String _boundary;
450
  String _authorization;
451
  RequestedConnectionType _reqconntype;
452
  AsyncAuthType _authMethod = AsyncAuthType::AUTH_NONE;
453
  bool _isMultipart;
454
  bool _isPlainPost;
455
  bool _expectingContinue;
456
  size_t _contentLength;
457
  size_t _parsedLength;
458
 
459
  std::list<AsyncWebHeader> _headers;
460
  std::list<AsyncWebParameter> _params;
461
#ifdef ASYNCWEBSERVER_REGEX
462
  std::list<String> _pathParams;
463
#endif
464
 
465
  std::unordered_map<const char *, String, std::hash<const char *>, std::equal_to<const char *>> _attributes;
466
 
467
  uint8_t _multiParseState;
468
  uint8_t _boundaryPosition;
469
  size_t _itemStartIndex;
470
  size_t _itemSize;
471
  String _itemName;
472
  String _itemFilename;
473
  String _itemType;
474
  String _itemValue;
475
  uint8_t *_itemBuffer;
476
  size_t _itemBufferIndex;
477
  bool _itemIsFile;
478
 
479
  size_t _chunkStartIndex;  // Offset from start of the chunked data stream
480
  size_t _chunkOffset;      // Offset into the current chunk
481
  size_t _chunkSize;        // Size of the current chunk
482
  uint8_t _chunkedParseState;
483
  uint8_t _chunkedLastChar;
484
  bool _parseChunkedBytes(uint8_t *data, size_t len);
485
 
486
  void _onPoll();
487
  void _onAck(size_t len, uint32_t time);
488
  void _onError(int8_t error);
489
  void _onTimeout(uint32_t time);
490
  void _onDisconnect();
491
  void _onData(void *buf, size_t len);
492
 
493
  bool _parseReqHead();
494
  bool _parseReqHeader();
495
  void _parseLine();
496
  void _parsePlainPostChar(uint8_t data);
497
  void _parseMultipartPostByte(uint8_t data, bool last);
498
  void _addGetParams(const String &params);
499
 
500
  void _handleUploadStart();
501
  void _handleUploadByte(uint8_t data, bool last);
502
  void _handleUploadEnd();
503
 
504
  void _send();
505
  void _runMiddlewareChain();
506
 
507
  static bool _getEtag(File gzFile, char *eTag);
508
 
509
public:
510
  File _tempFile;
511
  void *_tempObject;
512
 
513
  AsyncWebServerRequest(AsyncWebServer *, AsyncClient *);
514
  ~AsyncWebServerRequest();
515
 
516
  AsyncClient *client() {
517
    return _client;
518
  }
519
 
520
  /**
521
   * @brief release owned AsyncClient object
522
   * AsyncClient pointer will be abandoned in this instance,
523
   * the further ownership of the connection should be managed out of request's life-time scope
524
   * could be used for long lived connection like SSE or WebSockets
525
   * @note do not call this method unless you know what you are doing, otherwise it may lead to
526
   * memory leaks and connections lingering
527
   *
528
   * @return AsyncClient* pointer to released connection object
529
   */
530
  AsyncClient *clientRelease();
531
 
532
  uint8_t version() const {
533
    return _version;
534
  }
535
  WebRequestMethod method() const {
536
    return _method;
537
  }
538
  const String &url() const {
539
    return _url;
540
  }
541
  const String &host() const {
542
    return _host;
543
  }
544
  const String &contentType() const {
545
    return _contentType;
546
  }
547
  size_t contentLength() const {
548
    return _contentLength;
549
  }
550
  bool multipart() const {
551
    return _isMultipart;
552
  }
553
 
554
  inline const char *methodToString() const {
555
    return asyncsrv::methodToString(_method);
556
  };
557
  const char *requestedConnTypeToString() const;
558
 
559
  RequestedConnectionType requestedConnType() const {
560
    return _reqconntype;
561
  }
562
  bool isExpectedRequestedConnType(RequestedConnectionType erct1, RequestedConnectionType erct2 = RCT_NOT_USED, RequestedConnectionType erct3 = RCT_NOT_USED)
563
    const;
564
  bool isWebSocketUpgrade() const {
565
    return _method == AsyncWebRequestMethod::HTTP_GET && isExpectedRequestedConnType(RCT_WS);
566
  }
567
  bool isSSE() const {
568
    return _method == AsyncWebRequestMethod::HTTP_GET && isExpectedRequestedConnType(RCT_EVENT);
569
  }
570
  bool isHTTP() const {
571
    return isExpectedRequestedConnType(RCT_DEFAULT, RCT_HTTP);
572
  }
573
  void onDisconnect(ArDisconnectHandler fn);
574
 
575
  // hash is the string representation of:
576
  //  base64(user:pass) for basic or
577
  //  user:realm:md5(user:realm:pass) for digest
578
  bool authenticate(const char *hash) const;
579
  bool authenticate(const char *username, const char *credentials, const char *realm = NULL, bool isHash = false) const;
580
  void requestAuthentication(const char *realm = nullptr, bool isDigest = true) {
581
    requestAuthentication(isDigest ? AsyncAuthType::AUTH_DIGEST : AsyncAuthType::AUTH_BASIC, realm);
582
  }
583
  void requestAuthentication(AsyncAuthType method, const char *realm = nullptr, const char *_authFailMsg = nullptr);
584
 
585
  // detected Authentication type from "Authorization" request header during request parsing
586
  AsyncAuthType authType() const {
587
    return _authMethod;
588
  }
589
 
590
  // raw value of "Authorization" request header after the auth type
591
  // For example, for header "Authorization: Bearer <token>", <token> is the value returned
592
  const String &authChallenge() const {
593
    return _authorization;
594
  }
595
 
596
  // IMPORTANT: this method is for internal use ONLY
597
  // Please do not use it!
598
  // It can be removed or modified at any time without notice
599
  void setHandler(AsyncWebHandler *handler) {
600
    _handler = handler;
601
  }
602
 
603
#ifndef ESP8266
604
  [[deprecated("All headers are now collected. Use removeHeader(name) or AsyncHeaderFreeMiddleware if you really need to free some headers.")]]
605
#endif
606
  void addInterestingHeader(__asyncws_unused const char *name) {
607
  }
608
#ifndef ESP8266
609
  [[deprecated("All headers are now collected. Use removeHeader(name) or AsyncHeaderFreeMiddleware if you really need to free some headers.")]]
610
#endif
611
  void addInterestingHeader(__asyncws_unused const String &name) {
612
  }
613
 
614
  /**
615
     * @brief issue HTTP redirect response with Location header
616
     *
617
     * @param url - url to redirect to
618
     * @param code - response code, default is 302 : temporary redirect
619
     */
620
  void redirect(const char *url, int code = 302);
621
  void redirect(const String &url, int code = 302) {
622
    return redirect(url.c_str(), code);
623
  };
624
 
625
  void send(AsyncWebServerResponse *response);
626
  AsyncWebServerResponse *getResponse() const {
627
    return _response;
628
  }
629
 
630
  void send(int code, const char *contentType = asyncsrv::empty, const char *content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr) {
631
    send(beginResponse(code, contentType, content, callback));
632
  }
633
  void send(int code, const String &contentType, const char *content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr) {
634
    send(beginResponse(code, contentType.c_str(), content, callback));
635
  }
636
  void send(int code, const String &contentType, const String &content, AwsTemplateProcessor callback = nullptr) {
637
    send(beginResponse(code, contentType.c_str(), content.c_str(), callback));
638
  }
639
 
640
  void send(int code, const char *contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr) {
641
    send(beginResponse(code, contentType, content, len, callback));
642
  }
643
  void send(int code, const String &contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr) {
644
    send(beginResponse(code, contentType, content, len, callback));
645
  }
646
 
647
  void send(FS &fs, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
648
  void send(FS &fs, const String &path, const String &contentType, bool download = false, AwsTemplateProcessor callback = nullptr) {
649
    send(fs, path, contentType.c_str(), download, callback);
650
  }
651
 
652
  void send(File content, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr) {
653
    if (content) {
654
      send(beginResponse(content, path, contentType, download, callback));
655
    } else {
656
      send(404);
657
    }
658
  }
659
  void send(File content, const String &path, const String &contentType, bool download = false, AwsTemplateProcessor callback = nullptr) {
660
    send(content, path, contentType.c_str(), download, callback);
661
  }
662
 
663
  void send(Stream &stream, const char *contentType, size_t len, AwsTemplateProcessor callback = nullptr) {
664
    send(beginResponse(stream, contentType, len, callback));
665
  }
666
  void send(Stream &stream, const String &contentType, size_t len, AwsTemplateProcessor callback = nullptr) {
667
    send(beginResponse(stream, contentType, len, callback));
668
  }
669
 
670
  void send(const char *contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) {
671
    send(beginResponse(contentType, len, callback, templateCallback));
672
  }
673
  void send(const String &contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) {
674
    send(beginResponse(contentType, len, callback, templateCallback));
675
  }
676
 
677
  void sendChunked(const char *contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) {
678
    send(beginChunkedResponse(contentType, callback, templateCallback));
679
  }
680
  void sendChunked(const String &contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) {
681
    send(beginChunkedResponse(contentType, callback, templateCallback));
682
  }
683
 
684
#ifndef ESP8266
685
  [[deprecated("Replaced by send(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr)")]]
686
#endif
687
  void send_P(int code, const String &contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr) {
688
    send(code, contentType, content, len, callback);
689
  }
690
#ifndef ESP8266
691
  [[deprecated("Replaced by send(int code, const String& contentType, const char* content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr)")]]
692
  void send_P(int code, const String &contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
693
    send(code, contentType, content, callback);
694
  }
695
#else
696
  void send_P(int code, const String &contentType, PGM_P content, AwsTemplateProcessor callback = nullptr) {
697
    send(beginResponse_P(code, contentType, content, callback));
698
  }
699
#endif
700
 
701
  AsyncWebServerResponse *
702
    beginResponse(int code, const char *contentType = asyncsrv::empty, const char *content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr);
703
  AsyncWebServerResponse *beginResponse(int code, const String &contentType, const char *content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr) {
704
    return beginResponse(code, contentType.c_str(), content, callback);
705
  }
706
  AsyncWebServerResponse *beginResponse(int code, const String &contentType, const String &content, AwsTemplateProcessor callback = nullptr) {
707
    return beginResponse(code, contentType.c_str(), content.c_str(), callback);
708
  }
709
 
710
  AsyncWebServerResponse *beginResponse(int code, const char *contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr);
711
  AsyncWebServerResponse *beginResponse(int code, const String &contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr) {
712
    return beginResponse(code, contentType.c_str(), content, len, callback);
713
  }
714
 
715
  AsyncWebServerResponse *
716
    beginResponse(FS &fs, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
717
  AsyncWebServerResponse *beginResponse(
718
    FS &fs, const String &path, const String &contentType = asyncsrv::emptyString, bool download = false, AwsTemplateProcessor callback = nullptr
719
  ) {
720
    return beginResponse(fs, path, contentType.c_str(), download, callback);
721
  }
722
 
723
  AsyncWebServerResponse *
724
    beginResponse(File content, const String &path, const char *contentType = asyncsrv::empty, bool download = false, AwsTemplateProcessor callback = nullptr);
725
  AsyncWebServerResponse *beginResponse(
726
    File content, const String &path, const String &contentType = asyncsrv::emptyString, bool download = false, AwsTemplateProcessor callback = nullptr
727
  ) {
728
    return beginResponse(content, path, contentType.c_str(), download, callback);
729
  }
730
 
731
  AsyncWebServerResponse *beginResponse(Stream &stream, const char *contentType, size_t len, AwsTemplateProcessor callback = nullptr);
732
  AsyncWebServerResponse *beginResponse(Stream &stream, const String &contentType, size_t len, AwsTemplateProcessor callback = nullptr) {
733
    return beginResponse(stream, contentType.c_str(), len, callback);
734
  }
735
 
736
  AsyncWebServerResponse *beginResponse(const char *contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
737
  AsyncWebServerResponse *beginResponse(const String &contentType, size_t len, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) {
738
    return beginResponse(contentType.c_str(), len, callback, templateCallback);
739
  }
740
 
741
  AsyncWebServerResponse *beginChunkedResponse(const char *contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr);
742
  AsyncWebServerResponse *beginChunkedResponse(const String &contentType, AwsResponseFiller callback, AwsTemplateProcessor templateCallback = nullptr) {
743
    return beginChunkedResponse(contentType.c_str(), callback, templateCallback);
744
  }
745
 
746
  AsyncResponseStream *beginResponseStream(const char *contentType, size_t bufferSize = RESPONSE_STREAM_BUFFER_SIZE);
747
  AsyncResponseStream *beginResponseStream(const String &contentType, size_t bufferSize = RESPONSE_STREAM_BUFFER_SIZE) {
748
    return beginResponseStream(contentType.c_str(), bufferSize);
749
  }
750
 
751
#ifndef ESP8266
752
  [[deprecated("Replaced by beginResponse(int code, const String& contentType, const uint8_t* content, size_t len, AwsTemplateProcessor callback = nullptr)")]]
753
#endif
754
  AsyncWebServerResponse *beginResponse_P(int code, const String &contentType, const uint8_t *content, size_t len, AwsTemplateProcessor callback = nullptr) {
755
    return beginResponse(code, contentType.c_str(), content, len, callback);
756
  }
757
#ifndef ESP8266
758
  [[deprecated("Replaced by beginResponse(int code, const String& contentType, const char* content = asyncsrv::empty, AwsTemplateProcessor callback = nullptr)"
759
  )]]
760
#endif
761
  AsyncWebServerResponse *beginResponse_P(int code, const String &contentType, PGM_P content, AwsTemplateProcessor callback = nullptr);
762
 
763
  /**
764
   * @brief Request Continuation: this function pauses the current request and returns a weak pointer (AsyncWebServerRequestPtr is a std::weak_ptr) to the request in order to reuse it later on.
765
   * The middelware chain will continue to be processed until the end, but no response will be sent.
766
   * To resume operations (send the request), the request must be retrieved from the weak pointer and a send() function must be called.
767
   * AsyncWebServerRequestPtr is the only object allowed to exist the scope of the request handler.
768
   * @warning This function should be called from within the context of a request (in a handler or middleware for example).
769
   * @warning While the request is paused, if the client aborts the request, the latter will be disconnected and deleted.
770
   * So it is the responsibility of the user to check the validity of the request pointer (AsyncWebServerRequestPtr) before using it by calling lock() and/or expired().
771
   */
772
  AsyncWebServerRequestPtr pause();
773
 
774
  bool isPaused() const {
775
    return _paused;
776
  }
777
 
778
  /**
779
   * @brief Aborts the request and close the client (RST).
780
   * Mark the request as sent.
781
   * If it was paused, it will be unpaused and it won't be possible to resume it.
782
   */
783
  void abort();
784
 
785
  bool isSent() const {
786
    return _sent;
787
  }
788
 
789
  /**
790
     * @brief Get the Request parameter by name
791
     *
792
     * @param name
793
     * @param post
794
     * @param file
795
     * @return const AsyncWebParameter*
796
     */
797
  const AsyncWebParameter *getParam(const char *name, bool post = false, bool file = false) const;
798
 
799
  const AsyncWebParameter *getParam(const String &name, bool post = false, bool file = false) const {
800
    return getParam(name.c_str(), post, file);
801
  };
802
#ifdef ESP8266
803
  const AsyncWebParameter *getParam(const __FlashStringHelper *data, bool post, bool file) const;
804
#endif
805
 
806
  /**
807
     * @brief Get request parameter by number
808
     * i.e., n-th parameter
809
     * @param num
810
     * @return const AsyncWebParameter*
811
     */
812
  const AsyncWebParameter *getParam(size_t num) const;
813
  const AsyncWebParameter *getParam(int num) const {
814
    return num < 0 ? nullptr : getParam((size_t)num);
815
  }
816
 
817
  size_t args() const {
818
    return params();
819
  }  // get arguments count
820
 
821
  // get request argument value by name
822
  const String &arg(const char *name) const;
823
  // get request argument value by name
824
  const String &arg(const String &name) const {
825
    return arg(name.c_str());
826
  };
827
#ifdef ESP8266
828
  const String &arg(const __FlashStringHelper *data) const;  // get request argument value by F(name)
829
#endif
830
  const String &arg(size_t i) const;  // get request argument value by number
831
  const String &arg(int i) const {
832
    return i < 0 ? asyncsrv::emptyString : arg((size_t)i);
833
  };
834
  const String &argName(size_t i) const;  // get request argument name by number
835
  const String &argName(int i) const {
836
    return i < 0 ? asyncsrv::emptyString : argName((size_t)i);
837
  };
838
  bool hasArg(const char *name) const;  // check if argument exists
839
  bool hasArg(const String &name) const {
840
    return hasArg(name.c_str());
841
  };
842
#ifdef ESP8266
843
  bool hasArg(const __FlashStringHelper *data) const;  // check if F(argument) exists
844
#endif
845
 
846
#ifdef ASYNCWEBSERVER_REGEX
847
  const String &pathArg(size_t i) const {
848
    if (i >= _pathParams.size()) {
849
      return asyncsrv::emptyString;
850
    }
851
    auto it = _pathParams.begin();
852
    std::advance(it, i);
853
    return *it;
854
  }
855
  const String &pathArg(int i) const {
856
    return i < 0 ? asyncsrv::emptyString : pathArg((size_t)i);
857
  }
858
#else
859
  const String &pathArg(size_t i) const __attribute__((error("ERR: pathArg() requires -D ASYNCWEBSERVER_REGEX and only works on regex handlers")));
860
  const String &pathArg(int i) const __attribute__((error("ERR: pathArg() requires -D ASYNCWEBSERVER_REGEX and only works on regex handlers")));
861
#endif
862
 
863
  // get request header value by name
864
  const String &header(const char *name) const;
865
  const String &header(const String &name) const {
866
    return header(name.c_str());
867
  };
868
 
869
#ifdef ESP8266
870
  const String &header(const __FlashStringHelper *data) const;  // get request header value by F(name)
871
#endif
872
 
873
  const String &header(size_t i) const;  // get request header value by number
874
  const String &header(int i) const {
875
    return i < 0 ? asyncsrv::emptyString : header((size_t)i);
876
  };
877
  const String &headerName(size_t i) const;  // get request header name by number
878
  const String &headerName(int i) const {
879
    return i < 0 ? asyncsrv::emptyString : headerName((size_t)i);
880
  };
881
 
882
  size_t headers() const;  // get header count
883
 
884
  // check if header exists
885
  bool hasHeader(const char *name) const;
886
  bool hasHeader(const String &name) const {
887
    return hasHeader(name.c_str());
888
  };
889
#ifdef ESP8266
890
  bool hasHeader(const __FlashStringHelper *data) const;  // check if header exists
891
#endif
892
 
893
  const AsyncWebHeader *getHeader(const char *name) const;
894
  const AsyncWebHeader *getHeader(const String &name) const {
895
    return getHeader(name.c_str());
896
  };
897
#ifdef ESP8266
898
  const AsyncWebHeader *getHeader(const __FlashStringHelper *data) const;
899
#endif
900
 
901
  const AsyncWebHeader *getHeader(size_t num) const;
902
  const AsyncWebHeader *getHeader(int num) const {
903
    return num < 0 ? nullptr : getHeader((size_t)num);
904
  };
905
 
906
  const std::list<AsyncWebHeader> &getHeaders() const {
907
    return _headers;
908
  }
909
 
910
  size_t getHeaderNames(std::vector<const char *> &names) const;
911
 
912
  // Remove a header from the request.
913
  // It will free the memory and prevent the header to be seen during request processing.
914
  bool removeHeader(const char *name);
915
  // Remove all request headers.
916
  void removeHeaders() {
917
    _headers.clear();
918
  }
919
 
920
  size_t params() const;  // get arguments count
921
  bool hasParam(const char *name, bool post = false, bool file = false) const;
922
  bool hasParam(const String &name, bool post = false, bool file = false) const {
923
    return hasParam(name.c_str(), post, file);
924
  };
925
#ifdef ESP8266
926
  bool hasParam(const __FlashStringHelper *data, bool post = false, bool file = false) const {
927
    return hasParam(String(data).c_str(), post, file);
928
  };
929
#endif
930
 
931
  // REQUEST ATTRIBUTES
932
 
933
  void setAttribute(const char *name, const char *value) {
934
    _attributes[name] = value;
935
  }
936
  void setAttribute(const char *name, bool value) {
937
    _attributes[name] = value ? "1" : asyncsrv::emptyString;
938
  }
939
  void setAttribute(const char *name, long value) {
940
    _attributes[name] = String(value);
941
  }
942
  void setAttribute(const char *name, float value, unsigned int decimalPlaces = 2) {
943
    _attributes[name] = String(value, decimalPlaces);
944
  }
945
  void setAttribute(const char *name, double value, unsigned int decimalPlaces = 2) {
946
    _attributes[name] = String(value, decimalPlaces);
947
  }
948
 
949
  bool hasAttribute(const char *name) const {
950
    return _attributes.find(name) != _attributes.end();
951
  }
952
 
953
  const String &getAttribute(const char *name, const String &defaultValue = asyncsrv::emptyString) const;
954
  bool getAttribute(const char *name, bool defaultValue) const;
955
  long getAttribute(const char *name, long defaultValue) const;
956
  float getAttribute(const char *name, float defaultValue) const;
957
  double getAttribute(const char *name, double defaultValue) const;
958
 
959
  String urlDecode(const String &text) const;
960
};
961
 
962
class AsyncURIMatcher {
963
private:
964
  // Matcher types are internal, not part of public API
965
  enum class Type {
966
    None,                // default state: matcher does not match anything
967
    All,                 // matches everything
968
    Exact,               // matches equivalent to regex: ^{_uri}$
969
    Prefix,              // matches equivalent to regex: ^{_uri}.*
970
    Extension,           // non-regular match: /pattern../*.ext
971
    BackwardCompatible,  // matches equivalent to regex: ^{_uri}(/.*)?$
972
    Regex,               // matches _url as regex
973
  };
974
 
975
public:
976
  /**
977
   * @brief No special matching behavior (default)
978
   */
979
  static constexpr uint16_t None = 0;
980
 
981
  /**
982
   * @brief Enable case-insensitive URI matching
983
   *
984
   * When CaseInsensitive is specified:
985
   * - The URI pattern is converted to lowercase during construction
986
   * - Incoming request URLs are converted to lowercase before matching
987
   * - For regex matchers, the std::regex::icase flag is used
988
   *
989
   * Example usage:
990
   * ```cpp
991
   * // Matches /login, /LOGIN, /Login, /LoGiN, etc.
992
   * server.on(AsyncURIMatcher::exact("/login", AsyncURIMatcher::CaseInsensitive), handler);
993
   *
994
   * // Matches /api/\*, /API/\*, /Api/\*, etc.
995
   * server.on(AsyncURIMatcher::prefix("/api", AsyncURIMatcher::CaseInsensitive), handler);
996
   *
997
   * // Regex with case insensitive matching
998
   * server.on(AsyncURIMatcher::regex("^/user/([a-z]+)$", AsyncURIMatcher::CaseInsensitive), handler);
999
   * ```
1000
   *
1001
   * Performance note: Case conversion adds minimal overhead during construction and matching.
1002
   */
1003
  static constexpr uint16_t CaseInsensitive = (1 << 0);
1004
 
1005
  // public constructors
1006
  AsyncURIMatcher() : AsyncURIMatcher({}, Type::None, None) {}
1007
  AsyncURIMatcher(const char *uri, uint16_t modifiers = None) : AsyncURIMatcher(String(uri), modifiers) {}
1008
  AsyncURIMatcher(String uri, uint16_t modifiers = None);
1009
 
1010
#ifdef ASYNCWEBSERVER_REGEX
1011
  AsyncURIMatcher(const AsyncURIMatcher &c);
1012
  AsyncURIMatcher(AsyncURIMatcher &&c);
1013
  ~AsyncURIMatcher();
1014
 
1015
  AsyncURIMatcher &operator=(const AsyncURIMatcher &r);
1016
  AsyncURIMatcher &operator=(AsyncURIMatcher &&r);
1017
 
1018
#else
1019
  AsyncURIMatcher(const AsyncURIMatcher &) = default;
1020
  AsyncURIMatcher(AsyncURIMatcher &&) = default;
1021
  ~AsyncURIMatcher() = default;
1022
 
1023
  AsyncURIMatcher &operator=(const AsyncURIMatcher &) = default;
1024
  AsyncURIMatcher &operator=(AsyncURIMatcher &&) = default;
1025
#endif
1026
 
1027
  bool matches(AsyncWebServerRequest *request) const;
1028
 
1029
  // static factory methods for common match types:
1030
  // - AsyncURIMatcher::all() - matches everything
1031
  // - AsyncURIMatcher::none() - matches nothing
1032
  // - AsyncURIMatcher::exact(uri, modifiers) - exact match
1033
  // - AsyncURIMatcher::prefix(uri, modifiers) - prefix match
1034
  // - AsyncURIMatcher::dir(uri, modifiers) - directory/folder match (trailing slash added automatically)
1035
  // - AsyncURIMatcher::ext(uri, modifiers) - extension match (pattern with wildcard)
1036
  // - AsyncURIMatcher::regex(uri, modifiers) - regex match (requires ASYNCWEBSERVER_REGEX)
1037
 
1038
  /**
1039
   * @brief Create a matcher that matches all URIs unconditionally
1040
   * @return AsyncURIMatcher that accepts any request URL
1041
   *
1042
   * Usage: server.on(AsyncURIMatcher::all(), handler);
1043
   */
1044
  static inline AsyncURIMatcher all() {
1045
    return AsyncURIMatcher{{}, Type::All, None};
1046
  }
1047
 
1048
  /**
1049
   * @brief Create a matcher that matches no URIs (never matches)
1050
   * @return AsyncURIMatcher that rejects all request URLs
1051
   *
1052
   * Usage: server.on(AsyncURIMatcher::none(), handler);
1053
   */
1054
  static inline AsyncURIMatcher none() {
1055
    return AsyncURIMatcher{{}, Type::None, None};
1056
  }
1057
 
1058
  /**
1059
   * @brief Create an exact URI matcher
1060
   * @param c The exact URI string to match (e.g., "/login", "/api/status")
1061
   * @param modifiers Optional modifiers (CaseInsensitive, etc.)
1062
   * @return AsyncURIMatcher that matches only the exact URI
1063
   *
1064
   * Usage: server.on(AsyncURIMatcher::exact("/login"), handler);
1065
   * Matches: "/login"
1066
   * Doesn't match: "/login/", "/login-page"
1067
   * Doesn't match: "/LOGIN" (unless CaseInsensitive flag used)
1068
   */
1069
  static inline AsyncURIMatcher exact(String c, uint16_t modifiers = None) {
1070
    return AsyncURIMatcher{std::move(c), Type::Exact, modifiers};
1071
  }
1072
 
1073
  /**
1074
   * @brief Create a prefix URI matcher
1075
   * @param c The URI prefix to match (e.g., "/api", "/static")
1076
   * @param modifiers Optional modifiers (CaseInsensitive, etc.)
1077
   * @return AsyncURIMatcher that matches URIs starting with the prefix
1078
   *
1079
   * Usage: server.on(AsyncURIMatcher::prefix("/api"), handler);
1080
   * Matches: "/api", "/api/users", "/api-v2", "/apitest"
1081
   * Note: This is pure prefix matching - does NOT require folder separator
1082
   */
1083
  static inline AsyncURIMatcher prefix(String c, uint16_t modifiers = None) {
1084
    return AsyncURIMatcher{std::move(c), Type::Prefix, modifiers};
1085
  }
1086
 
1087
  /**
1088
   * @brief Create a directory/folder URI matcher
1089
   * @param c The directory path (trailing slash automatically added if missing)
1090
   * @param modifiers Optional modifiers (CaseInsensitive, etc.)
1091
   * @return AsyncURIMatcher that matches URIs under the directory
1092
   *
1093
   * Usage: server.on(AsyncURIMatcher::dir("/admin"), handler);
1094
   * Matches: "/admin/users", "/admin/settings", "/admin/sub/path"
1095
   * Doesn't match: "/admin" (exact), "/admin-panel" (no folder separator)
1096
   *
1097
   * The trailing slash is automatically added for convenience and efficiency.
1098
   */
1099
  static inline AsyncURIMatcher dir(String c, uint16_t modifiers = None) {
1100
    // Pre-calculate folder for efficiency
1101
    if (!c.length()) {
1102
      return AsyncURIMatcher{"/", Type::Prefix, modifiers};
1103
    }
1104
    if (c[c.length() - 1] != '/') {
1105
      c.concat('/');
1106
    }
1107
    return AsyncURIMatcher{std::move(c), Type::Prefix, modifiers};
1108
  }
1109
 
1110
  /**
1111
   * @brief Create a file extension URI matcher
1112
   * @param c The pattern with wildcard extension (e.g., "/images/\*.jpg", "/docs/\*.pdf")
1113
   * @param modifiers Optional modifiers (CaseInsensitive, etc.)
1114
   * @return AsyncURIMatcher that matches files with specific extensions under a path
1115
   *
1116
   * Usage: server.on(AsyncURIMatcher::ext("/images/\*.jpg"), handler);
1117
   * Matches: "/images/photo.jpg", "/images/gallery/pic.jpg"
1118
   * Doesn't match: "/images/photo.png", "/img/photo.jpg"
1119
   *
1120
   * Pattern format: "/path/\*.extension" where "*" is a literal wildcard placeholder.
1121
   * The path before "/\*." must match exactly, and the URI must end with the extension.
1122
   */
1123
  static inline AsyncURIMatcher ext(String c, uint16_t modifiers = None) {
1124
    return AsyncURIMatcher{std::move(c), Type::Extension, modifiers};
1125
  }
1126
 
1127
#ifdef ASYNCWEBSERVER_REGEX
1128
  /**
1129
   * @brief Create a regular expression URI matcher
1130
   * @param c The regex pattern string (e.g., "^/user/([0-9]+)$", "^/blog/([0-9]{4})/([0-9]{2})$")
1131
   * @param modifiers Optional modifiers (CaseInsensitive applies to regex compilation)
1132
   * @return AsyncURIMatcher that matches URIs using regex with capture groups
1133
   *
1134
   * Usage: server.on(AsyncURIMatcher::regex("^/user/([0-9]+)$"), handler);
1135
   * Matches: "/user/123", "/user/456"
1136
   * Doesn't match: "/user/abc", "/user/123/profile"
1137
   *
1138
   * Captured groups can be accessed via request->pathArg(index) in the handler.
1139
   * Requires ASYNCWEBSERVER_REGEX to be defined during compilation.
1140
   * Performance note: Regex matching is slower than other match types.
1141
   */
1142
  static inline AsyncURIMatcher regex(String c, uint16_t modifiers = None) {
1143
    return AsyncURIMatcher{std::move(c), Type::Regex, modifiers};
1144
  }
1145
#endif
1146
 
1147
private:
1148
  // fields
1149
  String _value;
1150
  union {
1151
    intptr_t _flags;  // type and flags packed together
1152
#ifdef ASYNCWEBSERVER_REGEX
1153
    // Overlay the pattern pointer storage with the type.  It is treated as a tagged pointer:
1154
    // if any of the LSBs are set, it stores type, as a valid object must be aligned and so
1155
    // none of the LSBs can be set in a valid pointer.
1156
    std::regex *pattern;
1157
#endif
1158
  };
1159
 
1160
  // private constructor called from static factory methods
1161
  AsyncURIMatcher(String uri, Type type, uint16_t modifiers);
1162
 
1163
#ifdef ASYNCWEBSERVER_REGEX
1164
  inline bool _isRegex() const {
1165
    static_assert(
1166
      (std::alignment_of<std::regex>::value % 2) == 0, "Unexpected regex type alignment - please let the ESPAsyncWebServer team know about your platform!"
1167
    );
1168
    // pattern is non-null pointer with correct alignment.
1169
    // We use the _flags view as it's already a integer type.
1170
    return _flags && !(_flags & (std::alignment_of<std::regex>::value - 1));
1171
  }
1172
#endif
1173
 
1174
  static constexpr intptr_t _toFlags(Type type, uint16_t modifiers) {
1175
    // Use lsb to disambiguate from regex pointer in the case where someone has regex activated but uses a non-regex type.
1176
    // We always do this shift, even if regex is not enabled, to keep the layout identical and also catch programmatic errors earlier.
1177
    // For example a mistake is to set a modifier flag to (1 << 15), which is the msb of the uint16_t.
1178
    // This msb is discarded during this shift operation.
1179
    // So pay attention to not have more than 15 modifier flags.
1180
    return ((uint32_t(modifiers) << 16 | uint16_t(type)) << 1) + 1;
1181
  }
1182
 
1183
  static constexpr std::tuple<Type, uint16_t> _fromFlags(intptr_t in_flags) {
1184
    // shift off disambiguation bit
1185
    // - Type is lower 16 bits
1186
    // - Modifiers are upper 16 bits
1187
    return std::make_tuple(static_cast<Type>((in_flags >> 1) & 0xFFFF), (in_flags >> 1) >> 16);
1188
  }
1189
};
1190
 
1191
/*
1192
 * FILTER :: Callback to filter AsyncWebRewrite and AsyncWebHandler (done by the Server)
1193
 * */
1194
 
1195
using ArRequestFilterFunction = std::function<bool(AsyncWebServerRequest *request)>;
1196
 
1197
bool ON_STA_FILTER(AsyncWebServerRequest *request);
1198
 
1199
bool ON_AP_FILTER(AsyncWebServerRequest *request);
1200
 
1201
/*
1202
 * MIDDLEWARE :: Request interceptor, assigned to a AsyncWebHandler (or the server), which can be used:
1203
 * 1. to run some code before the final handler is executed (e.g. check authentication)
1204
 * 2. decide whether to proceed or not with the next handler
1205
 * */
1206
 
1207
using ArMiddlewareNext = std::function<void(void)>;
1208
using ArMiddlewareCallback = std::function<void(AsyncWebServerRequest *request, ArMiddlewareNext next)>;
1209
 
1210
// Middleware is a base class for all middleware
1211
class AsyncMiddleware {
1212
public:
1213
  virtual ~AsyncMiddleware() {}
1214
  virtual void run(__asyncws_unused AsyncWebServerRequest *request, __asyncws_unused ArMiddlewareNext next) {
1215
    return next();
1216
  };
1217
 
1218
private:
1219
  friend class AsyncWebHandler;
1220
  friend class AsyncEventSource;
1221
  friend class AsyncMiddlewareChain;
1222
  bool _freeOnRemoval = false;
1223
};
1224
 
1225
// Create a custom middleware by providing an anonymous callback function
1226
class AsyncMiddlewareFunction : public AsyncMiddleware {
1227
public:
1228
  AsyncMiddlewareFunction(ArMiddlewareCallback fn) : _fn(fn) {}
1229
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next) override {
1230
    return _fn(request, next);
1231
  };
1232
 
1233
private:
1234
  ArMiddlewareCallback _fn;
1235
};
1236
 
1237
// For internal use only: super class to add/remove middleware to server or handlers
1238
class AsyncMiddlewareChain {
1239
public:
1240
  ~AsyncMiddlewareChain();
1241
 
1242
  void addMiddleware(ArMiddlewareCallback fn);
1243
  void addMiddleware(AsyncMiddleware *middleware);
1244
  void addMiddlewares(std::vector<AsyncMiddleware *> middlewares);
1245
  bool removeMiddleware(AsyncMiddleware *middleware);
1246
 
1247
  // For internal use only
1248
  void _runChain(AsyncWebServerRequest *request, ArMiddlewareNext finalizer);
1249
 
1250
protected:
1251
  std::list<AsyncMiddleware *> _middlewares;
1252
};
1253
 
1254
// AsyncAuthenticationMiddleware is a middleware that checks if the request is authenticated
1255
class AsyncAuthenticationMiddleware : public AsyncMiddleware {
1256
public:
1257
  const String &username() const {
1258
    return _username;
1259
  }
1260
  const String &credentials() const {
1261
    return _credentials;
1262
  }
1263
  const String &realm() const {
1264
    return _realm;
1265
  }
1266
  const String &authFailureMessage() const {
1267
    return _authFailMsg;
1268
  }
1269
  bool isHash() const {
1270
    return _hash;
1271
  }
1272
  AsyncAuthType authType() const {
1273
    return _authMethod;
1274
  }
1275
 
1276
  void setUsername(const char *username);
1277
  void setPassword(const char *password);
1278
  void setPasswordHash(const char *hash);
1279
 
1280
  // can be used for Bearer token authentication with a static shared secret
1281
  void setToken(const char *token);
1282
  void setAuthentificationFunction(std::function<bool(AsyncWebServerRequest *request)> func) {
1283
    _authcFunc = func;
1284
  }
1285
 
1286
  void setRealm(const char *realm) {
1287
    _realm = realm;
1288
  }
1289
  void setAuthFailureMessage(const char *message) {
1290
    _authFailMsg = message;
1291
  }
1292
 
1293
  // set the authentication method to use
1294
  // default is AUTH_NONE: no authentication required
1295
  // AUTH_BASIC: basic authentication
1296
  // AUTH_DIGEST: digest authentication
1297
  // AUTH_BEARER: bearer token authentication
1298
  // AUTH_OTHER: other authentication method
1299
  // AUTH_DENIED: always return 401 Unauthorized
1300
  // if a method is set but no username or password is set, authentication will be ignored
1301
  void setAuthType(AsyncAuthType authMethod) {
1302
    _authMethod = authMethod;
1303
  }
1304
 
1305
  // precompute and store the hash value based on the username, password, realm.
1306
  // can be used for DIGEST and BASIC to avoid recomputing the hash for each request.
1307
  // returns true if the hash was successfully generated and replaced
1308
  bool generateHash();
1309
 
1310
  // returns true if the username and password (or hash) are set
1311
  bool hasCredentials() const {
1312
    return _hasCreds;
1313
  }
1314
 
1315
  bool allowed(AsyncWebServerRequest *request) const;
1316
 
1317
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next);
1318
 
1319
private:
1320
  String _username;
1321
  String _credentials;
1322
  bool _hash = false;
1323
 
1324
  String _realm = asyncsrv::T_LOGIN_REQ;
1325
  AsyncAuthType _authMethod = AsyncAuthType::AUTH_NONE;
1326
  String _authFailMsg;
1327
  bool _hasCreds = false;
1328
  std::function<bool(AsyncWebServerRequest *request)> _authcFunc = [this](AsyncWebServerRequest *request) {
1329
    return request->authenticate(_username.c_str(), _credentials.c_str(), _realm.c_str(), _hash);
1330
  };
1331
};
1332
 
1333
using ArAuthorizeFunction = std::function<bool(AsyncWebServerRequest *request)>;
1334
// AsyncAuthorizationMiddleware is a middleware that checks if the request is authorized
1335
class AsyncAuthorizationMiddleware : public AsyncMiddleware {
1336
public:
1337
  AsyncAuthorizationMiddleware(ArAuthorizeFunction authorizeConnectHandler) : _code(403), _authz(authorizeConnectHandler) {}
1338
  AsyncAuthorizationMiddleware(int code, ArAuthorizeFunction authorizeConnectHandler) : _code(code), _authz(authorizeConnectHandler) {}
1339
 
1340
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next) {
1341
    return _authz && !_authz(request) ? request->send(_code) : next();
1342
  }
1343
 
1344
private:
1345
  int _code;
1346
  ArAuthorizeFunction _authz;
1347
};
1348
 
1349
// remove all headers from the incoming request except the ones provided in the constructor
1350
class AsyncHeaderFreeMiddleware : public AsyncMiddleware {
1351
public:
1352
  void keep(const char *name) {
1353
    _toKeep.push_back(name);
1354
  }
1355
  void unKeep(const char *name) {
1356
    _toKeep.remove(name);
1357
  }
1358
 
1359
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next);
1360
 
1361
private:
1362
  std::list<const char *> _toKeep;
1363
};
1364
 
1365
// filter out specific headers from the incoming request
1366
class AsyncHeaderFilterMiddleware : public AsyncMiddleware {
1367
public:
1368
  void filter(const char *name) {
1369
    _toRemove.push_back(name);
1370
  }
1371
  void unFilter(const char *name) {
1372
    _toRemove.remove(name);
1373
  }
1374
 
1375
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next);
1376
 
1377
private:
1378
  std::list<const char *> _toRemove;
1379
};
1380
 
1381
// curl-like logging of incoming requests
1382
class AsyncLoggingMiddleware : public AsyncMiddleware {
1383
public:
1384
  void setOutput(Print &output) {
1385
    _out = &output;
1386
  }
1387
  void setEnabled(bool enabled) {
1388
    _enabled = enabled;
1389
  }
1390
  bool isEnabled() const {
1391
    return _enabled && _out;
1392
  }
1393
 
1394
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next);
1395
 
1396
private:
1397
  Print *_out = nullptr;
1398
  bool _enabled = true;
1399
};
1400
 
1401
// CORS Middleware
1402
class AsyncCorsMiddleware : public AsyncMiddleware {
1403
public:
1404
  void setOrigin(const char *origin) {
1405
    _origin = origin;
1406
  }
1407
  void setMethods(const char *methods) {
1408
    _methods = methods;
1409
  }
1410
  void setHeaders(const char *headers) {
1411
    _headers = headers;
1412
  }
1413
  void setAllowCredentials(bool credentials) {
1414
    _credentials = credentials;
1415
  }
1416
  void setMaxAge(uint32_t seconds) {
1417
    _maxAge = seconds;
1418
  }
1419
 
1420
#ifndef ESP8266
1421
  [[deprecated("Use instead: addCORSHeaders(AsyncWebServerRequest *request, AsyncWebServerResponse *response)")]]
1422
#endif
1423
  void addCORSHeaders(AsyncWebServerResponse *response) {
1424
    addCORSHeaders(nullptr, response);
1425
  }
1426
  void addCORSHeaders(AsyncWebServerRequest *request, AsyncWebServerResponse *response);
1427
 
1428
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next);
1429
 
1430
private:
1431
  String _origin = "*";
1432
  String _methods = "*";
1433
  String _headers = "*";
1434
  bool _credentials = true;
1435
  uint32_t _maxAge = 86400;
1436
};
1437
 
1438
// Rate limit Middleware
1439
class AsyncRateLimitMiddleware : public AsyncMiddleware {
1440
public:
1441
  void setMaxRequests(size_t maxRequests) {
1442
    _maxRequests = maxRequests;
1443
  }
1444
  void setWindowSize(uint32_t seconds) {
1445
    _windowSizeMillis = seconds * 1000;
1446
  }
1447
 
1448
  bool isRequestAllowed(uint32_t &retryAfterSeconds);
1449
 
1450
  void run(AsyncWebServerRequest *request, ArMiddlewareNext next);
1451
 
1452
private:
1453
  size_t _maxRequests = 0;
1454
  uint32_t _windowSizeMillis = 0;
1455
  std::list<uint32_t> _requestTimes;
1456
};
1457
 
1458
/*
1459
 * REWRITE :: One instance can be handle any Request (done by the Server)
1460
 * */
1461
 
1462
class AsyncWebRewrite {
1463
protected:
1464
  String _from;
1465
  String _toUrl;
1466
  String _params;
1467
  ArRequestFilterFunction _filter{nullptr};
1468
 
1469
public:
1470
  AsyncWebRewrite(const char *from, const char *to) : _from(from), _toUrl(to) {
1471
    int index = _toUrl.indexOf('?');
1472
    if (index > 0) {
1473
      _params = _toUrl.substring(index + 1);
1474
      _toUrl = _toUrl.substring(0, index);
1475
    }
1476
  }
1477
  virtual ~AsyncWebRewrite() {}
1478
  AsyncWebRewrite &setFilter(ArRequestFilterFunction fn) {
1479
    _filter = fn;
1480
    return *this;
1481
  }
1482
  bool filter(AsyncWebServerRequest *request) const {
1483
    return _filter == NULL || _filter(request);
1484
  }
1485
  const String &from(void) const {
1486
    return _from;
1487
  }
1488
  const String &toUrl(void) const {
1489
    return _toUrl;
1490
  }
1491
  const String &params(void) const {
1492
    return _params;
1493
  }
1494
  virtual bool match(AsyncWebServerRequest *request) {
1495
    return from() == request->url() && filter(request);
1496
  }
1497
};
1498
 
1499
/*
1500
 * HANDLER :: One instance can be attached to any Request (done by the Server)
1501
 * */
1502
 
1503
class AsyncWebHandler : public AsyncMiddlewareChain {
1504
protected:
1505
  ArRequestFilterFunction _filter = nullptr;
1506
  AsyncAuthenticationMiddleware *_authMiddleware = nullptr;
1507
  bool _skipServerMiddlewares = false;
1508
 
1509
public:
1510
  AsyncWebHandler() {}
1511
  virtual ~AsyncWebHandler() {}
1512
  AsyncWebHandler &setFilter(ArRequestFilterFunction fn);
1513
  AsyncWebHandler &setAuthentication(const char *username, const char *password, AsyncAuthType authMethod = AsyncAuthType::AUTH_DIGEST);
1514
  AsyncWebHandler &setAuthentication(const String &username, const String &password, AsyncAuthType authMethod = AsyncAuthType::AUTH_DIGEST) {
1515
    return setAuthentication(username.c_str(), password.c_str(), authMethod);
1516
  };
1517
  AsyncWebHandler &setSkipServerMiddlewares(bool state) {
1518
    _skipServerMiddlewares = state;
1519
    return *this;
1520
  }
1521
  // skip all globally defined server middlewares for this handler and only execute those defined for this handler specifically
1522
  AsyncWebHandler &skipServerMiddlewares() {
1523
    return setSkipServerMiddlewares(true);
1524
  }
1525
  bool mustSkipServerMiddlewares() const {
1526
    return _skipServerMiddlewares;
1527
  }
1528
  bool filter(AsyncWebServerRequest *request) {
1529
    return _filter == NULL || _filter(request);
1530
  }
1531
  virtual bool canHandle(AsyncWebServerRequest *request __attribute__((unused))) const {
1532
    return false;
1533
  }
1534
  virtual void handleRequest(__asyncws_unused AsyncWebServerRequest *request) {}
1535
  virtual void handleUpload(
1536
    __asyncws_unused AsyncWebServerRequest *request, __asyncws_unused const String &filename, __asyncws_unused size_t index, __asyncws_unused uint8_t *data,
1537
    __asyncws_unused size_t len, __asyncws_unused bool final
1538
  ) {}
1539
  virtual void handleBody(
1540
    __asyncws_unused AsyncWebServerRequest *request, __asyncws_unused uint8_t *data, __asyncws_unused size_t len, __asyncws_unused size_t index,
1541
    __asyncws_unused size_t total
1542
  ) {}
1543
  virtual bool isRequestHandlerTrivial() const {
1544
    return true;
1545
  }
1546
};
1547
 
1548
/*
1549
 * RESPONSE :: One instance is created for each Request (attached by the Handler)
1550
 * */
1551
 
1552
typedef enum {
1553
  RESPONSE_SETUP,
1554
  RESPONSE_HEADERS,
1555
  RESPONSE_CONTENT,
1556
  RESPONSE_WAIT_ACK,
1557
  RESPONSE_END,
1558
  RESPONSE_FAILED
1559
} WebResponseState;
1560
 
1561
class AsyncWebServerResponse {
1562
protected:
1563
  int _code;
1564
  std::list<AsyncWebHeader> _headers;
1565
  String _contentType;
1566
  size_t _contentLength;
1567
  bool _sendContentLength;
1568
  bool _chunked;
1569
  size_t _headLength;
1570
  // amount of data sent for content part of the response (excluding all headers)
1571
  size_t _sentLength;
1572
  size_t _ackedLength;
1573
  // amount of response bytes (including all headers) written to sockbuff for delivery
1574
  size_t _writtenLength;
1575
  WebResponseState _state;
1576
 
1577
  static bool headerMustBePresentOnce(const String &name);
1578
 
1579
public:
1580
  // Return type changes based on platform (const char* or __FlashStringHelper*)
1581
  static STR_RETURN_TYPE responseCodeToString(int code);
1582
 
1583
public:
1584
  AsyncWebServerResponse();
1585
  virtual ~AsyncWebServerResponse() {}
1586
  void setCode(int code);
1587
  int code() const {
1588
    return _code;
1589
  }
1590
  void setContentLength(size_t len);
1591
  void setContentType(const String &type) {
1592
    setContentType(type.c_str());
1593
  }
1594
  void setContentType(const char *type);
1595
  bool addHeader(AsyncWebHeader &&header, bool replaceExisting = true);
1596
  bool addHeader(const AsyncWebHeader &header, bool replaceExisting = true) {
1597
    return header && addHeader(header.name(), header.value(), replaceExisting);
1598
  }
1599
  bool addHeader(const char *name, const char *value, bool replaceExisting = true);
1600
  bool addHeader(const String &name, const String &value, bool replaceExisting = true) {
1601
    return addHeader(name.c_str(), value.c_str(), replaceExisting);
1602
  }
1603
  bool addHeader(const char *name, long value, bool replaceExisting = true) {
1604
    return addHeader(name, String(value), replaceExisting);
1605
  }
1606
  bool addHeader(const String &name, long value, bool replaceExisting = true) {
1607
    return addHeader(name.c_str(), value, replaceExisting);
1608
  }
1609
  bool removeHeader(const char *name);
1610
  bool removeHeader(const char *name, const char *value);
1611
  const AsyncWebHeader *getHeader(const char *name) const;
1612
  const std::list<AsyncWebHeader> &getHeaders() const {
1613
    return _headers;
1614
  }
1615
 
1616
#ifndef ESP8266
1617
  [[deprecated("Use instead: _assembleHead(String& buffer, uint8_t version)")]]
1618
#endif
1619
  String _assembleHead(uint8_t version) {
1620
    String buffer;
1621
    _assembleHead(buffer, version);
1622
    return buffer;
1623
  }
1624
  void _assembleHead(String &buffer, uint8_t version);
1625
 
1626
  virtual bool _started() const;
1627
  virtual bool _finished() const;
1628
  virtual bool _failed() const;
1629
  virtual bool _sourceValid() const;
1630
  virtual void _respond(AsyncWebServerRequest *request);
1631
 
1632
  /**
1633
   * @brief write next portion of response data to send buffs
1634
   * this method (re)fills tcp send buffers, it could be called either at will
1635
   * or from a tcp_recv/tcp_poll callbacks from AsyncTCP
1636
   *
1637
   * @param request - used to access client object
1638
   * @param len - size of acknowledged data from the remote side (TCP window update, not TCP ack!)
1639
   * @param time - time passed between last sent and received packet
1640
   * @return size_t amount of response data placed to TCP send buffs for delivery (defined by sdkconfig value CONFIG_LWIP_TCP_SND_BUF_DEFAULT)
1641
   */
1642
  virtual size_t _ack(AsyncWebServerRequest *request, size_t len, uint32_t time) {
1643
    return 0;
1644
  };
1645
};
1646
 
1647
/*
1648
 * SERVER :: One instance
1649
 * */
1650
 
1651
typedef std::function<void(AsyncWebServerRequest *request)> ArRequestHandlerFunction;
1652
typedef std::function<void(AsyncWebServerRequest *request, const String &filename, size_t index, uint8_t *data, size_t len, bool final)>
1653
  ArUploadHandlerFunction;
1654
typedef std::function<void(AsyncWebServerRequest *request, uint8_t *data, size_t len, size_t index, size_t total)> ArBodyHandlerFunction;
1655
 
1656
#if ASYNC_JSON_SUPPORT == 1
1657
 
1658
class AsyncCallbackJsonWebHandler;
1659
typedef std::function<void(AsyncWebServerRequest *request, JsonVariant &json)> ArJsonRequestHandlerFunction;
1660
 
1661
#if ASYNC_MSG_PACK_SUPPORT == 1
1662
#ifndef ESP8266
1663
[[deprecated("Replaced by AsyncCallbackJsonWebHandler")]]
1664
#endif
1665
typedef AsyncCallbackJsonWebHandler AsyncCallbackMessagePackWebHandler;
1666
#endif  // ASYNC_MSG_PACK_SUPPORT
1667
 
1668
#endif
1669
 
1670
class AsyncWebServer : public AsyncMiddlewareChain {
1671
protected:
1672
  AsyncServer _server;
1673
  std::list<std::shared_ptr<AsyncWebRewrite>> _rewrites;
1674
  std::list<std::unique_ptr<AsyncWebHandler>> _handlers;
1675
  AsyncCallbackWebHandler *_catchAllHandler;
1676
 
1677
public:
1678
  AsyncWebServer(uint16_t port);
1679
  ~AsyncWebServer();
1680
 
1681
  void begin();
1682
  void end();
1683
 
1684
  tcp_state state() const {
1685
#ifdef ESP8266
1686
    // ESPAsyncTCP and RPAsyncTCP methods are not corrected declared with const for immutable ones.
1687
    return static_cast<tcp_state>(const_cast<AsyncWebServer *>(this)->_server.status());
1688
#else
1689
    return static_cast<tcp_state>(_server.status());
1690
#endif
1691
  }
1692
 
1693
#if ASYNC_TCP_SSL_ENABLED
1694
  void onSslFileRequest(AcSSlFileHandler cb, void *arg);
1695
  void beginSecure(const char *cert, const char *private_key_file, const char *password);
1696
#endif
1697
 
1698
  AsyncWebRewrite &addRewrite(AsyncWebRewrite *rewrite);
1699
 
1700
  /**
1701
     * @brief (compat) Add url rewrite rule by pointer
1702
     * a deep copy of the pointer object will be created,
1703
     * it is up to user to manage further lifetime of the object in argument
1704
     *
1705
     * @param rewrite pointer to rewrite object to copy setting from
1706
     * @return AsyncWebRewrite& reference to a newly created rewrite rule
1707
     */
1708
  AsyncWebRewrite &addRewrite(std::shared_ptr<AsyncWebRewrite> rewrite);
1709
 
1710
  /**
1711
     * @brief add url rewrite rule
1712
     *
1713
     * @param from
1714
     * @param to
1715
     * @return AsyncWebRewrite&
1716
     */
1717
  AsyncWebRewrite &rewrite(const char *from, const char *to);
1718
 
1719
  /**
1720
     * @brief (compat) remove rewrite rule via referenced object
1721
     * this will NOT deallocate pointed object itself, internal rule with same from/to urls will be removed if any
1722
     * it's a compat method, better use `removeRewrite(const char* from, const char* to)`
1723
     * @param rewrite
1724
     * @return true
1725
     * @return false
1726
     */
1727
  bool removeRewrite(AsyncWebRewrite *rewrite);
1728
 
1729
  /**
1730
     * @brief remove rewrite rule
1731
     *
1732
     * @param from
1733
     * @param to
1734
     * @return true
1735
     * @return false
1736
     */
1737
  bool removeRewrite(const char *from, const char *to);
1738
 
1739
  AsyncWebHandler &addHandler(AsyncWebHandler *handler);
1740
  bool removeHandler(AsyncWebHandler *handler);
1741
 
1742
  AsyncCallbackWebHandler &on(AsyncURIMatcher uri, ArRequestHandlerFunction onRequest) {
1743
    return on(std::move(uri), AsyncWebRequestMethod::HTTP_ALL, onRequest);
1744
  }
1745
  AsyncCallbackWebHandler &on(
1746
    AsyncURIMatcher uri, WebRequestMethodComposite method, ArRequestHandlerFunction onRequest, ArUploadHandlerFunction onUpload = nullptr,
1747
    ArBodyHandlerFunction onBody = nullptr
1748
  );
1749
 
1750
#if ASYNC_JSON_SUPPORT == 1
1751
  AsyncCallbackJsonWebHandler &on(AsyncURIMatcher uri, WebRequestMethodComposite method, ArJsonRequestHandlerFunction onBody);
1752
#endif
1753
 
1754
  AsyncStaticWebHandler &serveStatic(const char *uri, fs::FS &fs, const char *path, const char *cache_control = NULL);
1755
 
1756
  void onNotFound(ArRequestHandlerFunction fn);   // called when handler is not assigned
1757
  void onFileUpload(ArUploadHandlerFunction fn);  // handle file uploads
1758
  void onRequestBody(ArBodyHandlerFunction fn);   // handle posts with plain body content (JSON often transmitted this way as a request)
1759
  // give access to the handler used to catch all requests, so that middleware can be added to it
1760
  AsyncWebHandler &catchAllHandler() const;
1761
 
1762
  void reset();  // remove all writers and handlers, with onNotFound/onFileUpload/onRequestBody
1763
 
1764
  void _handleDisconnect(AsyncWebServerRequest *request);
1765
  void _attachHandler(AsyncWebServerRequest *request);
1766
  void _rewriteRequest(AsyncWebServerRequest *request);
1767
};
1768
 
1769
class DefaultHeaders {
1770
  using headers_t = std::list<AsyncWebHeader>;
1771
  headers_t _headers;
1772
 
1773
public:
1774
  DefaultHeaders() = default;
1775
 
1776
  using ConstIterator = headers_t::const_iterator;
1777
 
1778
  void addHeader(const String &name, const String &value) {
1779
    _headers.emplace_back(name, value);
1780
  }
1781
 
1782
  ConstIterator begin() const {
1783
    return _headers.begin();
1784
  }
1785
  ConstIterator end() const {
1786
    return _headers.end();
1787
  }
1788
 
1789
  DefaultHeaders(DefaultHeaders const &) = delete;
1790
  DefaultHeaders &operator=(DefaultHeaders const &) = delete;
1791
 
1792
  static DefaultHeaders &Instance() {
1793
    static DefaultHeaders instance;
1794
    return instance;
1795
  }
1796
};
1797
 
1798
#include "AsyncEventSource.h"
1799
#include "AsyncWebSocket.h"
1800
#include "WebHandlerImpl.h"
1801
#include "WebResponseImpl.h"
1802
 
1803
#if ASYNC_JSON_SUPPORT == 1
1804
#include <AsyncJson.h>
1805
#endif