132 lines · 3.2 KB · C
RawDownload
/* http_server.c - bind, listen, accept one HTTP request, reply, close */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h> static const char *status_text(int status) {    return status == 200 ? "OK" : "Internal Server Error";} int main(int argc, char *argv[]) {    if (argc < 2) {        fprintf(stderr, "usage: http_server <port>\n");        return 1;    }     int port = atoi(argv[1]);     int fd = socket(AF_INET, SOCK_STREAM, 0);    if (fd < 0) {        perror("socket");        return 1;    }     int reuse = 1;    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));     struct sockaddr_in addr;    memset(&addr, 0, sizeof(addr));    addr.sin_family = AF_INET;    addr.sin_port = htons((uint16_t)port);    addr.sin_addr.s_addr = htonl(INADDR_ANY);     if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {        perror("bind");        close(fd);        return 1;    }     if (listen(fd, 1) < 0) {        perror("listen");        close(fd);        return 1;    }     printf("http listening on port %d\n", port);    fflush(stdout);     struct sockaddr_in client_addr;    socklen_t client_len = sizeof(client_addr);    int client_fd = accept(fd, (struct sockaddr *)&client_addr, &client_len);    if (client_fd < 0) {        perror("accept");        close(fd);        return 1;    }     char request[2048];    ssize_t total = 0;    while (total < (ssize_t)sizeof(request) - 1) {        ssize_t n = recv(client_fd, request + total, sizeof(request) - 1 - (size_t)total, 0);        if (n < 0) {            perror("recv");            close(client_fd);            close(fd);            return 1;        }        if (n == 0) {            break;        }        total += n;        request[total] = '\0';        if (strstr(request, "\r\n\r\n") != NULL) {            break;        }    }    request[total] = '\0';     char method[16] = "";    char path[512] = "";    sscanf(request, "%15s %511s", method, path);    printf("received request: %s %s\n", method, path);    fflush(stdout);     int status = 200;    char body[768];    int body_len = snprintf(body, sizeof(body), "wasm:%s:%s", method, path);    if (body_len < 0 || (size_t)body_len >= sizeof(body)) {        status = 500;        body_len = snprintf(body, sizeof(body), "wasm:error");    }     char response[1400];    int response_len = snprintf(        response,        sizeof(response),        "HTTP/1.1 %d %s\r\n"        "Content-Type: text/plain\r\n"        "Content-Length: %d\r\n"        "Connection: close\r\n"        "\r\n"        "%s",        status,        status_text(status),        body_len,        body    );     if (response_len < 0 || (size_t)response_len >= sizeof(response)) {        fprintf(stderr, "response too large\n");        close(client_fd);        close(fd);        return 1;    }     ssize_t sent = send(client_fd, response, (size_t)response_len, 0);    if (sent < 0) {        perror("send");        close(client_fd);        close(fd);        return 1;    }     printf("sent response: %zd\n", sent);     close(client_fd);    close(fd);    return 0;}