Skip to content

Instantly share code, notes, and snippets.

@x-yuri
Last active January 3, 2025 05:48
Show Gist options
  • Save x-yuri/50bed482c75e64749d45c08e7d096455 to your computer and use it in GitHub Desktop.
Save x-yuri/50bed482c75e64749d45c08e7d096455 to your computer and use it in GitHub Desktop.
A poor man's http server

A poor man's http server

The server process handles a request and exits. But the server is running in a docker container with --restart always, so after each request docker restarts the server.

Dockerfile:

FROM alpine:3.20
COPY a.c a.c
RUN apk add gcc musl-dev \
    && gcc a.c

a.c:

#include <stdlib.h>
#include <sys/socket.h>
#include <err.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

#define BUF_SIZE 10

/*
static void print_buf(char *buf, int len)
{
    puts("buf: (");
    for (int i = 0; i < len; i++) {
        if (buf[i] < 32 || buf[i] == 127) {
            printf("\\%02x", buf[i]);
        } else putchar(buf[i]);
    }
    puts(")\n");
}
*/

static size_t read_request(int client) {
    char buf[BUF_SIZE], *bufp = buf;
    size_t n_read = 0;
    while (1) {
        ssize_t r;
        size_t i;
        r = read(client, bufp, BUF_SIZE - (bufp - buf));
        if (r == -1) err(1, "read()");
        n_read += r;
        /* print_buf(buf, bufp - buf + r); */

        /* find the beginning of the last \r\n sequence */
        i = r;
        while (i > 0 && r - i < 4 && (bufp[i - 1] == '\r' || bufp[i - 1] == '\n'))
            i--;

        /* copy the sequence to the beginning of the buffer */
        if (i > 0) {
            i += bufp - buf;
            r += bufp - buf;
            bufp = buf;
        }
        if (i < (size_t)r) {
            size_t j;
            for (j = 0; i < (size_t)r; j++, i++)
                bufp[j] = bufp[i];
            bufp = bufp + j;
        }

        /* break if reached \r\n\r\n */
        if (bufp - buf == 4 && memcmp(buf, "\r\n\r\n", 4) == 0)
            break;
    }
    return n_read;
}

int main(int argc, char **argv)
{
    (void) argc; /* unused */
    (void) argv; /* unused */

    int server = socket(AF_INET, SOCK_STREAM, 0);
    if (server == -1) err(1, "socket()");

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port = htons(8080),
        .sin_addr.s_addr = INADDR_ANY,
    };
    int r = bind(server, (struct sockaddr *)&addr, sizeof addr);
    if (r == -1) err(1, "bind()");

    r = listen(server, 5);
    if (r == -1) err(1, "listen()");

    int client = accept(server, NULL, NULL);
    if (r == -1) err(1, "bind()");

    read_request(client);

    #define RESPONSE "HTTP/1.1 200 OK\r\n"
    char *buf = malloc(sizeof RESPONSE);
    strcpy(buf, RESPONSE);
    write(client, buf, strlen(buf));

    return EXIT_SUCCESS;
}
$ docker build -t i .
$ docker run -p 8080:8080 --restart always i ./a.out
$ curl localhost:8080
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment