Initial project import
This commit is contained in:
commit
23f2d29e32
11957 files changed
+1754577
No files matched your search
@@ -0,0 +1,206 @@
|
||||
# fasthttp
|
||||
|
||||
The `fasthttp` module is a high-performance HTTP server library for V that provides low-level socket management and non-blocking I/O.
|
||||
|
||||
## Features
|
||||
|
||||
- **High Performance**: Uses platform-specific I/O multiplexing:
|
||||
- `epoll` on Linux for efficient connection handling
|
||||
- `kqueue` on macOS and BSD for high-performance event notification
|
||||
- **Non-blocking I/O**: Handles multiple concurrent connections efficiently
|
||||
- **Simple API**: Easy-to-use request handler pattern
|
||||
- **Cross-platform**: Supports Linux, macOS, FreeBSD, OpenBSD, NetBSD and DragonFly
|
||||
|
||||
## Installation
|
||||
|
||||
The module is part of the standard V library. Import it in your V code:
|
||||
|
||||
```v
|
||||
import fasthttp
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
Here's a minimal HTTP server example:
|
||||
|
||||
```v oksyntax
|
||||
import fasthttp
|
||||
|
||||
fn handle_request(req fasthttp.HttpRequest) ![]u8 {
|
||||
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
|
||||
|
||||
mut body := ''
|
||||
mut status_line := ''
|
||||
|
||||
if path == '/' {
|
||||
body = 'Hello, World!\n'
|
||||
status_line = 'HTTP/1.1 200 OK'
|
||||
} else {
|
||||
body = '${path} not found\n'
|
||||
status_line = 'HTTP/1.1 404 Not Found'
|
||||
}
|
||||
|
||||
headers := [
|
||||
status_line,
|
||||
'Content-Type: text/plain',
|
||||
'Content-Length: ${body.len}',
|
||||
'Connection: close',
|
||||
]
|
||||
header_string := headers.join('\r\n')
|
||||
|
||||
return '${header_string}\r\n\r\n${body}'.bytes()
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut server := fasthttp.new_server(fasthttp.ServerConfig{
|
||||
port: 3000
|
||||
handler: handle_request
|
||||
}) or {
|
||||
eprintln('Failed to create server: ${err}')
|
||||
return
|
||||
}
|
||||
|
||||
println('Server listening on http://localhost:3000')
|
||||
server.run() or { eprintln('error: ${err}') }
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### `HttpRequest` Struct
|
||||
|
||||
Represents an incoming HTTP request.
|
||||
|
||||
**Fields:**
|
||||
|
||||
- `buffer: []u8` - The raw request buffer containing the complete HTTP request
|
||||
- `method: Slice` - The HTTP method (GET, POST, etc.)
|
||||
- `path: Slice` - The request path
|
||||
- `version: Slice` - The HTTP version (e.g., "HTTP/1.1")
|
||||
- `client_conn_fd: int` - Internal socket file descriptor
|
||||
|
||||
### `Slice` Struct
|
||||
|
||||
Represents a slice of the request buffer.
|
||||
|
||||
**Fields:**
|
||||
|
||||
- `start: int` - Starting index in the buffer
|
||||
- `len: int` - Length of the slice
|
||||
|
||||
**Usage:**
|
||||
|
||||
```v ignore
|
||||
method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr()
|
||||
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
|
||||
```
|
||||
|
||||
## Request Handler Pattern
|
||||
|
||||
The handler function receives an `HttpRequest` and must return either:
|
||||
|
||||
- `[]u8` - A byte array containing the HTTP response body
|
||||
- An error if processing failed
|
||||
|
||||
The handler should extract method and path information from the request and route accordingly.
|
||||
|
||||
**Example:**
|
||||
|
||||
```v ignore
|
||||
fn my_handler(req fasthttp.HttpRequest) ![]u8 {
|
||||
method := req.buffer[req.method.start..req.method.start + req.method.len].bytestr()
|
||||
path := req.buffer[req.path.start..req.path.start + req.path.len].bytestr()
|
||||
|
||||
match method {
|
||||
'GET' {
|
||||
if path == '/' {
|
||||
return 'Home page'.bytes()
|
||||
}
|
||||
}
|
||||
'POST' {
|
||||
if path == '/api/data' {
|
||||
return 'Data received'.bytes()
|
||||
}
|
||||
}
|
||||
else {}
|
||||
}
|
||||
|
||||
return '404 Not Found'.bytes()
|
||||
}
|
||||
```
|
||||
|
||||
## Response Format
|
||||
|
||||
Responses should be returned as byte arrays.
|
||||
The server will send them directly to the client as HTTP response bodies.
|
||||
|
||||
```v ignore
|
||||
// Simple text response
|
||||
return 'Hello, World!'.bytes()
|
||||
|
||||
// HTML response
|
||||
return '<html><body>Hello</body></html>'.bytes()
|
||||
|
||||
// JSON response
|
||||
return '{"message": "success"}'.bytes()
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
See the complete example in `examples/fasthttp/` for a more
|
||||
detailed server implementation with multiple routes and controllers.
|
||||
|
||||
```sh
|
||||
./v examples/fasthttp
|
||||
./examples/fasthttp/fasthttp
|
||||
```
|
||||
|
||||
## Platform Support
|
||||
|
||||
- **Linux**: Uses `epoll` for high-performance I/O multiplexing
|
||||
- **macOS**: Uses `kqueue` for event notification
|
||||
- **Windows**: Currently not supported
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
- The `fasthttp` module is designed for high throughput and low latency
|
||||
- Handler functions should be efficient; blocking operations will affect other connections
|
||||
- Use goroutines within handlers if you need to perform long-running operations without
|
||||
blocking the I/O loop
|
||||
|
||||
## Request-scoped allocation with `-prealloc`
|
||||
|
||||
When an application is compiled with `-prealloc`, `fasthttp` starts a scoped
|
||||
prealloc arena for each request before decoding the HTTP request and before
|
||||
calling the request handler. All V allocations made by the request parser, the
|
||||
handler, and code called by the handler use that request arena while the handler
|
||||
is running.
|
||||
|
||||
The arena is freed as a unit after the response no longer needs request-owned
|
||||
data. On Linux the normal response path sends the response synchronously, then
|
||||
ends the request arena. On macOS and BSD the response buffer can be kept by the
|
||||
connection until `kqueue` finishes writing it; in that case `fasthttp` detaches
|
||||
the scope from the request thread and frees it after the write completes.
|
||||
|
||||
This means request-local V allocations are cheap bump-pointer allocations, and
|
||||
freeing them does not require walking individual objects. Startup state, server
|
||||
state, and allocations made directly by C libraries are not part of a request
|
||||
arena. If a handler starts V `spawn` work while the request scope is active, the
|
||||
generated thread wrapper retains that scope until the spawned function returns;
|
||||
void spawned functions also run inside their own scoped arena, which is freed at
|
||||
thread exit. Manual takeover responses transfer ownership to user code and
|
||||
currently abandon the request arena, so long-lived takeover handlers should
|
||||
manage their own allocation lifetime explicitly.
|
||||
|
||||
To inspect request arena usage while developing, build with:
|
||||
|
||||
```sh
|
||||
v -prealloc -d trace_prealloc run .
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- HTTP headers are currently not parsed; the entire request is available in the buffer
|
||||
- Only the request method, path, and version are parsed automatically
|
||||
- Response status codes and headers must be manually constructed if needed
|
||||
- The module provides low-level access for maximum control and performance
|
||||
Reference in new issue
Block a user