Building a Basic HTTP Server in C with Various Method Support
22 views
Creating a minimal HTTP server in C that supports GET, POST, DELETE, PUT, and PATCH methods involves using sockets and parsing HTTP requests. Below is a simplified example, focusing on the basic setup and handling of different methods.
Please note that a full-featured HTTP server would require a more sophisticated approach including proper request parsing, headers management, robust error handling, multi-threading for handling concurrent requests, and security considerations.
#include <arpa/inet.h>
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define PORT 8080
#define BUFFER_SIZE 4096
void handle_request(int client_socket);
void send_response(int client_socket, const char* status, const char* body);
int main() {
int server_socket, client_socket;
struct sockaddr_in server_addr, client_addr;
socklen_t client_len = sizeof(client_addr);
// Create socket
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// Set socket options
int opt = 1;
if (setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt))) {
perror("Setsockopt failed");
close(server_socket);
exit(EXIT_FAILURE);
}
// Bind socket to port
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
if (bind(server_socket, (struct sockaddr*)&server_addr, sizeof(server_addr)) < 0) {
perror("Bind failed");
close(server_socket);
exit(EXIT_FAILURE);
}
// Listen for connections
if (listen(server_socket, 10) < 0) {
perror("Listen failed");
close(server_socket);
exit(EXIT_FAILURE);
}
printf("HTTP server listening on port %d\n", PORT);
// Main loop to accept and handle requests
while (1) {
// Accept client connection
if ((client_socket = accept(server_socket, (struct sockaddr*)&client_addr, &client_len)) < 0) {
perror("Accept failed");
continue;
}
// Handle request in a separate function
handle_request(client_socket);
// Close client connection
close(client_socket);
}
// Close server socket
close(server_socket);
return 0;
}
void handle_request(int client_socket) {
char buffer[BUFFER_SIZE];
read(client_socket, buffer, BUFFER_SIZE);
// Simple request method parsing
if (strstr(buffer, "GET /")) {
send_response(client_socket, "200 OK", "GET method response");
} else if (strstr(buffer, "POST /")) {
send_response(client_socket, "200 OK", "POST method response");
} else if (strstr(buffer, "DELETE /")) {
send_response(client_socket, "200 OK", "DELETE method response");
} else if (strstr(buffer, "PUT /")) {
send_response(client_socket, "200 OK", "PUT method response");
} else if (strstr(buffer, "PATCH /")) {
send_response(client_socket, "200 OK", "PATCH method response");
} else {
send_response(client_socket, "405 Method Not Allowed", "Method not allowed");
}
}
void send_response(int client_socket, const char* status, const char* body) {
char response[BUFFER_SIZE];
snprintf(response, sizeof(response),
"HTTP/1.1 %s\r\n"
"Content-Type: text/plain\r\n"
"Content-Length: %zu\r\n"
"\r\n"
"%s",
status, strlen(body), body);
write(client_socket, response, strlen(response));
}
Key Points:
- Creating Socket: The server creates a socket to listen for incoming connections.
- Binding Socket: Binds the socket to a specified port.
- Listening: The server listens for incoming connection requests.
- Accepting Connections: Accepts connections from clients.
- Handling Requests: A basic parsing to determine the HTTP method and responding accordingly.
- Sending Responses: Sends an appropriate HTTP response based on the request.
This example demonstrates a basic structure and should be expanded to handle more complex scenarios appropriately.