FastCGI implementation in OCaml
1This repository exists to implement an OCaml specification for the FastCGI interface. 2 3The spec for the FastCGI protocol is in spec/FastCGI_Specification.html. 4The Go lang implementation of FastCGI is in spec/fcgi.go. 5An OCaml specification exists in spec/OCAML.md. 6 7These are intended to act as a reference implementation for us to figure out what the ideal OCaml interface should look like for FastCGI. 8 9Our target language is OCaml, using the Eio library. The README for Eio is in OCaml-EIO-README.md to give you a reference. 10The parsing and serialisation should be done using Eio's Buf_read and Buf_write modules. 11 12You can run commands with: 13 14- clean: `opam exec -- dune clean` 15- build: `opam exec -- dune build @check` 16- docs: `opam exec -- dune build @doc` 17- build while ignoring warnings: add `--profile=release` to the CLI to activate the profile that ignores warnings 18 19# Tips on fixing bugs 20 21If you see errors like this: 22 23``` 24File "../../.jmap.objs/byte/jmap.odoc": 25Warning: Hidden fields in type 'Jmap.Email.Identity.identity_create' 26``` 27 28Then 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. 29 30## Documentation Comments 31 32When adding OCaml documentation comments, be careful about ambiguous documentation comments. If you see errors like: 33 34``` 35Error (warning 50 [unexpected-docstring]): ambiguous documentation comment 36``` 37 38This usually means there isn't enough whitespace between the documentation comment and the code element it's documenting. Always: 39 401. Add blank lines between consecutive documentation comments 412. Add a blank line before a documentation comment for a module/type/value declaration 423. When documenting record fields or variant constructors, place the comment after the field with at least one space 43 44Example of correct documentation spacing: 45 46```ocaml 47(** Module documentation. *) 48 49(** Value documentation. *) 50val some_value : int 51 52(** Type documentation. *) 53type t = 54 | First (** First constructor *) 55 | Second (** Second constructor *) 56 57(** Record documentation. *) 58type record = { 59 field1 : int; (** Field1 documentation *) 60 field2 : string (** Field2 documentation *) 61} 62``` 63 64If 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. 65 66When 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. 67 68# Module Structure Guidelines 69 70IMPORTANT: 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. 71 721. Top-level files should define their main types directly (e.g., `jmap_identity.mli` should define identity-related types at the top level). 73 742. Related operations or specialized subtypes should be defined in nested modules within the file: 75 ```ocaml 76 module Create : sig 77 type t (* NOT 'type create' or any other name *) 78 (* Functions operating on creation requests *) 79 80 module Response : sig 81 type t 82 (* Functions for creation responses *) 83 end 84 end 85 ``` 86 873. Consistently use `type t` for the main type in each module and submodule. 88 894. Functions operating on a type should be placed in the same module as the type. 90 915. 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. 92 93This structured approach promotes encapsulation, consistent type naming, and clearer organization of related functionality. 94 95# Software engineering 96 97We will go through a multi step process to build this library. 98 991) 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. 100 1012) 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. 102 1033) 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. 104