From 1e59a38fb44f7e4c777a10600ad166c7248da04a Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Thu, 19 Sep 2024 11:43:15 +0200 Subject: [PATCH 01/17] Update README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 17fe465..5b34e83 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # My Blog Technology -This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. You can see it in action at http://playin.coz.is/index.html. You probably can't get it to crash, but feel free to try! And if you manage to do it, send me an email to show off! I'll leave the coolest attempts in `attempts.txt`. +This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. You can see it in action at http://playin.coz.is/index.html (It's running the dev branch). + +I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes and gigabytes of very funny and malicious request logs. I copied a couple into `attempts.txt`. Maybe one day I'll go over the logs to get some new ones :^) # Specs - Only runs on Linux From d75e3e6a3d15352e15b88d5d827e73210758486c Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Wed, 25 Sep 2024 00:54:11 +0200 Subject: [PATCH 02/17] Update README --- README.md | 83 +++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 71 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4778d74..b33c6bd 100644 --- a/README.md +++ b/README.md @@ -4,23 +4,69 @@ This is a minimal web server designed to serve my blog. I'm writing it to be rob I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes and gigabytes of very funny and malicious request logs. I copied a couple into `attempts.txt`. Maybe one day I'll go over the logs to get some new ones :^) # Specs -- Only runs on Linux -- HTTP/1.1 support with pipelining and keep-alive -- HTTPS (TLS 1.2 using BearSSL) -- Uses request and connection timeouts -- Access log, log file rotation, hard disk usage limits +- Only Linux is supported +- Implements HTTP/1.1, pipelining, and keep-alive connections +- HTTPS (up to TLS 1.2 using BearSSL) +- Minimal dependencies (libc and BearSSL when using HTTPS) +- Configurable timeouts +- Access log, crash log, log file rotation, hard disk usage limits - No `Transfer-Encoding: Chunked` (when receiving a chunked request the server responds with `411 Length Required`, prompting the client to try again with the `Content-Length` header) -- Static file serving utilities - Single core (This will probably change when I get a better VPS) +- No static file caching (yet) -# Building -By default the server is built without HTTPS and you can do so by doing: +# Benchmarks +The focus of the server is robustness, but it's definitely not slow. Here's a quick compatison agains nginx (static endpoint, both single-threaded, 1K connection limit) +``` +(blogtech) +$ wrk -c 500 -d 5s http://127.0.0.1:80/hello +Running 5s test @ http://127.0.0.1:80/hello + 2 threads and 500 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 6.66ms 3.71ms 48.87ms 92.30% + Req/Sec 39.59k 6.43k 50.60k 67.35% + 385975 requests in 5.01s, 30.55MB read +Requests/sec: 76974.24 +Transfer/sec: 6.09MB + +(nginx) +$ wrk -c 500 -d 5s http://127.0.0.1:8080/hello +Running 5s test @ http://127.0.0.1:8080/hello + 2 threads and 500 connections + Thread Stats Avg Stdev Max +/- Stdev + Latency 149.11ms 243.02ms 934.12ms 81.80% + Req/Sec 24.97k 16.87k 57.73k 61.11% + 224790 requests in 5.08s, 42.01MB read +Requests/sec: 44227.78 +Transfer/sec: 8.27MB +``` + +Nginx uses this configuration: +``` +worker_processes 1; + +events { + worker_connections 1024; +} + +http { + server { + listen 8080; + location /hello { + add_header Content-Type text/plain; + return 200 "Hello, world!"; + } + } +} +``` + +# Build and run +By default the server build is HTTP-only: ``` $ make ``` -this will generate `serve`, `serve_cov`, and `serve_debug`. These are respectively release, coverage, and debug build. Unless you're modifying the source you need to use `serve`. +this will generate the executables `serve` (release build), `serve_cov` (coverage build), and `serve_debug` (debug build). -If you want to enable HTTPS, you'll need to create a `3p` directory (in the same folder as this README) and clone BearSSL in it. Then you'll need to build it. +To enable HTTPS, you'll need to clone BearSSL and build it. You can do so by running these commands from the root folder of this repository: ``` $ mkdir 3p $ cd 3p @@ -30,9 +76,22 @@ $ make -j $ cd ../../ $ make -B HTTPS=1 ``` -which will produce the same executables but with HTTPS enabled. Your private key `key.pem` and certificate `cert.pem` will need to be stored in the same folder as the executable. +which will produce the usual executables with HTTPS enabled. The HTTPS server will continue serving HTTP content on port 80. -NOTE: If you already built the files and want to build them again with a different HTTPS setting, you'll need to force the build with the `-B` option +The Certificate "cert.pem" and private key "key.pem" need to be placed in the same directory as the executable. You can change their default name and/or location by modifying the symbols +``` +#define HTTPS_KEY_FILE "key.pem" +#define HTTPS_CERT_FILE "cert.pem" +``` +If you just want to test the HTTPS server locally, you can use a self-signed certificate. First, generate a private key: +``` +openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048 +``` +then the certificate: +``` +openssl req -new -x509 -key key.pem -out cert.pem -days 365 +``` +when sending requests with curl or similar tools you'll need to allow self-signed certificated. # Testing I routinely run the server under valgrind or sanitizers (address, undefined) and target it using `wrk`. I'm also adding automatized tests to `tests/test.py` to check compliance with the HTTP/1.1 spec. From add107d679bfdd1ed333c62939df5b77f1c289c1 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Wed, 25 Sep 2024 01:03:33 +0200 Subject: [PATCH 03/17] Update README --- README.md | 49 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index b33c6bd..f9dd4a3 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # My Blog Technology -This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. You can see it in action at http://playin.coz.is/index.html (It's running the dev branch). +This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. You can see it in action at http://playin.coz.is/index.html. I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes and gigabytes of very funny and malicious request logs. I copied a couple into `attempts.txt`. Maybe one day I'll go over the logs to get some new ones :^) @@ -76,10 +76,10 @@ $ make -j $ cd ../../ $ make -B HTTPS=1 ``` -which will produce the usual executables with HTTPS enabled. The HTTPS server will continue serving HTTP content on port 80. +The same executables as the HTTP-only will be generated, except they'll also listen on port 443 for secure connections. -The Certificate "cert.pem" and private key "key.pem" need to be placed in the same directory as the executable. You can change their default name and/or location by modifying the symbols -``` +The Certificate `cert.pem` and private key `key.pem` need to be placed in the same directory as the executable. You can change their default name and/or location by modifying the symbols +```c #define HTTPS_KEY_FILE "key.pem" #define HTTPS_CERT_FILE "cert.pem" ``` @@ -91,7 +91,46 @@ then the certificate: ``` openssl req -new -x509 -key key.pem -out cert.pem -days 365 ``` -when sending requests with curl or similar tools you'll need to allow self-signed certificated. + +# Usage +The server is hardcoded to serve static content in the `docroot/` folder. You can place your files there or you can change this behavior by modifying the `respond` function +```c +typedef struct { + Method method; + string path; + int major; + int minor; + int nheaders; + Header headers[MAX_HEADERS]; + string content; +} Request; + +void respond(Request request, ResponseBuilder *b) +{ + if (request.major != 1 || request.minor > 1) { + status_line(b, 505); // HTTP Version Not Supported + return; + } + + if (request.method != M_GET) { + status_line(b, 405); // Method Not Allowed + return; + } + + if (string_match_case_insensitive(request.path, LIT("/hello"))) { + status_line(b, 200); + append_content_s(b, LIT("Hello, world!")); + return; + } + + if (serve_file_or_dir(b, LIT("/"), LIT("docroot/"), request.path, NULLSTR, false)) + return; + + status_line(b, 404); + append_content_s(b, LIT("Nothing here :|")); +} +``` +you can add your endpoints here by switching on the `request.path` field. Note that the path is just a slice into the request buffer. URIs are not parsed. # Testing I routinely run the server under valgrind or sanitizers (address, undefined) and target it using `wrk`. I'm also adding automatized tests to `tests/test.py` to check compliance with the HTTP/1.1 spec. From 2bbee4f8a51a78d2d33f40f96e54de8c6d96bb39 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Wed, 25 Sep 2024 01:19:40 +0200 Subject: [PATCH 04/17] Update README --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index f9dd4a3..92cc0ba 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,11 @@ # My Blog Technology -This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. You can see it in action at http://playin.coz.is/index.html. +This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. No need for reverse proxies! You can see it in action at http://playin.coz.is/index.html. I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes and gigabytes of very funny and malicious request logs. I copied a couple into `attempts.txt`. Maybe one day I'll go over the logs to get some new ones :^) +# But.. Why? +I enjoy making my own tools, and always hearing about how you need to use battle-tested software makes me sad. So what it will crash? Bugs can be fixed :^) + # Specs - Only Linux is supported - Implements HTTP/1.1, pipelining, and keep-alive connections @@ -15,7 +18,7 @@ I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_m - No static file caching (yet) # Benchmarks -The focus of the server is robustness, but it's definitely not slow. Here's a quick compatison agains nginx (static endpoint, both single-threaded, 1K connection limit) +The focus of the server is robustness, but it's definitely not slow. Here's a quick comparison agains nginx (static endpoint, both single-threaded, 1K connection limit) ``` (blogtech) $ wrk -c 500 -d 5s http://127.0.0.1:80/hello @@ -64,7 +67,7 @@ By default the server build is HTTP-only: ``` $ make ``` -this will generate the executables `serve` (release build), `serve_cov` (coverage build), and `serve_debug` (debug build). +this will generate the executables `serve` (release build), `serve_cov` (coverage build), and `serve_debug` (debug build). Release builds listen on port 80, while debug builds on port 8080. To enable HTTPS, you'll need to clone BearSSL and build it. You can do so by running these commands from the root folder of this repository: ``` @@ -76,7 +79,7 @@ $ make -j $ cd ../../ $ make -B HTTPS=1 ``` -The same executables as the HTTP-only will be generated, except they'll also listen on port 443 for secure connections. +The same executables as the HTTP-only will be generated, except they'll also listen for secure connections on port 443 for release builds and port 8081 for debug builds. The Certificate `cert.pem` and private key `key.pem` need to be placed in the same directory as the executable. You can change their default name and/or location by modifying the symbols ```c From 0fec23bd33c5d4da4f49932e94961cb293a74ed6 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Wed, 25 Sep 2024 01:33:50 +0200 Subject: [PATCH 05/17] Update README --- README.md | 34 ++++++++++++++++------------------ 1 file changed, 16 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 92cc0ba..c23a2a1 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,24 @@ # My Blog Technology -This is a minimal web server designed to serve my blog. I'm writing it to be robust enough to face the public internet. No need for reverse proxies! You can see it in action at http://playin.coz.is/index.html. +This is a minimal web server designed to host my blog. It's built from scratch to be robust enough to face the public internet. No reverse proxies required! You can see it in action at http://playin.coz.is/index.html. -I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes and gigabytes of very funny and malicious request logs. I copied a couple into `attempts.txt`. Maybe one day I'll go over the logs to get some new ones :^) +I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes of hilarious and malicious request logs. I saved some in `attempts.txt`, and may dig out a few more for fun someday :^) # But.. Why? -I enjoy making my own tools, and always hearing about how you need to use battle-tested software makes me sad. So what it will crash? Bugs can be fixed :^) +I enjoy making my own tools and I'm a bit tired of hearing that everything needs to be "battle-tested." So what it will crash? Bugs can be fixed :^) # Specs -- Only Linux is supported +- Linux only - Implements HTTP/1.1, pipelining, and keep-alive connections -- HTTPS (up to TLS 1.2 using BearSSL) +- HTTPS support (up to TLS 1.2 using BearSSL) - Minimal dependencies (libc and BearSSL when using HTTPS) - Configurable timeouts -- Access log, crash log, log file rotation, hard disk usage limits -- No `Transfer-Encoding: Chunked` (when receiving a chunked request the server responds with `411 Length Required`, prompting the client to try again with the `Content-Length` header) +- Access logs, crash logs, log rotation, disk usage limits +- No `Transfer-Encoding: Chunked` (responds with `411 Length Required`, prompting the client to resend with `Content-Length`) - Single core (This will probably change when I get a better VPS) - No static file caching (yet) # Benchmarks -The focus of the server is robustness, but it's definitely not slow. Here's a quick comparison agains nginx (static endpoint, both single-threaded, 1K connection limit) +The focus of the project is robustness, but it's definitely not slow. Here's a quick comparison agains nginx (static endpoint, both single-threaded, 1K connection limit) ``` (blogtech) $ wrk -c 500 -d 5s http://127.0.0.1:80/hello @@ -62,12 +62,12 @@ http { } ``` -# Build and run +# Build & Run By default the server build is HTTP-only: ``` $ make ``` -this will generate the executables `serve` (release build), `serve_cov` (coverage build), and `serve_debug` (debug build). Release builds listen on port 80, while debug builds on port 8080. +this generates the executables: `serve` (release build), `serve_cov` (coverage build), and `serve_debug` (debug build). Release builds listen on port 80; debug builds on port 8080. To enable HTTPS, you'll need to clone BearSSL and build it. You can do so by running these commands from the root folder of this repository: ``` @@ -79,24 +79,22 @@ $ make -j $ cd ../../ $ make -B HTTPS=1 ``` -The same executables as the HTTP-only will be generated, except they'll also listen for secure connections on port 443 for release builds and port 8081 for debug builds. +The same executables will be generated, but with secure connections on port 443 (release) or 8081 (debug). -The Certificate `cert.pem` and private key `key.pem` need to be placed in the same directory as the executable. You can change their default name and/or location by modifying the symbols +Place your `cert.pem` and `key.pem` files in the same directory as the executable. You can customiza names and locations by changing: ```c #define HTTPS_KEY_FILE "key.pem" #define HTTPS_CERT_FILE "cert.pem" ``` -If you just want to test the HTTPS server locally, you can use a self-signed certificate. First, generate a private key: + +For testing locally with HTTPS, generate a self-signed certificate (and private key): ``` openssl genpkey -algorithm RSA -out key.pem -pkeyopt rsa_keygen_bits:2048 -``` -then the certificate: -``` openssl req -new -x509 -key key.pem -out cert.pem -days 365 ``` # Usage -The server is hardcoded to serve static content in the `docroot/` folder. You can place your files there or you can change this behavior by modifying the `respond` function +The server serves static content from the `docroot/` folder. You can change this by modifying the `respond` function: ```c typedef struct { Method method; @@ -136,7 +134,7 @@ void respond(Request request, ResponseBuilder *b) you can add your endpoints here by switching on the `request.path` field. Note that the path is just a slice into the request buffer. URIs are not parsed. # Testing -I routinely run the server under valgrind or sanitizers (address, undefined) and target it using `wrk`. I'm also adding automatized tests to `tests/test.py` to check compliance with the HTTP/1.1 spec. +I routinely run the server under valgrind and sanitizers (address, undefined) and target it using `wrk`. I'm also adding automatized tests to `tests/test.py` to check compliance with the HTTP/1.1 spec. I also use it to host my website and post it here and there to keep it under stress.Turns out, all of those bots scanning he internet for vulnerable websites make great fuzzers! # Known Issues - Server replies to HTTP/1.0 clients as HTTP/1.1 From 7cdc02aaab3ac31090280b5cb4431ec20afb2da6 Mon Sep 17 00:00:00 2001 From: Victor Widell Date: Wed, 25 Sep 2024 13:20:32 +0200 Subject: [PATCH 06/17] Fixed spelling --- docroot/index.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docroot/index.html b/docroot/index.html index 7f88bb9..f493c21 100644 --- a/docroot/index.html +++ b/docroot/index.html @@ -149,7 +149,7 @@

Projects

-

BPR Renderer

+

PBR Renderer

It's a 3D renderer I built to dive deeper into graphics programming, using as reference the great LearnOpenGL tutorial and Google's Filament. The renderer implements Physically Based Rendering (PBR), a technique that simulates light and shadows to closely mimic real-world behavior. It supports shadow mapping, Image-Based Lighting (IBL), and can load meshes from external files.

From c791232418e36a9a1335d64428498edb2c9d88e8 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Wed, 25 Sep 2024 13:51:57 +0200 Subject: [PATCH 07/17] Add Contributing paragraph to README --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index c23a2a1..31a5be1 100644 --- a/README.md +++ b/README.md @@ -138,3 +138,6 @@ I routinely run the server under valgrind and sanitizers (address, undefined) an # Known Issues - Server replies to HTTP/1.0 clients as HTTP/1.1 + +# Contributing +I usually work on the DEV branch and merge into MAIN once in a while. If you open a pull requests remember to target DEV. It will make things easier! \ No newline at end of file From b9cb3f92d767d0246cd48d69a6cb0b8dc1f1c253 Mon Sep 17 00:00:00 2001 From: Yonas Yanfa Date: Wed, 25 Sep 2024 22:15:15 -0400 Subject: [PATCH 08/17] Create testing.yaml --- .github/workflows/testing.yaml | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 .github/workflows/testing.yaml diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml new file mode 100644 index 0000000..08ba05b --- /dev/null +++ b/.github/workflows/testing.yaml @@ -0,0 +1,24 @@ +name: Testing + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: make + run: make + - name: Set up Python 3.12 + uses: actions/setup-python@v3 + with: + python-version: "3.12" + - name: Run tests + run: | + cd tests + python test.py From 8e121f02454c36376b2f54ec3d684408345d0f14 Mon Sep 17 00:00:00 2001 From: Yonas Date: Wed, 25 Sep 2024 22:31:51 -0400 Subject: [PATCH 09/17] Return status exit code 1 if test failed. --- tests/test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/test.py b/tests/test.py index c05cb0b..1ec632d 100644 --- a/tests/test.py +++ b/tests/test.py @@ -1,6 +1,7 @@ import time import socket import subprocess +import sys from typing import Optional from dataclasses import dataclass @@ -151,3 +152,6 @@ def run_test(test, addr, port): print("passed: ", passed, "/", total, sep="") p.terminate() p.wait() + +if passed < total: + sys.exit(1) From fd629fc519120ac3e6cac065fda8cf5d1cff0be4 Mon Sep 17 00:00:00 2001 From: Francesco Cozzuto Date: Thu, 26 Sep 2024 10:17:57 +0200 Subject: [PATCH 10/17] Update README --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 31a5be1..052b92c 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,10 @@ This is a minimal web server designed to host my blog. It's built from scratch t I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes of hilarious and malicious request logs. I saved some in `attempts.txt`, and may dig out a few more for fun someday :^) +There is also a discussion on [Hacker News](https://news.ycombinator.com/item?id=41642151) + +Feel free to help! At this time the main focus is on semantic correctess of HTTP and testing. I try to keep the main branch stable so remember to target the dev branch with PRs. Changes to README are fine to do on main though. + # But.. Why? I enjoy making my own tools and I'm a bit tired of hearing that everything needs to be "battle-tested." So what it will crash? Bugs can be fixed :^) @@ -138,6 +142,4 @@ I routinely run the server under valgrind and sanitizers (address, undefined) an # Known Issues - Server replies to HTTP/1.0 clients as HTTP/1.1 - -# Contributing -I usually work on the DEV branch and merge into MAIN once in a while. If you open a pull requests remember to target DEV. It will make things easier! \ No newline at end of file +- Server rejects HEAD requests From 1cbcb3334f7a3aacbf3d59235d5a924b68583810 Mon Sep 17 00:00:00 2001 From: Yonas Date: Wed, 25 Sep 2024 22:37:16 -0400 Subject: [PATCH 11/17] Seperate build and test jobs. --- .github/workflows/testing.yaml | 52 +++++++++++++++++++++++++++------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 08ba05b..2332b09 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -2,9 +2,9 @@ name: Testing on: push: - branches: [ "main" ] + branches: [ "main", "dev" ] pull_request: - branches: [ "main" ] + branches: [ "main", "dev" ] jobs: build: @@ -12,13 +12,45 @@ jobs: steps: - uses: actions/checkout@v4 + - name: make - run: make - - name: Set up Python 3.12 - uses: actions/setup-python@v3 - with: - python-version: "3.12" - - name: Run tests run: | - cd tests - python test.py + make + mkdir bin + bash -c 'mv {serve,serve_cov,serve_debug} bin/' + + - name: Temporarily save artifacts + uses: actions/upload-artifact@v4 + with: + name: artifacts + path: bin + retention-days: 1 + + test: + needs: [build] + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Retrieve saved artifacts + uses: actions/download-artifact@v4 + with: + name: artifacts + path: bin + + - name: Move artifacts to project root + run: | + chmod +x bin/* + mv bin/* . + + - name: Set up Python 3.12 + uses: actions/setup-python@v3 + with: + python-version: "3.12" + + - name: Run tests + run: | + cd tests + python test.py From 810febdd2befbf51ab41a4892fcd9ead48ff6781 Mon Sep 17 00:00:00 2001 From: Yonas Date: Thu, 26 Sep 2024 09:45:03 -0400 Subject: [PATCH 12/17] Add badges to README.md --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 31a5be1..47792aa 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ # My Blog Technology + +![Builds](https://github.com/cozis/blogtech/actions/workflows/testing.yaml/badge.svg) +[![GitHub Release](https://img.shields.io/github/release/cozis/blogtech.svg)](https://github.com/cozis/blogtech/releases/latest) +[![License](https://img.shields.io/github/license/cozis/blogtech.svg)](https://github.com/cozis/blogtech/blob/main/UNLICENSE) + This is a minimal web server designed to host my blog. It's built from scratch to be robust enough to face the public internet. No reverse proxies required! You can see it in action at http://playin.coz.is/index.html. I asked [Reddit](https://www.reddit.com/r/C_Programming/comments/1falo3b/using_my_c_web_server_to_host_a_blog_you_cant/) to [hack](https://www.reddit.com/r/hacking/comments/1fcc5hd/im_using_my_custom_c_webserver_to_host_my_blog_no/) me, which resulted in gigabytes of hilarious and malicious request logs. I saved some in `attempts.txt`, and may dig out a few more for fun someday :^) @@ -140,4 +145,4 @@ I routinely run the server under valgrind and sanitizers (address, undefined) an - Server replies to HTTP/1.0 clients as HTTP/1.1 # Contributing -I usually work on the DEV branch and merge into MAIN once in a while. If you open a pull requests remember to target DEV. It will make things easier! \ No newline at end of file +I usually work on the DEV branch and merge into MAIN once in a while. If you open a pull requests remember to target DEV. It will make things easier! From 97d698132addd452c65af70f703dc58e9d4b95a4 Mon Sep 17 00:00:00 2001 From: Yonas Date: Thu, 26 Sep 2024 09:55:22 -0400 Subject: [PATCH 13/17] Add changelog generator workflow. --- .github/workflows/changelog.yaml | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 .github/workflows/changelog.yaml diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml new file mode 100644 index 0000000..c2f2383 --- /dev/null +++ b/.github/workflows/changelog.yaml @@ -0,0 +1,39 @@ +name: Changelog + +on: + push: + tags: + - "v*.*.*" + +jobs: + changelog: + name: Generate and publish changelog + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Generate a changelog + uses: orhun/git-cliff-action@v4 + id: git-cliff + with: + config: cliff.toml + args: --verbose --latest --strip header + env: + OUTPUT: CHANGELOG.md + GITHUB_REPO: ${{ github.repository }} + + - name: Polish changelog + shell: bash + run: sed -i '1,2d' CHANGELOG.md + + - name: Upload the changelog + uses: ncipollo/release-action@v1 + with: + # draft: true + allowUpdates: true + bodyFile: CHANGELOG.md From 02064650f68d4a43cf8ce529ef81833bf3598a96 Mon Sep 17 00:00:00 2001 From: Yonas Date: Thu, 26 Sep 2024 10:04:48 -0400 Subject: [PATCH 14/17] Add CodeQL code quality workflow. --- .github/workflows/codeql.yaml | 94 +++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 .github/workflows/codeql.yaml diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml new file mode 100644 index 0000000..77ec9bd --- /dev/null +++ b/.github/workflows/codeql.yaml @@ -0,0 +1,94 @@ +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +on: + push: + branches: [ "main", "dev" ] + pull_request: + branches: [ "main", "dev" ] + schedule: + - cron: '19 8 * * 2' + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: autobuild + - language: python + build-mode: none + # CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' + # Use `c-cpp` to analyze code written in C, C++ or both + # Use 'java-kotlin' to analyze code written in Java, Kotlin or both + # Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both + # To learn more about changing the languages that are analyzed or customizing the build mode for your analysis, + # see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning. + # If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how + # your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + # Initializes the CodeQL tools for scanning. + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + # If you wish to specify custom queries, you can do so here or in a config file. + # By default, queries listed here will override any specified in a config file. + # Prefix the list here with "+" to use these queries and those in the config file. + + # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs + # queries: security-extended,security-and-quality + + # If the analyze step fails for one of the languages you are analyzing with + # "We were unable to automatically build your code", modify the matrix above + # to set the build mode to "manual" for that language. Then modify this step + # to build your code. + # â„šī¸ Command-line programs to run using the OS shell. + # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun + - if: matrix.build-mode == 'manual' + shell: bash + run: | + echo 'If you are using a "manual" build mode for one or more of the' \ + 'languages you are analyzing, replace this with the commands to build' \ + 'your code, for example:' + echo ' make bootstrap' + echo ' make release' + exit 1 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" From fc09343f3a3daed192a7cd54e825f39ecdf469b7 Mon Sep 17 00:00:00 2001 From: Yonas Date: Thu, 26 Sep 2024 10:17:01 -0400 Subject: [PATCH 15/17] Add lint and formatting workflow. --- .github/workflows/linting.yaml | 56 ++++++++++++++++++++++++++++++++++ .github/workflows/testing.yaml | 2 +- README.md | 3 +- 3 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 .github/workflows/linting.yaml diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml new file mode 100644 index 0000000..46037ec --- /dev/null +++ b/.github/workflows/linting.yaml @@ -0,0 +1,56 @@ +name: Lint and Format + +on: + push: + branches: [ "main", "dev" ] + pull_request: + branches: [ "main", "dev" ] + +jobs: + lint: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Setup environment + run: | + python3 -m venv venv + ./venv/bin/pip install pylint + + - name: Run pylint + run: | + ./venv/bin/pylint tests + + formatting: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Python 3.12 + uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Setup environment + run: | + python3 -m venv venv + ./venv/bin/pip install black + + - name: Run formatters + run: | + ./venv/bin/black tests + + - name: Check for changes + run: | + if [[ -n $(git status --porcelain) ]]; then + echo "Please commit the following formatting changes:\n" + git diff + exit 1 + fi diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index 2332b09..db49328 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -46,7 +46,7 @@ jobs: mv bin/* . - name: Set up Python 3.12 - uses: actions/setup-python@v3 + uses: actions/setup-python@v5 with: python-version: "3.12" diff --git a/README.md b/README.md index bb7d8d2..dc921dc 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ I routinely run the server under valgrind and sanitizers (address, undefined) an # Known Issues - Server replies to HTTP/1.0 clients as HTTP/1.1 +- Server rejects HEAD requests # Contributing -I usually work on the DEV branch and merge into MAIN once in a while. If you open a pull requests remember to target DEV. It will make things easier! \ No newline at end of file +I usually work on the [DEV](https://github.com/cozis/blogtech/tree/dev) branch and merge into [MAIN](https://github.com/cozis/blogtech/tree/main) once in a while. If you open a pull requests remember to target [DEV](https://github.com/cozis/blogtech/tree/dev). It will make things easier! From 347d161a5306c1bf196834f02b7140247a19d435 Mon Sep 17 00:00:00 2001 From: Yonas Date: Thu, 26 Sep 2024 13:01:02 -0400 Subject: [PATCH 16/17] Add release publishing workflow. --- .github/workflows/changelog.yaml | 1 + .github/workflows/release.yaml | 38 ++++++++++++++++++++++++++++++++ .github/workflows/testing.yaml | 1 + 3 files changed, 40 insertions(+) create mode 100644 .github/workflows/release.yaml diff --git a/.github/workflows/changelog.yaml b/.github/workflows/changelog.yaml index c2f2383..447a84b 100644 --- a/.github/workflows/changelog.yaml +++ b/.github/workflows/changelog.yaml @@ -1,6 +1,7 @@ name: Changelog on: + workflow_call: push: tags: - "v*.*.*" diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..5233db3 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,38 @@ +on: + push: + branches: [ "main" ] + tags: + - 'v*' + +name: Release Packaging + +permissions: + contents: write + +jobs: + tests: + uses: ./.github/workflows/testing.yaml + + changelog: + uses: ./.github/workflows/changelog.yaml + + release: + needs: [tests, changelog] + name: Release Packaging + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Release Build + run: make + + - name: Create Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ github.ref_name }} + run: | + gh release create "$tag" \ + --repo="$GITHUB_REPOSITORY" \ + --title="${tag#v}" \ + --generate-notes diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index db49328..bdd7fde 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -1,6 +1,7 @@ name: Testing on: + workflow_call: push: branches: [ "main", "dev" ] pull_request: From 993e696a9d30afe33a6d8aae643901c355b8413a Mon Sep 17 00:00:00 2001 From: Yonas Date: Thu, 26 Sep 2024 13:08:58 -0400 Subject: [PATCH 17/17] Fix formatting. --- .github/workflows/codeql.yaml | 8 ++++++-- .github/workflows/linting.yaml | 8 ++++++-- .github/workflows/release.yaml | 3 ++- .github/workflows/testing.yaml | 8 ++++++-- 4 files changed, 20 insertions(+), 7 deletions(-) diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 77ec9bd..11931fc 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -13,9 +13,13 @@ name: "CodeQL Advanced" on: push: - branches: [ "main", "dev" ] + branches: + - main + - dev pull_request: - branches: [ "main", "dev" ] + branches: + - main + - dev schedule: - cron: '19 8 * * 2' diff --git a/.github/workflows/linting.yaml b/.github/workflows/linting.yaml index 46037ec..787f45c 100644 --- a/.github/workflows/linting.yaml +++ b/.github/workflows/linting.yaml @@ -2,9 +2,13 @@ name: Lint and Format on: push: - branches: [ "main", "dev" ] + branches: + - main + - dev pull_request: - branches: [ "main", "dev" ] + branches: + - main + - dev jobs: lint: diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 5233db3..32f5fed 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -1,6 +1,7 @@ on: push: - branches: [ "main" ] + branches: + - main tags: - 'v*' diff --git a/.github/workflows/testing.yaml b/.github/workflows/testing.yaml index bdd7fde..77e571e 100644 --- a/.github/workflows/testing.yaml +++ b/.github/workflows/testing.yaml @@ -3,9 +3,13 @@ name: Testing on: workflow_call: push: - branches: [ "main", "dev" ] + branches: + - main + - dev pull_request: - branches: [ "main", "dev" ] + branches: + - main + - dev jobs: build: