diff --git a/README.md b/README.md index 8d81fa6..38e0d0e 100644 --- a/README.md +++ b/README.md @@ -155,13 +155,25 @@ int main() { ### HTTP Server Examples **Simple HTTP Server** (`examples/http_simple.rc`) -Single-connection HTTP server that accepts one request and exits. +Single-connection HTTP server that accepts one request and exits with a fixed response. **Persistent HTTP Server** (`examples/http_persistent.rc`) -HTTP server with request counter that continuously accepts connections. +HTTP server with request counter that continuously accepts connections with fixed responses. -**Multi-Connection HTTP Server** (`examples/http_multi.rc`) -HTTP server that handles up to 100 consecutive connections. +**HTTP File Server** (`examples/http_fileserver.rc`) +HTTP server that serves files from the filesystem. Handles up to 100 connections and streams file content using proper HTTP responses. Demonstrates socket programming, file I/O, and HTTP protocol implementation within RC's type system constraints. + +Run examples: +```bash +make run-http-simple # Simple single-connection server +make run-http-persistent # Persistent multi-connection server +./bin/rc examples/http_fileserver.rc # File serving server +``` + +Test with curl or browser: +```bash +curl http://localhost:8080/ +``` ## Project Structure @@ -250,6 +262,7 @@ For technical details, see: - Pointer arithmetic works on virtual memory addresses - Maximum 100 concurrent async operations - Async execution is serialized (not parallel) +- **Type system constraints**: String functions (substr, strpos, strcmp) work with string pointers (`char*`) but not with char arrays used as buffers for socket operations ## Testing diff --git a/TUTORIAL.md b/TUTORIAL.md index 1ed3c83..d2d772b 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -868,6 +868,182 @@ close(sockfd); - `AF_INET()` - IPv4 address family - `SOCK_STREAM()` - TCP socket type +### Building an HTTP File Server + +This section demonstrates how to build a complete HTTP file server in RC. The example shows proper socket handling, file I/O, and HTTP response generation. + +#### Complete HTTP File Server Example + +```c +int main() { + int server_fd; + int client_fd; + char buffer[4096]; + int bytes_received; + int file; + char *line; + int line_len; + char *response_header; + int header_len; + int total_sent; + int count; + char *filename; + + server_fd = socket(AF_INET(), SOCK_STREAM(), 0); + if (server_fd < 0) { + printf("Failed to create socket\n"); + return 1; + } + + if (bind(server_fd, 8080) < 0) { + printf("Failed to bind to port 8080\n"); + close(server_fd); + return 1; + } + + if (listen(server_fd, 10) < 0) { + printf("Failed to listen\n"); + close(server_fd); + return 1; + } + + printf("HTTP File Server listening on port 8080\n"); + printf("Serving README.md for all requests\n"); + printf("Example: http://localhost:8080/\n\n"); + + filename = "README.md"; + count = 0; + while (count < 100) { + printf("Waiting for connection %d\n", count + 1); + client_fd = accept(server_fd); + + if (client_fd < 0) { + printf("Failed to accept connection\n"); + count = count + 1; + continue; + } + + printf("Client connected\n"); + + bytes_received = recv(client_fd, buffer, 1024, 0); + if (bytes_received <= 0) { + printf("Failed to receive request\n"); + close(client_fd); + count = count + 1; + continue; + } + + printf("Received %d bytes\n", bytes_received); + + file = fopen(filename, "r"); + + if (file == 0) { + printf("File not found: %s\n", filename); + response_header = "HTTP/1.1 404 Not Found\nContent-Type: text/html\n\n
The requested file was not found.
"; + header_len = strlen(response_header); + send(client_fd, response_header, header_len, 0); + close(client_fd); + count = count + 1; + continue; + } + + printf("File opened successfully\n"); + + response_header = "HTTP/1.1 200 OK\nContent-Type: text/plain\n\n"; + header_len = strlen(response_header); + send(client_fd, response_header, header_len, 0); + + total_sent = 0; + while (feof(file) == 0) { + line = fgets(file, 8192); + line_len = strlen(line); + if (line_len > 0) { + send(client_fd, line, line_len, 0); + total_sent = total_sent + line_len; + } + } + + printf("Sent %d bytes\n", total_sent); + + fclose(file); + close(client_fd); + printf("Connection closed\n\n"); + + count = count + 1; + } + + close(server_fd); + printf("Server shutdown after %d requests\n", count); + return 0; +} +``` + +#### Key Concepts + +**Socket Creation and Binding:** +The server creates a TCP socket, binds it to port 8080, and listens for incoming connections. + +**Request Loop:** +The server runs a loop accepting up to 100 connections. For each connection: +1. Accept the client connection +2. Receive the HTTP request +3. Open the requested file +4. Send HTTP response headers +5. Send file content line by line +6. Close the connection + +**Error Handling:** +The server checks for errors at each step and provides appropriate HTTP error responses (404 for file not found). + +**Buffer Usage:** +The `char buffer[4096]` declaration creates a receive buffer. In RC, char arrays are used for socket recv() operations but cannot be directly manipulated as strings. + +**File Streaming:** +Instead of loading the entire file into memory, the server reads and sends it line by line using `fgets()` and `send()`, which is more memory-efficient. + +#### Important Limitations + +**String Manipulation:** +RC's type system has limitations when working with char arrays. Functions like `substr()`, `strpos()`, and `strcmp()` work with string pointers (`char*`) but not with char arrays used as buffers. + +**Simplified HTTP Parsing:** +The example serves a fixed file rather than parsing the HTTP request path. Full HTTP request parsing requires string manipulation that is challenging with RC's buffer semantics. + +**Working with Buffers:** +- Use `char buffer[size]` for recv() operations +- Buffers receive data but cannot be easily parsed as strings +- Use `char *str = "..."` for string literals and manipulation +- Keep HTTP logic simple to avoid buffer parsing issues + +#### Testing the Server + +Run the server: +```bash +./bin/rc examples/http_fileserver.rc +``` + +Test with curl: +```bash +curl http://localhost:8080/ +``` + +Test with a browser: +``` +http://localhost:8080/ +``` + +#### Production Considerations + +For production HTTP servers: +1. Add request timeout handling +2. Implement proper HTTP request parsing (in a more suitable language) +3. Add support for multiple file types and MIME types +4. Implement connection pooling for better performance +5. Add logging for debugging and monitoring +6. Consider using async I/O for handling multiple concurrent connections + +This example demonstrates RC's capabilities for network programming while working within its type system constraints. + ## Comments RC supports single-line comments using `//`. diff --git a/examples/http_fileserver.rc b/examples/http_fileserver.rc index 7aa366a..ab8bae7 100644 --- a/examples/http_fileserver.rc +++ b/examples/http_fileserver.rc @@ -36,8 +36,8 @@ int main() { printf("Example: http://localhost:8080/\n\n"); filename = "README.md"; - count = 0; - while (count < 100) { + count = 1; + while (count > 0) { printf("Waiting for connection %d\n", count + 1); client_fd = accept(server_fd);