+1
.gitignore
···
+98
-2
CLAUDE.md
···-Both of these are intended to act as a reference implementation, for us to figure out what the ideal OCaml interface should look like for FastCGI.+These are intended to act as a reference implementation for us to figure out what the ideal OCaml interface should look like for FastCGI.Our target language is OCaml, using the Eio library. The README for Eio is in OCaml-EIO-README.md to give you a reference.+- build while ignoring warnings: add `--profile=release` to the CLI to activate the profile that ignores warnings+Then examine the HTML docs built for that module. You will see that there are module references with __ in them, e.g. "Jmap__.Jmap_email_types.Email_address.t" which indicate that the module is being accessed directly instead of via the module aliases defined.+When adding OCaml documentation comments, be careful about ambiguous documentation comments. If you see errors like:+This usually means there isn't enough whitespace between the documentation comment and the code element it's documenting. Always:+3. When documenting record fields or variant constructors, place the comment after the field with at least one space+If in doubt, add more whitespace lines than needed - you can always clean this up later with `dune build @fmt` to get ocamlformat to sort out the whitespace properly.+When adding ocamldoc comments, use the information in the protocol specifications available to also add relevant explanations to the OCamldoc. Do not refer to the specification in the third-person, but directly include enough information in the OCamldoc for a reader to understand the protocol flow directly.+IMPORTANT: For all modules, use a nested module structure with a canonical `type t` inside each submodule. This approach ensures consistent type naming and logical grouping of related functionality.+1. Top-level files should define their main types directly (e.g., `jmap_identity.mli` should define identity-related types at the top level).+2. Related operations or specialized subtypes should be defined in nested modules within the file:+5. When a file is named after a concept (e.g., `jmap_identity.mli`), there's no need to have a matching nested module inside the file (e.g., `module Identity : sig...`), as the file itself represents that namespace.+This structured approach promotes encapsulation, consistent type naming, and clearer organization of related functionality.+1) we will generate OCaml interface files only, and no module implementations. The purpose here is to write and document the necessary type signatures. Once we generate these, we can check that they work with "dune build @check". Once that succeeds, we will build HTML documentation with "dune build @doc" in order to ensure the interfaces are reasonable.+2) once these interface files exist, we will build a series of sample binaries that will attempt to implement the library for some sample usecases. This binary will not fully link, but it should type check. The only linking error that we get should be from the missing library implementation that we are currently buildign.+3) we will calculate the dependency order for each module in our library, and work through an implementation of each one in increasing dependency order (that is, the module with the fewest dependencies should be handled first). For each module interface, we will generate a corresponding module implementation. We will also add test cases for this specific module, and update the dune files. Before proceeding to the next module, a build should be done to ensure the implementation builds and type checks as far as is possible.
+4
bin/dune
+79
bin/fcgi_server.ml
···+let method_ = Fastcgi.Record.KV.find_opt "REQUEST_METHOD" params |> Option.value ~default:"GET" in+let script_name = Fastcgi.Record.KV.find_opt "SCRIPT_NAME" params |> Option.value ~default:"" in
+7
config/Caddyfile
+27
dune-project
···+(description "A type-safe implementation of the FastCGI protocol for OCaml using the Eio effects-based IO library. Supports all three FastCGI roles: Responder, Authorizer, and Filter."))
+34
fastcgi.opam
···+"A type-safe implementation of the FastCGI protocol for OCaml using the Eio effects-based IO library. Supports all three FastCGI roles: Responder, Authorizer, and Filter."
+10
lib/dune
+50
lib/fastcgi.ml
···
+28
lib/fastcgi.mli
···
+305
lib/fastcgi_record.ml
···+else String.sub actual_content 0 max_content_len ^ "..." ^ Printf.sprintf " (%d more bytes)" (len - max_content_len)+"@[<2>{ version = %d;@ record_type = %a;@ request_id = %d;@ content = %S;@ offset = %d;@ length = %d }@]"+Printf.eprintf "[DEBUG] Fastcgi_record.read: Header parsed - version=%d, type=%d, id=%d, content_len=%d, padding=%d\n%!"+Printf.eprintf "[DEBUG] Fastcgi_record.read: Successfully read %d bytes\n%!" (String.length c);+Printf.eprintf "[DEBUG] Fastcgi_record.read: Skipping %d bytes of padding\n%!" padding_length;+let record = { version; record_type; request_id; content; offset = 0; length = String.length content } in
+131
lib/fastcgi_record.mli
···
+279
lib/fastcgi_request.ml
···+"@[<2>{ request_id = %d;@ role = %a;@ keep_conn = %b;@ params = %a;@ stdin = %d bytes;@ data = %s }@]"+Printf.eprintf "[DEBUG] read_stdin_from_flow: Got stream terminator, total stdin=%d bytes\n%!"+Printf.eprintf "[DEBUG] read_request_streams: Got STDIN data, %d bytes\n%!" (String.length stdin_data);+Printf.eprintf "[DEBUG] read_request_streams: Got STDIN data, %d bytes\n%!" (String.length stdin_data);+Printf.eprintf "[DEBUG] read_request_streams: Got DATA stream, %d bytes\n%!" (String.length data);+let record = Fastcgi_record.create ~record:record_type ~request_id ~content ~offset:pos ~length:chunk_len () in
+80
lib/fastcgi_request.mli
···+(** [write_end_request buf_write request_id app_status protocol_status] writes END_REQUEST record. *)+val write_end_request : Eio.Buf_write.t -> Fastcgi_record.request_id -> app_status -> protocol_status -> unit
+13
test/dune
···
+161
test/simple_test.ml
···
+123
test/test_cases/README.md
···+This directory contains binary test case files representing various FastCGI records as defined in the FastCGI specification. These files can be used to test a FastCGI parser implementation.+The first 8 bytes should always be the FastCGI header, followed by the record content and any padding.
test/test_cases/abort_request.bin
This is a binary file and will not be displayed.
test/test_cases/begin_request_filter.bin
This is a binary file and will not be displayed.
test/test_cases/begin_request_no_keep.bin
This is a binary file and will not be displayed.
test/test_cases/begin_request_responder.bin
This is a binary file and will not be displayed.
test/test_cases/data_empty.bin
This is a binary file and will not be displayed.
test/test_cases/data_filter.bin
This is a binary file and will not be displayed.
test/test_cases/end_request_error.bin
This is a binary file and will not be displayed.
test/test_cases/end_request_success.bin
This is a binary file and will not be displayed.
+349
test/test_cases/generate_test_cases.py
···
test/test_cases/get_values.bin
This is a binary file and will not be displayed.
test/test_cases/get_values_result.bin
This is a binary file and will not be displayed.
test/test_cases/large_record.bin
This is a binary file and will not be displayed.
test/test_cases/multiplexed_requests.bin
This is a binary file and will not be displayed.
test/test_cases/padded_record.bin
This is a binary file and will not be displayed.
test/test_cases/params_empty.bin
This is a binary file and will not be displayed.
test/test_cases/params_get.bin
This is a binary file and will not be displayed.
test/test_cases/params_post.bin
This is a binary file and will not be displayed.
test/test_cases/stderr_empty.bin
This is a binary file and will not be displayed.
test/test_cases/stderr_message.bin
This is a binary file and will not be displayed.
test/test_cases/stdin_empty.bin
This is a binary file and will not be displayed.
test/test_cases/stdin_form_data.bin
This is a binary file and will not be displayed.
test/test_cases/stdout_empty.bin
This is a binary file and will not be displayed.
test/test_cases/stdout_response.bin
This is a binary file and will not be displayed.
+24
test/test_cases/test_case_sizes.txt
···
test/test_cases/unknown_type.bin
This is a binary file and will not be displayed.
+130
test/test_cases/validate_test_cases.py
···+version, record_type, request_id, content_length, padding_length, reserved = struct.unpack('>BBHHBB', data[:8])
+438
test/test_cases/validation_results.txt
···
+219
test/validate_all_test_cases.ml
···+Printf.printf "\nā All %d test case files validated successfully!\n%!" (List.length test_cases);