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
//
5
// AsyncURIMatcher Examples - Advanced URI Matching and Routing
6
//
7
// This example demonstrates the various ways to use AsyncURIMatcher class
8
// for flexible URL routing with different matching strategies:
9
//
10
// 1. Exact matching
11
// 2. Prefix matching
12
// 3. Folder/directory matching
13
// 4. Extension matching
14
// 5. Case insensitive matching
15
// 6. Regex matching (if ASYNCWEBSERVER_REGEX is enabled)
16
// 7. Factory functions for common patterns
17
//
18
// Test URLs:
19
// - Exact: http://192.168.4.1/exact
20
// - Prefix: http://192.168.4.1/prefix-anything
21
// - Folder: http://192.168.4.1/api/users, http://192.168.4.1/api/posts
22
// - Extension: http://192.168.4.1/images/photo.jpg, http://192.168.4.1/docs/readme.pdf
23
// - Case insensitive: http://192.168.4.1/CaSe or http://192.168.4.1/case
24
// - Wildcard: http://192.168.4.1/wildcard-test
25
 
26
#include <Arduino.h>
27
#if defined(ESP32) || defined(LIBRETINY)
28
#include <AsyncTCP.h>
29
#include <WiFi.h>
30
#elif defined(ESP8266)
31
#include <ESP8266WiFi.h>
32
#include <ESPAsyncTCP.h>
33
#elif defined(TARGET_RP2040) || defined(TARGET_RP2350) || defined(PICO_RP2040) || defined(PICO_RP2350)
34
#include <RPAsyncTCP.h>
35
#include <WiFi.h>
36
#endif
37
 
38
#include <ESPAsyncWebServer.h>
39
 
40
static AsyncWebServer server(80);
41
 
42
void setup() {
43
  Serial.begin(115200);
44
  Serial.println();
45
  Serial.println("=== AsyncURIMatcher Example ===");
46
 
47
#if ASYNCWEBSERVER_WIFI_SUPPORTED
48
  WiFi.mode(WIFI_AP);
49
  WiFi.softAP("esp-captive");
50
  Serial.print("AP IP address: ");
51
  Serial.println(WiFi.softAPIP());
52
#endif
53
 
54
  // =============================================================================
55
  // 1. AUTO-DETECTION BEHAVIOR - traditional string-based routing
56
  // =============================================================================
57
 
58
  // Traditional string-based routing with auto-detection
59
  // This uses URIMatchAuto which combines URIMatchPrefixFolder | URIMatchExact
60
  // It will match BOTH "/auto" exactly AND "/auto/" + anything
61
  server.on("/auto", HTTP_GET, [](AsyncWebServerRequest *request) {
62
    Serial.println("Auto-Detection Match (Traditional)");
63
    Serial.println("Matched URL: " + request->url());
64
    Serial.println("Uses auto-detection: exact + folder matching");
65
    request->send(200, "text/plain", "OK - Auto-detection match");
66
  });
67
 
68
  // Auto-detection for wildcard patterns (ends with *)
69
  // This auto-detects as URIMatchPrefix
70
  server.on("/wildcard*", HTTP_GET, [](AsyncWebServerRequest *request) {
71
    Serial.println("Auto-Detected Wildcard (Prefix)");
72
    Serial.println("Matched URL: " + request->url());
73
    Serial.println("Auto-detected as prefix match due to trailing *");
74
    request->send(200, "text/plain", "OK - Wildcard prefix match");
75
  });
76
 
77
  // Auto-detection for extension patterns (contains /*.ext)
78
  // This auto-detects as URIMatchExtension
79
  server.on("/auto-images/*.png", HTTP_GET, [](AsyncWebServerRequest *request) {
80
    Serial.println("Auto-Detected Extension Pattern");
81
    Serial.println("Matched URL: " + request->url());
82
    Serial.println("Auto-detected as extension match due to /*.png pattern");
83
    request->send(200, "text/plain", "OK - Extension match");
84
  });
85
 
86
  // =============================================================================
87
  // 2. EXACT MATCHING - matches only the exact URL (explicit)
88
  // =============================================================================
89
 
90
  // Using factory function for exact match
91
  server.on(AsyncURIMatcher::exact("/exact"), HTTP_GET, [](AsyncWebServerRequest *request) {
92
    Serial.println("Factory Exact Match");
93
    Serial.println("Matched URL: " + request->url());
94
    Serial.println("Uses AsyncURIMatcher::exact() factory function");
95
    request->send(200, "text/plain", "OK - Factory exact match");
96
  });
97
 
98
  // =============================================================================
99
  // 3. PREFIX MATCHING - matches URLs that start with the pattern
100
  // =============================================================================
101
 
102
  // Using factory function for prefix match
103
  server.on(AsyncURIMatcher::prefix("/service"), HTTP_GET, [](AsyncWebServerRequest *request) {
104
    Serial.println("Service Prefix Match (Factory)");
105
    Serial.println("Matched URL: " + request->url());
106
    Serial.println("Uses AsyncURIMatcher::prefix() factory function");
107
    request->send(200, "text/plain", "OK - Factory prefix match");
108
  });
109
 
110
  // =============================================================================
111
  // 4. FOLDER/DIRECTORY MATCHING - matches URLs in a folder structure
112
  // =============================================================================
113
 
114
  // Folder match using factory function (automatically adds trailing slash)
115
  server.on(AsyncURIMatcher::dir("/admin"), HTTP_GET, [](AsyncWebServerRequest *request) {
116
    Serial.println("Admin Directory Match");
117
    Serial.println("Matched URL: " + request->url());
118
    Serial.println("This matches URLs under /admin/ directory");
119
    Serial.println("Note: /admin (without slash) will NOT match");
120
    request->send(200, "text/plain", "OK - Directory match");
121
  });
122
 
123
  // =============================================================================
124
  // 5. EXTENSION MATCHING - matches files with specific extensions
125
  // =============================================================================
126
 
127
  // Image extension matching
128
  server.on(AsyncURIMatcher::ext("/images/*.jpg"), HTTP_GET, [](AsyncWebServerRequest *request) {
129
    Serial.println("JPG Image Handler");
130
    Serial.println("Matched URL: " + request->url());
131
    Serial.println("This matches any .jpg file under /images/");
132
    request->send(200, "text/plain", "OK - Extension match");
133
  });
134
 
135
  // =============================================================================
136
  // 6. CASE INSENSITIVE MATCHING
137
  // =============================================================================
138
 
139
  // Case insensitive exact match
140
  server.on(AsyncURIMatcher::exact("/case", AsyncURIMatcher::CaseInsensitive), HTTP_GET, [](AsyncWebServerRequest *request) {
141
    Serial.println("Case Insensitive Match");
142
    Serial.println("Matched URL: " + request->url());
143
    Serial.println("This matches /case in any case combination");
144
    request->send(200, "text/plain", "OK - Case insensitive match");
145
  });
146
 
147
#ifdef ASYNCWEBSERVER_REGEX
148
  // =============================================================================
149
  // 7. REGEX MATCHING (only available if ASYNCWEBSERVER_REGEX is enabled)
150
  // =============================================================================
151
 
152
  // Regex match for numeric IDs
153
  server.on(AsyncURIMatcher::regex("^/user/([0-9]+)$"), HTTP_GET, [](AsyncWebServerRequest *request) {
154
    Serial.println("Regex Match - User ID");
155
    Serial.println("Matched URL: " + request->url());
156
    if (request->pathArg(0).length() > 0) {
157
      Serial.println("Captured User ID: " + request->pathArg(0));
158
    }
159
    Serial.println("This regex matches /user/{number} pattern");
160
    request->send(200, "text/plain", "OK - Regex match");
161
  });
162
#endif
163
 
164
  // =============================================================================
165
  // 8. COMBINED FLAGS EXAMPLE
166
  // =============================================================================
167
 
168
  // Combine multiple flags
169
  server.on(AsyncURIMatcher::prefix("/MixedCase", AsyncURIMatcher::CaseInsensitive), HTTP_GET, [](AsyncWebServerRequest *request) {
170
    Serial.println("Combined Flags Example");
171
    Serial.println("Matched URL: " + request->url());
172
    Serial.println("Uses both AsyncURIMatcher::Prefix and AsyncURIMatcher::CaseInsensitive");
173
    request->send(200, "text/plain", "OK - Combined flags match");
174
  });
175
 
176
  // =============================================================================
177
  // 9. HOMEPAGE WITH NAVIGATION
178
  // =============================================================================
179
 
180
  server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
181
    Serial.println("Homepage accessed");
182
    String response = R"(<!DOCTYPE html>
183
<html>
184
<head>
185
  <title>AsyncURIMatcher Examples</title>
186
  <style>
187
    body { font-family: Arial, sans-serif; margin: 20px; }
188
    h1 { color: #2E86AB; }
189
    .test-link { display: block; margin: 5px 0; padding: 8px; background: #f0f0f0; text-decoration: none; color: #333; border-radius: 4px; }
190
    .test-link:hover { background: #e0e0e0; }
191
    .section { margin: 20px 0; }
192
  </style>
193
</head>
194
<body>
195
  <h1>AsyncURIMatcher Examples</h1>
196
 
197
  <div class="section">
198
    <h3>Auto-Detection (Traditional String Matching)</h3>
199
    <a href="/auto" class="test-link">/auto (auto-detection: exact + folder)</a>
200
    <a href="/auto/sub" class="test-link">/auto/sub (folder match)</a>
201
    <a href="/wildcard-test" class="test-link">/wildcard-test (auto prefix)</a>
202
    <a href="/auto-images/photo.png" class="test-link">/auto-images/photo.png (auto extension)</a>
203
  </div>
204
 
205
  <div class="section">
206
    <h3>Factory Method Examples</h3>
207
    <a href="/exact" class="test-link">/exact (factory exact)</a>
208
    <a href="/service/status" class="test-link">/service/status (factory prefix)</a>
209
    <a href="/admin/users" class="test-link">/admin/users (factory directory)</a>
210
    <a href="/images/photo.jpg" class="test-link">/images/photo.jpg (factory extension)</a>
211
  </div>
212
 
213
  <div class="section">
214
    <h3>Case Insensitive Matching</h3>
215
    <a href="/case" class="test-link">/case (lowercase)</a>
216
    <a href="/CASE" class="test-link">/CASE (uppercase)</a>
217
    <a href="/CaSe" class="test-link">/CaSe (mixed case)</a>
218
  </div>
219
 
220
)";
221
#ifdef ASYNCWEBSERVER_REGEX
222
    response += R"(  <div class="section">
223
    <h3>Regex Matching</h3>
224
    <a href="/user/123" class="test-link">/user/123 (regex numeric ID)</a>
225
    <a href="/user/456" class="test-link">/user/456 (regex numeric ID)</a>
226
  </div>
227
 
228
)";
229
#endif
230
    response += R"(  <div class="section">
231
    <h3>Combined Flags</h3>
232
    <a href="/mixedcase-test" class="test-link">/mixedcase-test (prefix + case insensitive)</a>
233
    <a href="/MIXEDCASE/sub" class="test-link">/MIXEDCASE/sub (prefix + case insensitive)</a>
234
  </div>
235
 
236
</body>
237
</html>)";
238
    request->send(200, "text/html", response);
239
  });
240
 
241
  // =============================================================================
242
  // 10. NOT FOUND HANDLER
243
  // =============================================================================
244
 
245
  server.onNotFound([](AsyncWebServerRequest *request) {
246
    String html = "<h1>404 - Not Found</h1>";
247
    html += "<p>The requested URL <strong>" + request->url() + "</strong> was not found.</p>";
248
    html += "<p><a href='/'>← Back to Examples</a></p>";
249
    request->send(404, "text/html", html);
250
  });
251
 
252
  server.begin();
253
 
254
  Serial.println();
255
  Serial.println("=== Server Started ===");
256
  Serial.println("Open your browser and navigate to:");
257
  Serial.println("http://192.168.4.1/ - Main examples page");
258
  Serial.println();
259
  Serial.println("Available test endpoints:");
260
  Serial.println("• Auto-detection: /auto (exact+folder), /wildcard*, /auto-images/*.png");
261
  Serial.println("• Exact matches: /exact");
262
  Serial.println("• Prefix matches: /service*");
263
  Serial.println("• Folder matches: /admin/*");
264
  Serial.println("• Extension matches: /images/*.jpg");
265
  Serial.println("• Case insensitive: /case (try /CASE, /Case)");
266
#ifdef ASYNCWEBSERVER_REGEX
267
  Serial.println("• Regex matches: /user/123");
268
#endif
269
  Serial.println("• Combined flags: /mixedcase*");
270
  Serial.println();
271
}
272
 
273
void loop() {
274
  // Nothing to do here - the server handles everything asynchronously
275
  delay(1000);
276
}