mirror of
https://github.com/KevinMidboe/http-200.git
synced 2025-10-29 09:30:28 +00:00
Init commit
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
server
|
||||||
11
Dockerfile
Normal file
11
Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
# Use the scratch base image
|
||||||
|
FROM scratch
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY server .
|
||||||
|
|
||||||
|
# Expose port 80
|
||||||
|
EXPOSE 80
|
||||||
|
|
||||||
|
# Run the binary
|
||||||
|
CMD ["/app/server"]
|
||||||
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Kevin Midbøe
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
41
Makefile
Normal file
41
Makefile
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
.PHONY: all docker-build run clean
|
||||||
|
|
||||||
|
# Variables for C compilation
|
||||||
|
CC = gcc
|
||||||
|
CFLAGS = -Os -fdata-sections -ffunction-sections -march=native -Wall -Wextra
|
||||||
|
TARGET = server
|
||||||
|
|
||||||
|
# Variables for Docker Buildx
|
||||||
|
IMAGE_NAME = kevinmidboe/http-200
|
||||||
|
VERSION = latest
|
||||||
|
PLATFORMS = linux/amd64,linux/arm64,linux/arm/v7
|
||||||
|
DATE=$(shell date +%Y.%m.%d)
|
||||||
|
|
||||||
|
# Default rule to compile the C program and build Docker image
|
||||||
|
all: $(TARGET)
|
||||||
|
|
||||||
|
run:
|
||||||
|
./server
|
||||||
|
|
||||||
|
# Rule to compile the C executable
|
||||||
|
$(TARGET): server.c
|
||||||
|
$(CC) $(CFLAGS) -o $(TARGET) server.c
|
||||||
|
|
||||||
|
# Docker Buildx setup
|
||||||
|
docker-setup: $(TARGET)
|
||||||
|
docker buildx create --use --name multiarch_builder || true
|
||||||
|
docker buildx inspect --bootstrap
|
||||||
|
|
||||||
|
# Build multi-platform Docker image without pushing to registry
|
||||||
|
docker-build: docker-setup
|
||||||
|
docker buildx build --platform $(PLATFORMS) -t $(IMAGE_NAME):$(VERSION) -t $(IMAGE_NAME):$(DATE) .
|
||||||
|
|
||||||
|
# Build multi-platform Docker image and push to registry
|
||||||
|
docker-publish: docker-setup
|
||||||
|
docker buildx build --platform $(PLATFORMS) -t $(IMAGE_NAME):$(VERSION) -t $(IMAGE_NAME):$(DATE) --push .
|
||||||
|
|
||||||
|
# Clean up Buildx builder and compiled binary
|
||||||
|
clean:
|
||||||
|
rm -f $(TARGET)
|
||||||
|
docker buildx rm multiarch_builder || true
|
||||||
|
|
||||||
41
README.md
Normal file
41
README.md
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
# http-200
|
||||||
|
|
||||||
|
Simple http C server that always responds 200 to all http requests. Resulting in docker image size smaller than 40 kB (or 3 kB compressed).
|
||||||
|
|
||||||
|
## build
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gcc -o server server.c
|
||||||
|
```
|
||||||
|
|
||||||
|
or using make
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make
|
||||||
|
```
|
||||||
|
|
||||||
|
## run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./server
|
||||||
|
```
|
||||||
|
|
||||||
|
or
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make run
|
||||||
|
```
|
||||||
|
|
||||||
|
## docker
|
||||||
|
|
||||||
|
build using docker with
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t http-200 .
|
||||||
|
```
|
||||||
|
|
||||||
|
publish (multi-arch) using
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make docker-publish
|
||||||
|
```
|
||||||
91
server.c
Normal file
91
server.c
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <arpa/inet.h> // For inet_ntop
|
||||||
|
|
||||||
|
int server_fd;
|
||||||
|
|
||||||
|
void handle_signal(int signal) {
|
||||||
|
printf("\nReceived signal %d, shutting down server...\n", signal);
|
||||||
|
fflush(stdout); // Ensure output is flushed immediately
|
||||||
|
if (server_fd >= 0) {
|
||||||
|
close(server_fd);
|
||||||
|
}
|
||||||
|
exit(0); // Graceful exit after closing the socket
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
struct sockaddr_in address;
|
||||||
|
struct sockaddr_in client_address;
|
||||||
|
int client_fd;
|
||||||
|
int addrlen = sizeof(address);
|
||||||
|
int port = 80;
|
||||||
|
|
||||||
|
// Disable stdout buffering
|
||||||
|
setbuf(stdout, NULL); // Disables buffering, output is immediate
|
||||||
|
|
||||||
|
// Setup signal handler for graceful shutdown
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = handle_signal;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sa.sa_flags = 0;
|
||||||
|
sigaction(SIGINT, &sa, NULL);
|
||||||
|
sigaction(SIGTERM, &sa, NULL);
|
||||||
|
|
||||||
|
// Create socket
|
||||||
|
server_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
if (server_fd == 0) {
|
||||||
|
perror("Socket failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Configure the server address and port
|
||||||
|
address.sin_family = AF_INET;
|
||||||
|
address.sin_addr.s_addr = INADDR_ANY;
|
||||||
|
address.sin_port = htons(port);
|
||||||
|
|
||||||
|
// Bind the socket to the port
|
||||||
|
if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0) {
|
||||||
|
perror("Bind failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start listening for incoming connections
|
||||||
|
if (listen(server_fd, 1) < 0) {
|
||||||
|
perror("Listen failed");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output immediately after listening starts
|
||||||
|
printf("Server listening on port %i...\n", port);
|
||||||
|
fflush(stdout); // Ensure output is flushed immediately
|
||||||
|
|
||||||
|
while (1) {
|
||||||
|
// Accept client connections
|
||||||
|
client_fd = accept(server_fd, (struct sockaddr *)&client_address, (socklen_t *)&addrlen);
|
||||||
|
if (client_fd < 0) {
|
||||||
|
perror("Accept failed");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the client's IP address
|
||||||
|
char client_ip[INET_ADDRSTRLEN];
|
||||||
|
if (inet_ntop(AF_INET, &client_address.sin_addr, client_ip, sizeof(client_ip)) == NULL) {
|
||||||
|
perror("inet_ntop failed");
|
||||||
|
} else {
|
||||||
|
printf("Connection from IP: %s\n", client_ip); // Log the client IP
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send a simple HTTP 200 OK response
|
||||||
|
char response[] = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\nserver: http-200\r\n\r\n";
|
||||||
|
send(client_fd, response, strlen(response), 0);
|
||||||
|
close(client_fd); // Close the client connection after sending the response
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Reference in New Issue
Block a user