Skip to content

Commit 281d596

Browse files
committed
Introduce AsyncURIMatcher class to encapsulate the URI matching logic with and without regex support (-D ASYNCWEBSERVER_REGEX=1)
1 parent 2809b8d commit 281d596

File tree

11 files changed

+1076
-62
lines changed

11 files changed

+1076
-62
lines changed

examples/URIMatcher/README.md

Lines changed: 240 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
# AsyncURIMatcher Example
2+
3+
This example demonstrates the comprehensive URI matching capabilities of the ESPAsyncWebServer library using the `AsyncURIMatcher` class.
4+
5+
## Overview
6+
7+
The `AsyncURIMatcher` class provides flexible and powerful URL routing mechanisms that go beyond simple string matching. It supports various matching strategies that can be combined to create sophisticated routing rules.
8+
9+
**Important**: When using plain strings (not `AsyncURIMatcher` objects), the library uses auto-detection (`URIMatchAuto`) which analyzes the URI pattern and applies appropriate matching rules. This is **not** simple exact matching - it combines exact and folder matching by default!
10+
11+
## Auto-Detection Behavior
12+
13+
When you pass a plain string or `const char*` to `server.on()`, the `URIMatchAuto` flag is used, which:
14+
15+
1. **Empty URI**: Matches everything
16+
2. **Ends with `*`**: Becomes prefix match (`URIMatchPrefix`)
17+
3. **Contains `/*.ext`**: Becomes extension match (`URIMatchExtension`)
18+
4. **Starts with `^` and ends with `$`**: Becomes regex match (if enabled)
19+
5. **Everything else**: Becomes **both** exact and folder match (`URIMatchPrefixFolder | URIMatchExact`)
20+
21+
This means traditional string-based routes like `server.on("/path", handler)` will match:
22+
- `/path` (exact match)
23+
- `/path/anything` (folder match)
24+
25+
But will **NOT** match `/path-suffix` (prefix without folder separator).
26+
27+
## Features Demonstrated
28+
29+
### 1. **Auto-Detection (Traditional Behavior)**
30+
- When using plain strings, automatically detects the appropriate matching strategy
31+
- Default behavior: combines exact and folder matching
32+
- Special patterns: `*` suffix → prefix, `/*.ext` → extension, regex patterns
33+
- Use cases: Traditional ESP32 web server behavior with enhanced capabilities
34+
- Examples: `/path` matches both `/path` and `/path/sub`
35+
36+
### 2. **Exact Matching**
37+
- Matches only the exact URL specified
38+
- Use cases: API endpoints, specific pages
39+
- Examples: `/exact`, `/login`, `/dashboard`
40+
41+
### 3. **Prefix Matching**
42+
- Matches URLs that start with the specified pattern
43+
- Use cases: API versioning, module grouping
44+
- Examples: `/api*` matches `/api/users`, `/api/posts`, etc.
45+
46+
### 4. **Folder/Directory Matching**
47+
- Matches URLs under a specific directory path
48+
- Use cases: Admin sections, organized content
49+
- Examples: `/admin/` matches `/admin/users`, `/admin/settings`
50+
51+
### 5. **Extension Matching**
52+
- Matches files with specific extensions under a path
53+
- Use cases: Static file serving, file type handlers
54+
- Examples: `/images/*.jpg` matches any `.jpg` file under `/images/`
55+
56+
### 6. **Case Insensitive Matching**
57+
- Matches URLs regardless of character case
58+
- Use cases: User-friendly URLs, legacy support
59+
- Examples: `/CaSe` matches `/case`, `/CASE`, etc.
60+
61+
### 7. **Regular Expression Matching**
62+
- Advanced pattern matching using regex (requires `ASYNCWEBSERVER_REGEX`)
63+
- Use cases: Complex URL patterns, parameter extraction
64+
- Examples: `/user/([0-9]+)` matches `/user/123` and captures the ID
65+
66+
### 8. **Combined Flags**
67+
- Multiple matching strategies can be combined
68+
- Use cases: Flexible routing requirements
69+
- Examples: Case-insensitive prefix matching
70+
71+
## Usage Patterns
72+
73+
### Traditional String-based Routing (Auto-Detection)
74+
```cpp
75+
// Auto-detection with exact + folder matching
76+
server.on("/api", handler); // Matches /api AND /api/anything
77+
server.on("/login", handler); // Matches /login AND /login/sub
78+
79+
// Auto-detection with prefix matching
80+
server.on("/prefix*", handler); // Matches /prefix, /prefix-test, /prefix/sub
81+
82+
// Auto-detection with extension matching
83+
server.on("/images/*.jpg", handler); // Matches /images/pic.jpg, /images/sub/pic.jpg
84+
```
85+
86+
### Explicit AsyncURIMatcher Syntax
87+
### Explicit AsyncURIMatcher Syntax
88+
```cpp
89+
// Exact matching only
90+
server.on(AsyncURIMatcher("/path", URIMatchExact), handler);
91+
92+
// Prefix matching only
93+
server.on(AsyncURIMatcher("/api", URIMatchPrefix), handler);
94+
95+
// Combined flags
96+
server.on(AsyncURIMatcher("/api", URIMatchPrefix | URIMatchCaseInsensitive), handler);
97+
```
98+
99+
### Factory Functions
100+
```cpp
101+
// More readable and expressive
102+
server.on(AsyncURIMatcher::exact("/login"), handler);
103+
server.on(AsyncURIMatcher::prefix("/api"), handler);
104+
server.on(AsyncURIMatcher::dir("/admin"), handler);
105+
server.on(AsyncURIMatcher::ext("/images/*.jpg"), handler);
106+
server.on(AsyncURIMatcher::iExact("/case"), handler);
107+
108+
#ifdef ASYNCWEBSERVER_REGEX
109+
server.on(AsyncURIMatcher::regex("^/user/([0-9]+)$"), handler);
110+
#endif
111+
```
112+
113+
## Available Flags
114+
115+
| Flag | Description |
116+
|------|-------------|
117+
| `URIMatchAuto` | Auto-detect match type from pattern (default) |
118+
| `URIMatchExact` | Exact URL match |
119+
| `URIMatchPrefix` | Prefix match |
120+
| `URIMatchPrefixFolder` | Folder prefix match (requires trailing /) |
121+
| `URIMatchExtension` | File extension match pattern |
122+
| `URIMatchCaseInsensitive` | Case insensitive matching |
123+
| `URIMatchRegex` | Regular expression matching (requires ASYNCWEBSERVER_REGEX) |
124+
125+
## Testing the Example
126+
127+
1. **Upload the sketch** to your ESP32/ESP8266
128+
2. **Connect to WiFi AP**: `esp-captive` (no password required)
129+
3. **Navigate to**: `http://192.168.4.1/`
130+
4. **Explore the examples** by clicking the organized test links
131+
5. **Monitor Serial output**: Open Serial Monitor to see detailed debugging information for each matched route
132+
133+
### Test URLs Available (All Clickable from Homepage)
134+
135+
**Auto-Detection Examples:**
136+
- `http://192.168.4.1/auto` (exact + folder match)
137+
- `http://192.168.4.1/auto/sub` (folder match - same handler!)
138+
- `http://192.168.4.1/wildcard-test` (auto-detected prefix)
139+
- `http://192.168.4.1/auto-images/photo.png` (auto-detected extension)
140+
141+
**Factory Method Examples:**
142+
- `http://192.168.4.1/exact` (AsyncURIMatcher::exact)
143+
- `http://192.168.4.1/service/status` (AsyncURIMatcher::prefix)
144+
- `http://192.168.4.1/admin/users` (AsyncURIMatcher::dir)
145+
- `http://192.168.4.1/images/photo.jpg` (AsyncURIMatcher::ext)
146+
147+
**Case Insensitive Examples:**
148+
- `http://192.168.4.1/case` (lowercase)
149+
- `http://192.168.4.1/CASE` (uppercase)
150+
- `http://192.168.4.1/CaSe` (mixed case)
151+
152+
**Regex Examples (if ASYNCWEBSERVER_REGEX enabled):**
153+
- `http://192.168.4.1/user/123` (captures numeric ID)
154+
- `http://192.168.4.1/user/456` (captures numeric ID)
155+
156+
**Combined Flags Examples:**
157+
- `http://192.168.4.1/mixedcase-test` (prefix + case insensitive)
158+
- `http://192.168.4.1/MIXEDCASE/sub` (prefix + case insensitive)
159+
160+
### Console Output
161+
162+
Each handler provides detailed debugging information via Serial output:
163+
```
164+
Auto-Detection Match (Traditional)
165+
Matched URL: /auto
166+
Uses auto-detection: exact + folder matching
167+
```
168+
169+
```
170+
Factory Exact Match
171+
Matched URL: /exact
172+
Uses AsyncURIMatcher::exact() factory function
173+
```
174+
175+
```
176+
Regex Match - User ID
177+
Matched URL: /user/123
178+
Captured User ID: 123
179+
This regex matches /user/{number} pattern
180+
```
181+
182+
## Compilation Options
183+
184+
### Enable Regex Support
185+
To enable regular expression matching, compile with:
186+
```
187+
-D ASYNCWEBSERVER_REGEX
188+
```
189+
190+
In PlatformIO, add to `platformio.ini`:
191+
```ini
192+
build_flags = -D ASYNCWEBSERVER_REGEX
193+
```
194+
195+
In Arduino IDE, add to your sketch:
196+
```cpp
197+
#define ASYNCWEBSERVER_REGEX
198+
```
199+
200+
## Performance Considerations
201+
202+
1. **Exact matches** are fastest
203+
2. **Prefix matches** are very efficient
204+
3. **Regex matches** are slower but most flexible
205+
4. **Case insensitive** matching adds minimal overhead
206+
5. **Auto-detection** adds slight parsing overhead at construction time
207+
208+
## Real-World Applications
209+
210+
### REST API Design
211+
```cpp
212+
// API versioning
213+
server.on(AsyncURIMatcher::prefix("/api/v1"), handleAPIv1);
214+
server.on(AsyncURIMatcher::prefix("/api/v2"), handleAPIv2);
215+
216+
// Resource endpoints with IDs
217+
server.on(AsyncURIMatcher::regex("^/api/users/([0-9]+)$"), handleUserById);
218+
server.on(AsyncURIMatcher::regex("^/api/posts/([0-9]+)/comments$"), handlePostComments);
219+
```
220+
221+
### File Serving
222+
```cpp
223+
// Serve different file types
224+
server.on(AsyncURIMatcher::ext("/assets/*.css"), serveCSSFiles);
225+
server.on(AsyncURIMatcher::ext("/assets/*.js"), serveJSFiles);
226+
server.on(AsyncURIMatcher::ext("/images/*.jpg"), serveImageFiles);
227+
```
228+
229+
### Admin Interface
230+
```cpp
231+
// Admin section with authentication
232+
server.on(AsyncURIMatcher::dir("/admin"), handleAdminPages);
233+
server.on(AsyncURIMatcher::exact("/admin"), redirectToAdminDashboard);
234+
```
235+
236+
## See Also
237+
238+
- [ESPAsyncWebServer Documentation](https://github.com/ESP32Async/ESPAsyncWebServer)
239+
- [Regular Expression Reference](https://en.cppreference.com/w/cpp/regex)
240+
- Other examples in the `examples/` directory

0 commit comments

Comments
 (0)