{"id":15225226,"url":"https://github.com/c-cube/tiny_httpd","last_synced_at":"2026-02-16T04:06:02.946Z","repository":{"id":36120282,"uuid":"221620396","full_name":"c-cube/tiny_httpd","owner":"c-cube","description":"Minimal HTTP server using good old threads + blocking IO, with a small request router.","archived":false,"fork":false,"pushed_at":"2026-02-09T04:30:41.000Z","size":8162,"stargazers_count":83,"open_issues_count":10,"forks_count":12,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-02-09T09:43:06.158Z","etag":null,"topics":["http","httpd","ocaml","simplehttpserver","threads","tiny"],"latest_commit_sha":null,"homepage":"https://c-cube.github.io/tiny_httpd","language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/c-cube.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGES.md","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-11-14T05:39:25.000Z","updated_at":"2025-12-12T16:33:01.000Z","dependencies_parsed_at":"2023-12-20T07:28:30.661Z","dependency_job_id":"3d6d16d5-9076-44db-a693-4d3c1be4afec","html_url":"https://github.com/c-cube/tiny_httpd","commit_stats":{"total_commits":493,"total_committers":9,"mean_commits":54.77777777777778,"dds":"0.10344827586206895","last_synced_commit":"d38eb852f807c87bd5ccc8be069eecb5a098d222"},"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"purl":"pkg:github/c-cube/tiny_httpd","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Ftiny_httpd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Ftiny_httpd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Ftiny_httpd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Ftiny_httpd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/c-cube","download_url":"https://codeload.github.com/c-cube/tiny_httpd/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/c-cube%2Ftiny_httpd/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29499815,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-16T03:57:51.541Z","status":"ssl_error","status_checked_at":"2026-02-16T03:55:59.854Z","response_time":115,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http","httpd","ocaml","simplehttpserver","threads","tiny"],"created_at":"2024-09-28T18:05:13.083Z","updated_at":"2026-02-16T04:06:02.909Z","avatar_url":"https://github.com/c-cube.png","language":"OCaml","readme":"# Tiny_httpd [![build](https://github.com/c-cube/tiny_httpd/workflows/build/badge.svg)](https://github.com/c-cube/tiny_httpd/actions)\n\nMinimal HTTP server using good old threads, with stream abstractions,\nsimple routing, URL encoding/decoding, static asset serving,\nand optional compression with camlzip.\nIt also supports [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events)\n([w3c](https://html.spec.whatwg.org/multipage/server-sent-events.html#event-stream-interpretation))\n\nFree from all forms of `ppx`, async monads, etc. 🙃\n\n**Note**: it can be useful to add the `jemalloc` opam package for long running\nserver, as it does a good job at controlling memory usage.\n\nThe basic echo server from `src/examples/echo.ml`:\n\n```ocaml\n\nmodule S = Tiny_httpd\n\nlet () =\n  let server = S.create () in\n  (* say hello *)\n  S.add_route_handler ~meth:`GET server\n    S.Route.(exact \"hello\" @/ string @/ return)\n    (fun name _req -\u003e S.Response.make_string (Ok (\"hello \" ^name ^\"!\\n\")));\n  (* echo request *)\n  S.add_route_handler server\n    S.Route.(exact \"echo\" @/ return)\n    (fun req -\u003e S.Response.make_string (Ok (Format.asprintf \"echo:@ %a@.\" S.Request.pp req)));\n  Printf.printf \"listening on http://%s:%d\\n%!\" (S.addr server) (S.port server);\n  match S.run server with\n  | Ok () -\u003e ()\n  | Error e -\u003e raise e\n```\n\n```sh\n$ dune exec src/examples/echo.exe \u0026\nlistening on http://127.0.0.1:8080\n\n# the path \"hello/name\" greets you.\n$ curl -X GET http://localhost:8080/hello/quadrarotaphile\nhello quadrarotaphile!\n\n# the path \"echo\" just prints the request.\n$ curl -X GET http://localhost:8080/echo --data \"howdy y'all\" \necho:\n{meth=GET;\n headers=Host: localhost:8080\n         User-Agent: curl/7.66.0\n         Accept: */*\n         Content-Length: 10\n         Content-Type: application/x-www-form-urlencoded;\n path=\"/echo\"; body=\"howdy y'all\"}\n\n```\n\n## `http_of_dir`\n\nSimilar to `python -m http.server`, a simple program `http_of_dir` is provided.\nIt serves files from the current directory.\n\n```sh\n$ http_of_dir . -p 8080 \u0026\n$ curl -X GET http://localhost:8080\n...\n\u003chtml list of current dir\u003e\n...\n\n```\n\n## Static assets and files\n\nThe program `http_of_dir` relies on the module `Tiny_httpd_dir`, which\ncan serve directories, as well as _virtual file systems_.\n\nIn 'examples/dune', we produce an OCaml module `vfs.ml` using\nthe program `tiny-httpd-vfs-pack`.  This module contains a VFS (virtual file\nsystem) which can be served as if it were an actual directory.\n\nThe dune rule:\n\n```lisp\n(rule\n  (targets vfs.ml)\n  (deps (source_tree files) (:out test_output.txt.expected))\n  (enabled_if (= %{system} \"linux\"))\n  (action (run ../src/bin/vfs_pack.exe -o %{targets}\n               --mirror=files/\n               --file=test_out.txt,%{out}\n               --url=example_dot_com,http://example.com)))\n```\n\nThe code to serve the VFS from `vfs.ml` is as follows:\n\n```ocaml\n  …\n  Tiny_httpd_dir.add_vfs server\n    ~config:(Tiny_httpd_dir.config ~download:true\n               ~dir_behavior:Tiny_httpd_dir.Index_or_lists ())\n    ~vfs:Vfs.vfs ~prefix:\"vfs\";\n  …\n```\n\nit allows downloading the files, and listing directories.\nIf a directory contains `index.html` then this will be served\ninstead of listing the content.\n\n## Steaming response body\n\nTiny_httpd provides multiple ways of returning a body in a response.\nThe response body type is:\n\n```ocaml\ntype body =\n  [ `String of string\n  | `Stream of byte_stream\n  | `Writer of Tiny_httpd_io.Writer.t\n  | `Void ]\n```\n\nThe simplest way is to return, say, `` `String \"hello\" ``. The response\nwill have a set content-length header and its body is just the string.\nSome responses don't have a body at all, which is where `` `Void `` is useful.\n\nThe `` `Stream _ `` case is more advanced and really only intended for experts.\n\nThe `` `Writer w `` is new, and is intended as an easy way to write the\nbody in a streaming fashion. See 'examples/writer.ml' to see a full example.\nTypically the idea is to create the body with `Tiny_httpd_io.Writer.make ~write ()`\nwhere `write` will be called with an output channel (the connection to the client),\nand can write whatever it wants to this channel. Once the `write` function returns\nthe body has been fully sent and the next request can be processed.\n\n## Socket activation\n\nSince version 0.10, socket activation is supported indirectly, by allowing a\nsocket to be explicitly passed in to the `create` function:\n\n```ocaml\nmodule S = Tiny_httpd\n\nlet not_found _ _ = S.Response.fail ~code:404 \"Not Found\\n\"\n\nlet () =\n  (* Module [Daemon] is from the [ocaml-systemd] package *)\n  let server = match Daemon.listen_fds () with\n    (* If no socket passed in, assume server was started explicitly i.e. without\n       socket activation *)\n    | [] -\u003e S.create ()\n\n    (* If a socket passed in e.g. by systemd, listen on that *)\n    | sock :: _ -\u003e S.create ~sock ()\n  in\n  S.add_route_handler server S.Route.rest_of_path not_found;\n  Printf.printf \"Listening on http://%s:%d\\n%!\" (S.addr server) (S.port server);\n  match S.run server with\n  | Ok () -\u003e ()\n  | Error e -\u003e raise e\n```\n\nOn Linux, this requires the\n[ocaml-systemd](https://github.com/juergenhoetzel/ocaml-systemd) package:\n\n```\nopam install ocaml-systemd\n```\n\nTip: in the `dune` file, the package name should be `systemd`.\n\nIn case you're not familiar with socket activation, Lennart Poettering's\n[blog post](http://0pointer.de/blog/projects/socket-activation.html) explains it\nwell.\n\n## Why?\n\nWhy not? If you just want a super basic local server (perhaps for exposing\ndata from a local demon, like Cups or Syncthing do), no need for a ton of\ndependencies or high scalability libraries.\n\nUse cases might include:\n\n- serve content directly from a static blog generator;\n- provide a web UI to some tool (like CUPS and syncthing do);\n- implement a basic monitoring page for a service;\n- provide a simple json API for a service, on top of http;\n- use `http_of_dir` to serve odoc-generated docs or some assets directory.\n\n## Documentation\n\nSee https://c-cube.github.io/tiny_httpd\n\n## License\n\nMIT.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Ftiny_httpd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fc-cube%2Ftiny_httpd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fc-cube%2Ftiny_httpd/lists"}