Skip to content

Commit 645e94e

Browse files
authored
fasthttp: fixes and improvements (#25906)
1 parent 7fd6d3b commit 645e94e

File tree

16 files changed

+1063
-711
lines changed

16 files changed

+1063
-711
lines changed

cmd/tools/vbuild-examples.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ const efolders = [
1111
'examples/vweb_orm_jwt',
1212
'examples/vweb_fullstack',
1313
'examples/vanilla_http_server',
14+
'examples/fasthttp',
1415
]
1516

1617
pub fn normalised_vroot_path(path string) string {

examples/fasthttp/README.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Fasthttp Example
2+
3+
A simple HTTP server example using the `fasthttp` module from `vlib/fasthttp`.
4+
5+
## Features
6+
7+
- Handles GET and POST requests
8+
- Routes requests to different controllers based on HTTP method and path
9+
- Returns appropriate HTTP responses with status codes and content
10+
11+
## Building
12+
13+
```sh
14+
./v examples/fasthttp
15+
```
16+
17+
## Running
18+
19+
```sh
20+
./examples/fasthttp/fasthttp
21+
```
22+
23+
The server will listen on `http://localhost:3000`
24+
25+
## Testing
26+
27+
### Home endpoint
28+
29+
```sh
30+
curl http://localhost:3000/
31+
```
32+
33+
### Get user by ID
34+
35+
```sh
36+
curl http://localhost:3000/user/123
37+
```
38+
39+
### Create user
40+
41+
```sh
42+
curl -X POST http://localhost:3000/user
43+
```
44+
45+
### 404 response
46+
47+
```sh
48+
curl http://localhost:3000/notfound
49+
```
50+
51+
## File Structure
52+
53+
- `main.v` - Entry point and request router
54+
- `controllers.v` - Request handlers for different routes
55+
- `v.mod` - Module metadata
56+
57+
## Architecture
58+
59+
The example demonstrates:
60+
61+
1. **Request Routing**: The `handle_request()` function routes incoming HTTP requests based on
62+
method and path
63+
2. **Response Handling**: Controllers return HTTP responses with proper headers and status codes
64+
3. **Content Type**: All responses are returned as `[]u8` (byte arrays)
65+
66+
The fasthttp module handles:
67+
68+
- Low-level socket management
69+
- Request parsing
70+
- Connection handling
71+
- Non-blocking I/O with epoll (Linux) or kqueue (macOS)

examples/fasthttp/controllers.v

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
module main
2+
3+
fn home_controller() ![]u8 {
4+
response := 'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: 13\r\n\r\nHello, World!'
5+
return response.bytes()
6+
}
7+
8+
fn get_user_controller(id string) ![]u8 {
9+
body := 'User ID: ${id}'
10+
content_length := body.len
11+
response := 'HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\nContent-Length: ${content_length}\r\n\r\n${body}'
12+
return response.bytes()
13+
}
14+
15+
fn create_user_controller() ![]u8 {
16+
body := 'User created successfully'
17+
content_length := body.len
18+
response := 'HTTP/1.1 201 Created\r\nContent-Type: text/plain\r\nContent-Length: ${content_length}\r\n\r\n${body}'
19+
return response.bytes()
20+
}
21+
22+
fn not_found_response() ![]u8 {
23+
body := '404 Not Found'
24+
content_length := body.len
25+
response := 'HTTP/1.1 404 Not Found\r\nContent-Type: text/plain\r\nContent-Length: ${content_length}\r\n\r\n${body}'
26+
return response.bytes()
27+
}

examples/fasthttp/main.v

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
module main
2+
3+
import fasthttp
4+
5+
fn handle_request(req fasthttp.HttpRequest) ![]u8 {
6+
method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr()
7+
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
8+
9+
if method == 'GET' {
10+
if path == '/' {
11+
return home_controller()!
12+
} else if path.starts_with('/user/') {
13+
id := path[6..]
14+
return get_user_controller(id)!
15+
}
16+
} else if method == 'POST' {
17+
if path == '/user' {
18+
return create_user_controller()!
19+
}
20+
}
21+
22+
return not_found_response()!
23+
}
24+
25+
fn main() {
26+
mut server := fasthttp.new_server(fasthttp.ServerConfig{
27+
port: 3000
28+
handler: handle_request
29+
}) or {
30+
eprintln('Failed to create server: ${err}')
31+
return
32+
}
33+
34+
println('Starting fasthttp server on port http://localhost:3000...')
35+
36+
server.run() or { eprintln('error: ${err}') }
37+
}

examples/fasthttp/v.mod

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Module {
2+
name: 'fasthttp_example'
3+
description: 'A simple HTTP server example using the fasthttp module'
4+
version: '0.0.1'
5+
license: 'MIT'
6+
}

vlib/fasthttp/README.md

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
# fasthttp
2+
3+
The `fasthttp` module is a high-performance HTTP server library for V that provides low-level socket management and non-blocking I/O.
4+
5+
## Features
6+
7+
- **High Performance**: Uses platform-specific I/O multiplexing:
8+
- `epoll` on Linux for efficient connection handling
9+
- `kqueue` on macOS for high-performance event notification
10+
- **Non-blocking I/O**: Handles multiple concurrent connections efficiently
11+
- **Simple API**: Easy-to-use request handler pattern
12+
- **Cross-platform**: Supports Linux and macOS
13+
14+
## Installation
15+
16+
The module is part of the standard V library. Import it in your V code:
17+
18+
```v
19+
import fasthttp
20+
```
21+
22+
## Quick Start
23+
24+
Here's a minimal HTTP server example:
25+
26+
```v
27+
import fasthttp
28+
29+
fn handle_request(req fasthttp.HttpRequest) ![]u8 {
30+
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
31+
32+
if path == '/' {
33+
return 'Hello, World!'.bytes()
34+
}
35+
36+
return '404 Not Found'.bytes()
37+
}
38+
39+
fn main() {
40+
mut server := fasthttp.new_server(fasthttp.ServerConfig{
41+
port: 3000
42+
handler: handle_request
43+
}) or {
44+
eprintln('Failed to create server: ${err}')
45+
return
46+
}
47+
48+
println('Server listening on http://localhost:3000')
49+
server.run() or { eprintln('error: ${err}') }
50+
}
51+
```
52+
53+
## API Reference
54+
55+
### `HttpRequest` Struct
56+
57+
Represents an incoming HTTP request.
58+
59+
**Fields:**
60+
61+
- `buffer: []u8` - The raw request buffer containing the complete HTTP request
62+
- `method: Slice` - The HTTP method (GET, POST, etc.)
63+
- `path: Slice` - The request path
64+
- `version: Slice` - The HTTP version (e.g., "HTTP/1.1")
65+
- `client_conn_fd: int` - Internal socket file descriptor
66+
67+
### `Slice` Struct
68+
69+
Represents a slice of the request buffer.
70+
71+
**Fields:**
72+
73+
- `start: int` - Starting index in the buffer
74+
- `len: int` - Length of the slice
75+
76+
**Usage:**
77+
78+
```v ignore
79+
method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr()
80+
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
81+
```
82+
83+
## Request Handler Pattern
84+
85+
The handler function receives an `HttpRequest` and must return either:
86+
87+
- `[]u8` - A byte array containing the HTTP response body
88+
- An error if processing failed
89+
90+
The handler should extract method and path information from the request and route accordingly.
91+
92+
**Example:**
93+
94+
```v ignore
95+
fn my_handler(req fasthttp.HttpRequest) ![]u8 {
96+
method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr()
97+
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
98+
99+
match method {
100+
'GET' {
101+
if path == '/' {
102+
return 'Home page'.bytes()
103+
}
104+
}
105+
'POST' {
106+
if path == '/api/data' {
107+
return 'Data received'.bytes()
108+
}
109+
}
110+
else {}
111+
}
112+
113+
return '404 Not Found'.bytes()
114+
}
115+
```
116+
117+
## Response Format
118+
119+
Responses should be returned as byte arrays.
120+
The server will send them directly to the client as HTTP response bodies.
121+
122+
```v ignore
123+
// Simple text response
124+
return 'Hello, World!'.bytes()
125+
126+
// HTML response
127+
return '<html><body>Hello</body></html>'.bytes()
128+
129+
// JSON response
130+
return '{"message": "success"}'.bytes()
131+
```
132+
133+
## Example
134+
135+
See the complete example in `examples/fasthttp/` for a more
136+
detailed server implementation with multiple routes and controllers.
137+
138+
```sh
139+
./v examples/fasthttp
140+
./examples/fasthttp/fasthttp
141+
```
142+
143+
## Platform Support
144+
145+
- **Linux**: Uses `epoll` for high-performance I/O multiplexing
146+
- **macOS**: Uses `kqueue` for event notification
147+
- **Windows**: Currently not supported
148+
149+
## Performance Considerations
150+
151+
- The `fasthttp` module is designed for high throughput and low latency
152+
- Handler functions should be efficient; blocking operations will affect other connections
153+
- Use goroutines within handlers if you need to perform long-running operations without
154+
blocking the I/O loop
155+
156+
## Notes
157+
158+
- HTTP headers are currently not parsed; the entire request is available in the buffer
159+
- Only the request method, path, and version are parsed automatically
160+
- Response status codes and headers must be manually constructed if needed
161+
- The module provides low-level access for maximum control and performance

0 commit comments

Comments
 (0)