chore: vendor sglang v0.5.10 snapshot

This commit is contained in:
2026-04-24 12:29:36 +00:00
parent 78f0d15221
commit bded08301f
4308 changed files with 1200894 additions and 2 deletions

View File

@@ -0,0 +1,27 @@
# Rust build artifacts
target/
**/target/
# Cargo lock files (examples don't need locked dependencies)
Cargo.lock
**/Cargo.lock
# Generated WASM files
*.wasm
*.component.wasm
**/*.wasm
**/*.component.wasm
# Build scripts output
build/
# IDE files
.idea/
.vscode/
*.swp
*.swo
*~
# OS files
.DS_Store
Thumbs.db

View File

@@ -0,0 +1,102 @@
# WASM Guest Examples for sgl-model-gateway
This directory contains example WASM middleware components demonstrating how to implement custom middleware for sgl-model-gateway using the WebAssembly Component Model.
## Examples Overview
### [wasm-guest-auth](./wasm-guest-auth/)
API key authentication middleware that validates API keys for requests to `/api` and `/v1` paths.
**Features:**
- Validates API keys from `Authorization` header or `x-api-key` header
- Returns `401 Unauthorized` for missing or invalid keys
- Attach point: `OnRequest` only
**Use case:** Protect API endpoints with API key authentication.
### [wasm-guest-logging](./wasm-guest-logging/)
Request tracking and status code conversion middleware.
**Features:**
- Adds tracking headers (`x-request-id`, `x-wasm-processed`, `x-processed-at`, `x-api-route`)
- Converts `500` errors to `503` for better client handling
- Attach points: `OnRequest` and `OnResponse`
**Use case:** Request tracing and error status code conversion.
### [wasm-guest-ratelimit](./wasm-guest-ratelimit/)
Rate limiting middleware with configurable limits.
**Features:**
- Rate limiting per identifier (API Key, IP, or Request ID)
- Default: 60 requests per minute
- Returns `429 Too Many Requests` when limit exceeded
- Attach point: `OnRequest` only
**Note:** This is a simplified demonstration with per-instance state. For production, use router-level rate limiting with shared state.
**Use case:** Protect against request flooding and abuse.
## Quick Start
Each example includes its own README with detailed build and deployment instructions. See individual example directories for:
- Build instructions
- Deployment configuration
- Customization options
- Testing examples
## Common Prerequisites
All examples require:
- Rust toolchain (latest stable)
- `wasm32-wasip2` target: `rustup target add wasm32-wasip2`
- `wasm-tools`: `cargo install wasm-tools`
- sgl-model-gateway running with WASM enabled (`--enable-wasm`)
## Building All Examples
```bash
cd examples/wasm
for example in wasm-guest-auth wasm-guest-logging wasm-guest-ratelimit; do
echo "Building $example..."
cd $example && ./build.sh && cd ..
done
```
## Deploying Multiple Modules
You can deploy all three modules together:
```bash
curl -X POST http://localhost:3000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [
{
"name": "auth-middleware",
"file_path": "/path/to/wasm_guest_auth.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
},
{
"name": "logging-middleware",
"file_path": "/path/to/wasm_guest_logging.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}, {"Middleware": "OnResponse"}]
},
{
"name": "ratelimit-middleware",
"file_path": "/path/to/wasm_guest_ratelimit.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
}
]
}'
```
Modules execute in the order they are deployed. If a module returns `Reject`, subsequent modules won't execute.

View File

@@ -0,0 +1,10 @@
[package]
name = "wasm-guest-auth"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wit-bindgen = { version = "0.21", features = ["macros"] }

View File

@@ -0,0 +1,62 @@
# WASM Auth Example for sgl-model-gateway
This example demonstrates API key authentication middleware for sgl-model-gateway using the WebAssembly Component Model.
## Overview
This middleware validates API keys for requests to `/api` and `/v1` paths:
- Supports `Authorization: Bearer <key>` header
- Supports `Authorization: ApiKey <key>` header
- Supports `x-api-key` header
- Returns `401 Unauthorized` for missing or invalid keys
**Default API Key**: `secret-api-key-12345`
## Quick Start
### Build and Deploy
```bash
# Build
cd examples/wasm-guest-auth
./build.sh
# Deploy (replace file_path with actual path)
curl -X POST http://localhost:3000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [{
"name": "auth-middleware",
"file_path": "/absolute/path/to/wasm_guest_auth.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
}]
}'
```
### Customization
Modify `EXPECTED_API_KEY` in `src/lib.rs`:
```rust
const EXPECTED_API_KEY: &str = "your-secret-key";
```
## Testing
```bash
# Test unauthorized (returns 401)
curl -v http://localhost:3000/api/test
# Test authorized (passes)
curl -v http://localhost:3000/api/test \
-H "Authorization: Bearer secret-api-key-12345"
```
## Troubleshooting
- Verify API key matches `EXPECTED_API_KEY` in code
- Check request header format and path (`/api` or `/v1`)
- Verify module is attached to `OnRequest` phase
- Check router logs for errors

View File

@@ -0,0 +1,77 @@
#!/bin/bash
# Build script for WASM guest auth example
# This script simplifies the build process for the WASM middleware component
set -e
echo "Building WASM guest auth example..."
# Check if we're in the right directory
if [ ! -f "Cargo.toml" ]; then
echo "Error: Cargo.toml not found. Please run this script from the wasm-guest-auth directory."
exit 1
fi
# Check for required tools
command -v cargo >/dev/null 2>&1 || { echo "Error: cargo is required but not installed. Aborting." >&2; exit 1; }
# Check and install wasm32-wasip2 target
echo "Checking for wasm32-wasip2 target..."
if ! rustup target list --installed | grep -q "wasm32-wasip2"; then
echo "wasm32-wasip2 target not found. Installing..."
rustup target add wasm32-wasip2
echo "✓ wasm32-wasip2 target installed"
else
echo "✓ wasm32-wasip2 target already installed"
fi
# Check for wasm-tools
if ! command -v wasm-tools >/dev/null 2>&1; then
echo "Error: wasm-tools is required but not installed."
echo "Install it with: cargo install wasm-tools"
exit 1
fi
# Build with cargo (wit-bindgen uses cargo, not wasm-pack)
echo "Running cargo build..."
cargo build --target wasm32-wasip2 --release
# Output locations
WASM_MODULE="target/wasm32-wasip2/release/wasm_guest_auth.wasm"
WASM_COMPONENT="target/wasm32-wasip2/release/wasm_guest_auth.component.wasm"
if [ ! -f "$WASM_MODULE" ]; then
echo "Error: Build failed - WASM module not found"
exit 1
fi
# Check if the file is already a component
echo "Checking WASM file format..."
if wasm-tools print "$WASM_MODULE" 2>/dev/null | grep -q "^(\s*component"; then
echo "✓ WASM file is already in component format"
# Copy to component path for consistency
cp "$WASM_MODULE" "$WASM_COMPONENT"
else
# Wrap the WASM module into a component format
echo "Wrapping WASM module into component format..."
wasm-tools component new "$WASM_MODULE" -o "$WASM_COMPONENT"
if [ ! -f "$WASM_COMPONENT" ]; then
echo "Error: Failed to create component file"
exit 1
fi
fi
if [ -f "$WASM_COMPONENT" ]; then
echo ""
echo "✓ Build successful!"
echo " WASM module: $WASM_MODULE"
echo " WASM component: $WASM_COMPONENT"
echo ""
echo "Next steps:"
echo "1. Use the component file ($WASM_COMPONENT) when adding the module"
echo "2. Prepare the module configuration (see README.md for JSON format)"
echo "3. Use the API endpoint to add the module (see README.md for details)"
else
echo "Error: Component file not found"
exit 1
fi

View File

@@ -0,0 +1,70 @@
//! WASM Guest Auth Example for sgl-model-gateway
//!
//! This example demonstrates API key authentication middleware
//! for sgl-model-gateway using the WebAssembly Component Model.
//!
//! Features:
//! - API Key authentication
wit_bindgen::generate!({
path: "../../../src/wasm/interface",
world: "sgl-model-gateway",
});
use exports::sgl::model_gateway::{
middleware_on_request::Guest as OnRequestGuest,
middleware_on_response::Guest as OnResponseGuest,
};
use sgl::model_gateway::middleware_types::{Action, Request, Response};
/// Expected API Key (in production, this should be passed as configuration)
const EXPECTED_API_KEY: &str = "secret-api-key-12345";
/// Main middleware implementation
struct Middleware;
// Helper function to find header value
fn find_header_value(
headers: &[sgl::model_gateway::middleware_types::Header],
name: &str,
) -> Option<String> {
headers
.iter()
.find(|h| h.name.eq_ignore_ascii_case(name))
.map(|h| h.value.clone())
}
// Implement on-request interface
impl OnRequestGuest for Middleware {
fn on_request(req: Request) -> Action {
// API Key Authentication
// Check for API key in Authorization header for /api routes
if req.path.starts_with("/api") || req.path.starts_with("/v1") {
let api_key = find_header_value(&req.headers, "authorization")
.and_then(|h| {
h.strip_prefix("Bearer ")
.or_else(|| h.strip_prefix("ApiKey "))
.map(|s| s.to_string())
})
.or_else(|| find_header_value(&req.headers, "x-api-key"));
// Reject if API key is missing or invalid
if api_key.as_deref() != Some(EXPECTED_API_KEY) {
return Action::Reject(401);
}
}
// Authentication passed, continue processing
Action::Continue
}
}
// Implement on-response interface (empty - not used for auth)
impl OnResponseGuest for Middleware {
fn on_response(_resp: Response) -> Action {
Action::Continue
}
}
// Export the component
export!(Middleware);

View File

@@ -0,0 +1,10 @@
[package]
name = "wasm-guest-logging"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wit-bindgen = { version = "0.21", features = ["macros"] }

View File

@@ -0,0 +1,53 @@
# WASM Logging Example for sgl-model-gateway
This example demonstrates logging and tracing middleware for sgl-model-gateway using the WebAssembly Component Model.
## Overview
This middleware provides:
- **Request Tracking** - Adds tracking headers (`x-request-id`, `x-wasm-processed`, `x-processed-at`, `x-api-route`)
- **Status Code Conversion** - Converts `500` errors to `503`
## Quick Start
### Build and Deploy
```bash
# Build
cd examples/wasm-guest-logging
./build.sh
# Deploy (replace file_path with actual path)
curl -X POST http://localhost:3000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [{
"name": "logging-middleware",
"file_path": "/absolute/path/to/wasm_guest_logging.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}, {"Middleware": "OnResponse"}]
}]
}'
```
### Customization
Modify `on_request` or `on_response` functions in `src/lib.rs` to add custom tracking headers or status code conversions.
## Testing
```bash
# Check tracking headers
curl -v http://localhost:3000/v1/models 2>&1 | \
grep -E "(x-request-id|x-wasm-processed|x-processed-at)"
# Test status code conversion (requires endpoint returning 500)
curl -v http://localhost:3000/some-endpoint 2>&1 | grep -E "(< HTTP|500|503)"
```
## Troubleshooting
- Verify module attached to both `OnRequest` and `OnResponse` phases
- Check router logs for execution errors
- Ensure module built successfully

View File

@@ -0,0 +1,77 @@
#!/bin/bash
# Build script for WASM guest logging example
# This script simplifies the build process for the WASM middleware component
set -e
echo "Building WASM guest logging example..."
# Check if we're in the right directory
if [ ! -f "Cargo.toml" ]; then
echo "Error: Cargo.toml not found. Please run this script from the wasm-guest-logging directory."
exit 1
fi
# Check for required tools
command -v cargo >/dev/null 2>&1 || { echo "Error: cargo is required but not installed. Aborting." >&2; exit 1; }
# Check and install wasm32-wasip2 target
echo "Checking for wasm32-wasip2 target..."
if ! rustup target list --installed | grep -q "wasm32-wasip2"; then
echo "wasm32-wasip2 target not found. Installing..."
rustup target add wasm32-wasip2
echo "✓ wasm32-wasip2 target installed"
else
echo "✓ wasm32-wasip2 target already installed"
fi
# Check for wasm-tools
if ! command -v wasm-tools >/dev/null 2>&1; then
echo "Error: wasm-tools is required but not installed."
echo "Install it with: cargo install wasm-tools"
exit 1
fi
# Build with cargo (wit-bindgen uses cargo, not wasm-pack)
echo "Running cargo build..."
cargo build --target wasm32-wasip2 --release
# Output locations
WASM_MODULE="target/wasm32-wasip2/release/wasm_guest_logging.wasm"
WASM_COMPONENT="target/wasm32-wasip2/release/wasm_guest_logging.component.wasm"
if [ ! -f "$WASM_MODULE" ]; then
echo "Error: Build failed - WASM module not found"
exit 1
fi
# Check if the file is already a component
echo "Checking WASM file format..."
if wasm-tools print "$WASM_MODULE" 2>/dev/null | grep -q "^(\s*component"; then
echo "✓ WASM file is already in component format"
# Copy to component path for consistency
cp "$WASM_MODULE" "$WASM_COMPONENT"
else
# Wrap the WASM module into a component format
echo "Wrapping WASM module into component format..."
wasm-tools component new "$WASM_MODULE" -o "$WASM_COMPONENT"
if [ ! -f "$WASM_COMPONENT" ]; then
echo "Error: Failed to create component file"
exit 1
fi
fi
if [ -f "$WASM_COMPONENT" ]; then
echo ""
echo "✓ Build successful!"
echo " WASM module: $WASM_MODULE"
echo " WASM component: $WASM_COMPONENT"
echo ""
echo "Next steps:"
echo "1. Use the component file ($WASM_COMPONENT) when adding the module"
echo "2. Prepare the module configuration (see README.md for JSON format)"
echo "3. Use the API endpoint to add the module (see README.md for details)"
else
echo "Error: Component file not found"
exit 1
fi

View File

@@ -0,0 +1,88 @@
//! WASM Guest Logging Example for sgl-model-gateway
//!
//! This example demonstrates logging and tracing middleware
//! for sgl-model-gateway using the WebAssembly Component Model.
//!
//! Features:
//! - Request tracking and tracing headers
//! - Response status code conversion
wit_bindgen::generate!({
path: "../../../src/wasm/interface",
world: "sgl-model-gateway",
});
use exports::sgl::model_gateway::{
middleware_on_request::Guest as OnRequestGuest,
middleware_on_response::Guest as OnResponseGuest,
};
use sgl::model_gateway::middleware_types::{Action, Header, ModifyAction, Request, Response};
/// Main middleware implementation
struct Middleware;
// Helper function to create header
fn create_header(name: &str, value: &str) -> Header {
Header {
name: name.to_string(),
value: value.to_string(),
}
}
// Implement on-request interface
impl OnRequestGuest for Middleware {
fn on_request(req: Request) -> Action {
let mut modify_action = ModifyAction {
status: None,
headers_set: vec![],
headers_add: vec![],
headers_remove: vec![],
body_replace: None,
};
// Request Logging and Tracing
// Add tracing headers with request ID
modify_action
.headers_add
.push(create_header("x-request-id", &req.request_id));
modify_action
.headers_add
.push(create_header("x-wasm-processed", "true"));
modify_action.headers_add.push(create_header(
"x-processed-at",
&req.now_epoch_ms.to_string(),
));
// Add custom header for API requests
if req.path.starts_with("/api") || req.path.starts_with("/v1") {
modify_action
.headers_add
.push(create_header("x-api-route", "true"));
}
Action::Modify(modify_action)
}
}
// Implement on-response interface
impl OnResponseGuest for Middleware {
fn on_response(resp: Response) -> Action {
// Status code conversion: Convert 500 to 503 for better client handling
if resp.status == 500 {
let modify_action = ModifyAction {
status: Some(503),
headers_set: vec![],
headers_add: vec![],
headers_remove: vec![],
body_replace: None,
};
Action::Modify(modify_action)
} else {
// No modification needed
Action::Continue
}
}
}
// Export the component
export!(Middleware);

View File

@@ -0,0 +1,10 @@
[package]
name = "wasm-guest-ratelimit"
version = "0.1.0"
edition = "2021"
[lib]
crate-type = ["cdylib"]
[dependencies]
wit-bindgen = { version = "0.21", features = ["macros"] }

View File

@@ -0,0 +1,68 @@
# WASM Rate Limit Example for sgl-model-gateway
This example demonstrates rate limiting middleware for sgl-model-gateway using the WebAssembly Component Model.
## Overview
This middleware provides rate limiting:
- **Default**: 60 requests per minute per identifier
- **Identifier Priority**: API Key > IP Address > Request ID
- **Response**: Returns `429 Too Many Requests` when limit exceeded
**Important**: This is a simplified demonstration. Since WASM components are stateless, each worker thread maintains its own counter. For production, implement rate limiting at the router/host level with shared state.
## Quick Start
### Build and Deploy
```bash
# Build
cd examples/wasm-guest-ratelimit
./build.sh
# Deploy (replace file_path with actual path)
curl -X POST http://localhost:3000/wasm \
-H "Content-Type: application/json" \
-d '{
"modules": [{
"name": "ratelimit-middleware",
"file_path": "/absolute/path/to/wasm_guest_ratelimit.component.wasm",
"module_type": "Middleware",
"attach_points": [{"Middleware": "OnRequest"}]
}]
}'
```
### Customization
Modify constants in `src/lib.rs`:
```rust
const RATE_LIMIT_REQUESTS: u64 = 100; // requests per window
const RATE_LIMIT_WINDOW_MS: u64 = 60_000; // time window in ms
```
## Testing
```bash
# Send multiple requests (first 60 succeed, then 429)
for i in {1..65}; do
curl -s -o /dev/null -w "%{http_code}\n" \
http://localhost:3000/v1/models \
-H "Authorization: Bearer secret-api-key-12345"
done
```
## Limitations
- Per-instance state (not shared across workers)
- No cross-process state sharing
- Memory growth with unique identifiers
- State lost on instance restart
## Troubleshooting
- Verify module attached to `OnRequest` phase
- Check identifier extraction logic matches request format
- Note: Each WASM worker has separate counter

View File

@@ -0,0 +1,77 @@
#!/bin/bash
# Build script for WASM guest rate limit example
# This script simplifies the build process for the WASM middleware component
set -e
echo "Building WASM guest rate limit example..."
# Check if we're in the right directory
if [ ! -f "Cargo.toml" ]; then
echo "Error: Cargo.toml not found. Please run this script from the wasm-guest-ratelimit directory."
exit 1
fi
# Check for required tools
command -v cargo >/dev/null 2>&1 || { echo "Error: cargo is required but not installed. Aborting." >&2; exit 1; }
# Check and install wasm32-wasip2 target
echo "Checking for wasm32-wasip2 target..."
if ! rustup target list --installed | grep -q "wasm32-wasip2"; then
echo "wasm32-wasip2 target not found. Installing..."
rustup target add wasm32-wasip2
echo "✓ wasm32-wasip2 target installed"
else
echo "✓ wasm32-wasip2 target already installed"
fi
# Check for wasm-tools
if ! command -v wasm-tools >/dev/null 2>&1; then
echo "Error: wasm-tools is required but not installed."
echo "Install it with: cargo install wasm-tools"
exit 1
fi
# Build with cargo (wit-bindgen uses cargo, not wasm-pack)
echo "Running cargo build..."
cargo build --target wasm32-wasip2 --release
# Output locations
WASM_MODULE="target/wasm32-wasip2/release/wasm_guest_ratelimit.wasm"
WASM_COMPONENT="target/wasm32-wasip2/release/wasm_guest_ratelimit.component.wasm"
if [ ! -f "$WASM_MODULE" ]; then
echo "Error: Build failed - WASM module not found"
exit 1
fi
# Check if the file is already a component
echo "Checking WASM file format..."
if wasm-tools print "$WASM_MODULE" 2>/dev/null | grep -q "^(\s*component"; then
echo "✓ WASM file is already in component format"
# Copy to component path for consistency
cp "$WASM_MODULE" "$WASM_COMPONENT"
else
# Wrap the WASM module into a component format
echo "Wrapping WASM module into component format..."
wasm-tools component new "$WASM_MODULE" -o "$WASM_COMPONENT"
if [ ! -f "$WASM_COMPONENT" ]; then
echo "Error: Failed to create component file"
exit 1
fi
fi
if [ -f "$WASM_COMPONENT" ]; then
echo ""
echo "✓ Build successful!"
echo " WASM module: $WASM_MODULE"
echo " WASM component: $WASM_COMPONENT"
echo ""
echo "Next steps:"
echo "1. Use the component file ($WASM_COMPONENT) when adding the module"
echo "2. Prepare the module configuration (see README.md for JSON format)"
echo "3. Use the API endpoint to add the module (see README.md for details)"
else
echo "Error: Component file not found"
exit 1
fi

View File

@@ -0,0 +1,155 @@
//! WASM Guest Rate Limit Example for sgl-model-gateway
//!
//! This example demonstrates rate limiting middleware
//! for sgl-model-gateway using the WebAssembly Component Model.
//!
//! Features:
//! - Rate limiting based on API Key or IP address
//! - Fixed time window (e.g., 60 requests per minute)
//! - Returns 429 Too Many Requests when limit exceeded
//!
//! Note: This is a simplified implementation. Since WASM components are stateless,
//! each instance maintains its own counters. For production use, consider
//! implementing rate limiting at the host/router level with shared state.
wit_bindgen::generate!({
path: "../../../src/wasm/interface",
world: "sgl-model-gateway",
});
use std::cell::RefCell;
use exports::sgl::model_gateway::{
middleware_on_request::Guest as OnRequestGuest,
middleware_on_response::Guest as OnResponseGuest,
};
use sgl::model_gateway::middleware_types::{Action, Request, Response};
/// Main middleware implementation
struct Middleware;
// Rate limit configuration
const RATE_LIMIT_REQUESTS: u64 = 60; // Maximum requests per window
const RATE_LIMIT_WINDOW_MS: u64 = 60_000; // Time window in milliseconds (1 minute)
// Simple in-memory counter (per WASM instance)
// In a real implementation, this would be shared across all instances
// This is a simplified example for demonstration purposes
struct RateLimitState {
requests: Vec<(String, u64)>, // (identifier, timestamp_ms)
}
impl RateLimitState {
fn new() -> Self {
Self {
requests: Vec::new(),
}
}
// Clean up old entries outside the time window
fn cleanup(&mut self, current_time_ms: u64) {
let cutoff = current_time_ms.saturating_sub(RATE_LIMIT_WINDOW_MS);
self.requests.retain(|(_, timestamp)| *timestamp > cutoff);
}
// Check if identifier has exceeded rate limit
fn check_limit(&mut self, identifier: &str, current_time_ms: u64) -> bool {
self.cleanup(current_time_ms);
// Count requests in current window for this identifier
let count = self
.requests
.iter()
.filter(|(id, timestamp)| {
id == identifier
&& *timestamp > current_time_ms.saturating_sub(RATE_LIMIT_WINDOW_MS)
})
.count() as u64;
if count >= RATE_LIMIT_REQUESTS {
return false; // Limit exceeded
}
// Add new request
self.requests
.push((identifier.to_string(), current_time_ms));
true // Within limit
}
}
// Thread-local state (per WASM instance thread)
// Using thread_local! is safer than static mut as it avoids unsafe blocks
// and provides separate state for each thread automatically
thread_local! {
static RATE_LIMIT_STATE: RefCell<RateLimitState> = RefCell::new(RateLimitState::new());
}
fn get_identifier(req: &Request) -> String {
// Helper function to find header value
let find_header_value =
|headers: &[sgl::model_gateway::middleware_types::Header], name: &str| -> Option<String> {
headers
.iter()
.find(|h| h.name.eq_ignore_ascii_case(name))
.map(|h| h.value.clone())
};
// Prefer API Key as identifier (more stable than IP)
if let Some(auth_header) = find_header_value(&req.headers, "authorization") {
if auth_header.starts_with("Bearer ") {
return format!("api_key:{}", &auth_header[7..]);
} else if auth_header.starts_with("ApiKey ") {
return format!("api_key:{}", &auth_header[7..]);
}
}
if let Some(api_key) = find_header_value(&req.headers, "x-api-key") {
return format!("api_key:{}", api_key);
}
// Fall back to IP address from forwarded headers
if let Some(forwarded_for) = find_header_value(&req.headers, "x-forwarded-for") {
// Take first IP from comma-separated list
let ip = forwarded_for.split(',').next().unwrap_or("").trim();
if !ip.is_empty() {
return format!("ip:{}", ip);
}
}
if let Some(real_ip) = find_header_value(&req.headers, "x-real-ip") {
return format!("ip:{}", real_ip);
}
// Last resort: use request ID (not ideal, but better than nothing)
format!("req_id:{}", req.request_id)
}
// Implement on-request interface
impl OnRequestGuest for Middleware {
fn on_request(req: Request) -> Action {
let identifier = get_identifier(&req);
let current_time_ms = req.now_epoch_ms;
// Access thread-local state safely without unsafe blocks
// Each thread gets its own RateLimitState instance
RATE_LIMIT_STATE.with(|state| {
let mut state = state.borrow_mut();
if !state.check_limit(&identifier, current_time_ms) {
// Rate limit exceeded
return Action::Reject(429);
}
// Within rate limit, continue processing
Action::Continue
})
}
}
// Implement on-response interface (empty - not used for rate limiting)
impl OnResponseGuest for Middleware {
fn on_response(_resp: Response) -> Action {
Action::Continue
}
}
// Export the component
export!(Middleware);