UVHTTP Static File Server Guide
Overview
UVHTTP's static file server serves static files with automatic MIME type detection, file caching, conditional request support, and related features.
Design Principles
Application Layer Implementation
Static file routing is implemented by the application layer, not built into the framework. This follows UVHTTP's "Focus on Core" principle:
- Framework Core:
uvhttp_static_handle_request()handles individual static file requests - Application Layer: responsible for routing configuration, path mapping, context passing
- Flexibility: the application controls static file service routing strategies
Recommended Implementation
// 1. Create static file context
uvhttp_static_context_t* static_ctx;
uvhttp_static_create(&config, &static_ctx);
// 2. Create application layer wrapper function
int static_file_handler(uvhttp_request_t* request, uvhttp_response_t* response) {
// Get static_ctx from context
app_context_t* app_ctx = (app_context_t*)loop->data;
return uvhttp_static_handle_request(app_ctx->static_ctx, request, response);
}
// 3. Add routes (application layer control)
uvhttp_router_add_route(router, "/static/*", static_file_handler);
uvhttp_router_add_route(router, "/*", static_file_handler); // Fallback routeWhy Not Built-in?
- Avoids framework bloat
- Keeps application layer flexibility and control
- Follows the "Less is More" minimalist principle
Core Features
Performance Optimization
- LRU Cache System: in-memory cache reduces disk I/O
- Zero-Copy Optimization: sendfile-based file transfer
- Connection Reuse: libuv event-driven architecture
- Compression Support: gzip/deflate compression interface
Security Features
- Path Safety Validation: prevents directory traversal attacks
- File Type Checking: configurable file type whitelist
- Access Control: path-based access restriction
- Resource Limits: guards against large-file DoS
Functional Features
- Automatic MIME Type Detection: common file types
- Conditional Requests: ETag and Last-Modified support
- Directory Listing: configurable directory browsing
- Custom Headers: add custom HTTP headers
- Error Handling: error pages and logging
Quick Start
Basic Example
See examples/04_static_files/static_file_server.c for a complete example of static file routing.
Key Points
- Use
uvhttp_router_add_route()to add static file routes - Create wrapper functions to call
uvhttp_static_handle_request() - Pass application context through
server->contextorloop->data - Use wildcard routes to handle multiple static file paths
API Reference
For detailed API documentation, see:
include/uvhttp_static.h- Static file service APIexamples/04_static_files/- Example programs
Best Practices
Route Configuration
- Use specific routes when possible (e.g.,
/static/*) - Place wildcard routes last to avoid blocking other routes
- Consider separating static and dynamic content
- Use specific routes when possible (e.g.,
Security
- Always validate file paths
- Configure file size limits
- Use proper directory permissions
Performance
- Enable LRU cache for frequently accessed files
- Use appropriate cache TTL values
- Consider CDN for large-scale deployments
Cache Prewarming Strategies
UVHTTP provides cache prewarming APIs so the application layer can implement strategies for its own use cases. The framework provides the infrastructure; the application decides the strategy.
Available Prewarming APIs
// Prewarm a single file
uvhttp_result_t uvhttp_static_prewarm_cache(uvhttp_static_context_t* ctx,
const char* file_path);
// Prewarm an entire directory
int uvhttp_static_prewarm_directory(uvhttp_static_context_t* ctx,
const char* dir_path, int max_files);
// Direct cache prewarming (low-level)
uvhttp_error_t uvhttp_lru_cache_prewarm(cache_manager_t* cache,
const char* file_path, char* content,
size_t content_length,
const char* mime_type,
time_t last_modified, const char* etag,
int priority);Strategy 1: Directory-Based Prewarming by File Type
Preload common web asset types from a directory:
int prewarm_web_assets(uvhttp_static_context_t* ctx, const char* dir_path) {
const char* web_extensions[] = {".css", ".js", ".png", ".jpg", ".svg", ".woff2"};
int prewarmed_count = 0;
DIR* dir = opendir(dir_path);
if (!dir) return -1;
struct dirent* entry;
while ((entry = readdir(dir)) != NULL && prewarmed_count < 100) {
const char* ext = strrchr(entry->d_name, '.');
if (!ext) continue;
// Check if extension matches web assets
for (size_t i = 0; i < sizeof(web_extensions) / sizeof(web_extensions[0]); i++) {
if (strcasecmp(ext, web_extensions[i]) == 0) {
char full_path[512];
snprintf(full_path, sizeof(full_path), "%s/%s", dir_path, entry->d_name);
if (uvhttp_static_prewarm_cache(ctx, full_path) == UVHTTP_OK) {
prewarmed_count++;
}
break;
}
}
}
closedir(dir);
return prewarmed_count;
}
// Usage
prewarm_web_assets(static_ctx, "./public/static");Strategy 2: Preload Related Files from HTML
Parse HTML to extract and preload referenced resources:
int preload_html_resources(uvhttp_static_context_t* ctx, const char* html_path) {
// Read HTML file
FILE* f = fopen(html_path, "r");
if (!f) return -1;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
char* html = malloc(size + 1);
fread(html, 1, size, f);
html[size] = '\0';
fclose(f);
// Extract resource paths (simplified example)
char* patterns[] = {"href=\"", "src=\""};
int prewarmed_count = 0;
for (int i = 0; i < 2 && prewarmed_count < 50; i++) {
char* p = html;
while ((p = strstr(p, patterns[i])) != NULL && prewarmed_count < 50) {
p += strlen(patterns[i]);
char* end = strchr(p, '"');
if (!end) break;
*end = '\0';
char resource_path[512];
snprintf(resource_path, sizeof(resource_path), "./public/%s", p);
if (uvhttp_static_prewarm_cache(ctx, resource_path) == UVHTTP_OK) {
prewarmed_count++;
}
*end = '"';
p = end + 1;
}
}
free(html);
return prewarmed_count;
}
// Usage
preload_html_resources(static_ctx, "./public/index.html");Strategy 3: Priority-Based Prewarming
Set different priorities for different file types:
void prewarm_with_priority(uvhttp_static_context_t* ctx) {
// High priority: Core CSS and JS
const char* high_priority_files[] = {
"./public/css/main.css",
"./public/js/app.js",
"./public/js/vendor.js"
};
for (size_t i = 0; i < sizeof(high_priority_files) / sizeof(high_priority_files[0]); i++) {
uvhttp_lru_cache_set_entry_priority(ctx->cache, high_priority_files[i], 100);
uvhttp_static_prewarm_cache(ctx, high_priority_files[i]);
}
// Medium priority: Images
const char* medium_priority_files[] = {
"./public/images/logo.png",
"./public/images/banner.jpg"
};
for (size_t i = 0; i < sizeof(medium_priority_files) / sizeof(medium_priority_files[0]); i++) {
uvhttp_lru_cache_set_entry_priority(ctx->cache, medium_priority_files[i], 50);
uvhttp_static_prewarm_cache(ctx, medium_priority_files[i]);
}
}Strategy 4: Gradual Prewarming on Server Start
Warm up cache gradually during server initialization:
void gradual_prewarm(uvhttp_static_context_t* ctx, const char* dir_path) {
int batch_size = 10;
int total_files = 0;
int prewarmed = 0;
// First batch: Core files
prewarmed = uvhttp_static_prewarm_directory(ctx, dir_path, batch_size);
printf("Prewarmed %d core files\n", prewarmed);
// Second batch: Additional files
prewarmed = uvhttp_static_prewarm_directory(ctx, dir_path, batch_size);
printf("Prewarmed %d additional files\n", prewarmed);
// Continue until cache is full or all files are loaded
size_t total_memory;
int entry_count;
uvhttp_lru_cache_get_stats(ctx->cache, &total_memory, &entry_count, NULL, NULL, NULL);
printf("Cache stats: %zu bytes, %d entries\n", total_memory, entry_count);
}Strategy 5: On-Demand Prewarming
Preload files when they are first requested:
int smart_file_handler(uvhttp_request_t* req, uvhttp_response_t* res) {
app_context_t* app_ctx = (app_context_t*)req->client->loop->data;
// Handle the current request
int result = uvhttp_static_handle_request(app_ctx->static_ctx, req, res);
// If this is a CSS or JS file, preload related files
if (result == UVHTTP_OK && req->path) {
if (strstr(req->path, ".css") || strstr(req->path, ".js")) {
char base_path[512];
strncpy(base_path, req->path, sizeof(base_path));
char* last_slash = strrchr(base_path, '/');
if (last_slash) {
*last_slash = '\0';
// Prewarm other files in the same directory
uvhttp_static_prewarm_directory(app_ctx->static_ctx, base_path, 5);
}
}
}
return result;
}Performance Monitoring
Monitor cache effectiveness:
void print_cache_stats(uvhttp_static_context_t* ctx) {
size_t total_memory;
uvhttp_lru_cache_get_stats(ctx->cache, &total_memory, &entry_count, NULL, NULL, NULL);
hit_rate = uvhttp_lru_cache_get_hit_rate(ctx->cache);
printf("Cache Statistics:\n");
printf(" Memory Usage: %zu bytes\n", total_memory);
printf(" Entry Count: %d\n", entry_count);
printf(" Hit Rate: %.2f%%\n", hit_rate * 100);
}Best Practices for Prewarming
- Start simple: begin with directory-based prewarming before complex strategies
- Watch memory: track cache usage to avoid excess memory consumption
- Prioritize: set higher priorities for frequently accessed files
- Be selective: don't prewarm everything — focus on critical resources
- Profile: use cache statistics to find hot files and tune the strategy
When to Use Prewarming
- Production deployment: preload critical assets before accepting traffic
- Zero-downtime deployments: warm new instances before routing traffic
- High-traffic events: prepare cache for expected spikes
- Performance tuning: optimize based on access patterns
When NOT to Use Prewarming
- Development: unnecessary during development
- Small-scale apps: cache may not help
- Dynamically generated content: static cache won't help
- Memory-constrained environments: may cause memory pressure
See Also
- FAQ - Common questions and answers
- API Reference - Complete API documentation
- Performance Guide - Performance benchmarks