Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

██████╗ ███████╗███╗   ██╗███████╗████████╗
██╔══██╗██╔════╝████╗  ██║██╔════╝╚══██╔══╝
██████╔╝█████╗  ██╔██╗ ██║█████╗     ██║
██╔══██╗██╔══╝  ██║╚██╗██║██╔══╝     ██║
██████╔╝██║     ██║ ╚████║███████╗   ██║
╚═════╝ ╚═╝     ╚═╝  ╚═══╝╚══════╝   ╚═╝

Just an HTTP server, except brainfuck runs the entire thing :3

CI Release Rust License: MIT Made by Elchi


Overview

Every "brainfuck web server" you'll find out there cheats the same way: some real language handles the socket, brainfuck just fills in a response body. Fair enough, brainfuck genuinely can't do networking - its only I/O is a byte in, a byte out.

bfnet closes that gap with a handful of extra instructions, kept as narrow and single-purpose as possible rather than exposing a generic syscall gateway. The accept loop, connection handling, routing, even outbound connections - all of it lives inside the .bf file. bfnet itself doesn't know what HTTP is; it's an instruction dispatcher and nothing else.

client ──TCP──▶ bfnet
                  │
                  ▼
            executes `~` or `&`  ───▶ waits for / forks on a connection
                  │
                  ▼
      tape runs, `,` `.` `?` `@` all operate on that connection
                  │
                  ▼
       loops back around for the next one (or the thread just ends)

This is not standard brainfuck. A vanilla interpreter treats the extra instructions as comment characters and none of this works. If you want something that runs on any bf interpreter out there, this isn't it - that would mean putting the networking outside brainfuck entirely, which defeats the point of this repo.

Instruction set

+ - increment / decrement the current cell
< > move the pointer left / right
[ ] standard brainfuck loop
, read one byte from the current connection
. write one byte to the current connection
~ close the current connection if any, block for the next one, wire it up as the , / . target
& accept like ~, but fork: a new thread continues after & with the connection and cell = 1, the original thread also continues after & with cell = 0 and no connection, and loops back for the next one
? write the peer's IPv4 + port into the current cell and the five after it (4 bytes IP, 2 bytes port), no pointer movement
@ connect out to the NUL-terminated "host:port" string starting at the current cell; on success it becomes the new , / . target and the current cell gets set to 1, otherwise 0

8 standard, 4 new. , and . don't change meaning, they just stop pointing at stdin/stdout and start pointing at whatever connection the current thread owns.

Build

cargo build --release

Binary lands at target/release/bfnet, a few hundred KB, no runtime deps.

Prebuilt binaries for Linux, macOS and Windows are attached to every release - grab one directly if you don't want to build it yourself.

Run

bfnet program.bf [port]

Port defaults to 8080.

Examples

bfnet examples/router.bf 8080
curl localhost:8080/about
File Uses Does
examples/hello-json.bf ~ fixed JSON body, same for every request
examples/hello-text.bf ~ fixed plain text body, same for every request
examples/concurrent.bf & same fixed response as hello-json, but connections actually overlap instead of queueing - try two requests at once
examples/whoami.bf & ? prints the caller's own IP and port back at them, in readable decimal
examples/notify.bf & @ answers the caller, then fires a fixed request at a second host as a side effect
examples/router.bf & real path-based routing (/, /about, /hello, 404 otherwise), byte-compared, no shortcuts

Writing your own

A minimal server, in full:

+[~>[-]<response bytes go here>.<]
  • + sets cell 0 to 1 and nothing ever touches it again, so [...] never exits
  • ~ blocks for a connection
  • >[-] moves to a scratch cell and zeroes it out - it's dirty from whatever the last response left behind
  • then come the actual response bytes
  • < moves back to cell 0 so the loop condition still holds next round

Swap ~ for & and you get concurrency, at the cost of needing to check which thread you are - see examples/concurrent.bf for the shape of that.

Writing responses byte-by-byte by hand works but gets old fast. tools/text2bf.py takes raw bytes on stdin and prints a ~-based program in exactly that shape:

cat response.txt | tools/text2bf.py > examples/whatever.bf

For anything with actual logic - routing, decimal formatting, and so on - tools/bfbuilder.py is a small Python code builder that tracks pointer position for you instead of hand-counting < and >. tools/route_gen.py and tools/build_examples.py are built on top of it and are a reasonable place to start if you want to see it used for something non-trivial. None of this is needed at runtime - the binary has zero Python involvement.

Status

Fixed response for any request
Multiple sequential connections, one process
Concurrent connections (&)
Peer IP/port visible to the program (?)
Outbound connections (@)
Path-based routing, parsed byte by byte in bf
Content-Length computed at runtime instead of build time 📅
True relay/proxying (two live connections at once) 📅
UDP 📅

Known limitations

  • one connection per thread - concurrency needs &, plain ~ still serves one at a time
  • a malformed program (unmatched brackets, pointer walking off either end of the tape) takes down whichever thread hit it - the main process and other in-flight connections are unaffected
  • @ only gives you one connection slot, same as ~ / &. Once you connect out, the original inbound connection is gone - there's no way to read from one connection and write to another at the same time, so true proxying isn't possible yet. notify.bf works around this by answering the real client before ever touching @
  • Content-Length is either baked in at build time (when the response is fixed) or left out entirely with Connection: close relied on instead (when it isn't, like in whoami.bf)

See CHANGELOG.md for what changed between releases.

License

MIT — LICENSE · built by Elchi-dev

About

Just an HTTP server, except brainfuck runs the entire thing :3

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages