···11+(** FastCGI protocol implementation for OCaml using Eio.
22+33+ This library provides a type-safe, high-performance implementation of the
44+ FastCGI protocol using OCaml's Eio effects-based IO library. It supports
55+ all three FastCGI roles: Responder, Authorizer, and Filter.
66+77+ FastCGI is an open extension to CGI that provides high performance for all
88+ Internet applications without the penalties of Web server APIs. Unlike
99+ traditional CGI programs that are started for each request, FastCGI
1010+ applications are long-lived processes that can handle multiple requests
1111+ over persistent connections.
1212+1313+ The library follows Eio conventions for structured concurrency,
1414+ capability-based security, and resource management. All network I/O is
1515+ performed using Eio's effects system, enabling high-performance concurrent
1616+ request processing.
1717+1818+ {2 Key Features}
1919+2020+ - {b Type Safety}: Leverages OCaml's type system to prevent protocol errors
2121+ - {b High Performance}: Connection multiplexing and keep-alive for efficiency
2222+ - {b Structured Concurrency}: Automatic resource cleanup using Eio switches
2323+ - {b All FastCGI Roles}: Complete support for Responder, Authorizer, and Filter
2424+ - {b Standards Compliant}: Full implementation of FastCGI Protocol 1.0
2525+2626+ {2 Usage Example}
2727+2828+ {[
2929+ let hello_handler request response =
3030+ let http_req = Responder.request_of_fastcgi request in
3131+ let http_resp = Responder.response_of_fastcgi response in
3232+3333+ http_resp.write_status 200;
3434+ http_resp.write_header "Content-Type" "text/html";
3535+ http_resp.write_body "<h1>Hello, FastCGI!</h1>";
3636+ http_resp.finish ();
3737+3838+ { app_status = 0; protocol_status = Request_complete }
3939+4040+ let () = Eio_main.run @@ fun env ->
4141+ let net = Eio.Stdenv.net env in
4242+ Switch.run @@ fun sw ->
4343+ Server.run_default ~sw ~net
4444+ ~handler:(Handler.Responder hello_handler)
4545+ ~listen_address:(`Tcp (Eio.Net.Sockaddr.stream, 9000))
4646+ ]}
4747+4848+ {2 References}
4949+5050+ - {{:https://github.com/ocaml-multicore/eio} Eio Documentation} *)
5151+5252+(** {1 Core Types} *)
5353+5454+(** Re-export core types from Fastcgi_types.
5555+5656+ This includes all the fundamental FastCGI protocol types such as
5757+ [record_type], [role], [request], [response], and protocol constants.
5858+ This includes all the fundamental FastCGI protocol types. *)
5959+include module type of Fastcgi_types
6060+6161+(** {1 Application Interface} *)
6262+6363+(** Application handler signatures.
6464+6565+ This module defines the core handler types that applications implement
6666+ to process FastCGI requests. Each handler type corresponds to one of
6767+ the three FastCGI roles: Responder, Authorizer, and Filter. *)
6868+module Handler : sig
6969+ (** Responder handler: process HTTP request and generate response.
7070+7171+ This is the most common handler type, equivalent to traditional CGI.
7272+ A Responder FastCGI application has the same purpose as a CGI/1.1 program:
7373+ it receives all the information associated with an HTTP request and generates
7474+ an HTTP response.
7575+7676+ @param request Complete FastCGI request with parameters and input streams
7777+ @param response Output streams for writing response data
7878+ @return Response result with application and protocol status *)
7979+ type 'a responder = 'a request -> 'a response -> response_result
8080+8181+ (** Authorizer handler: make authorization decision.
8282+8383+ An Authorizer FastCGI application receives all the information associated
8484+ with an HTTP request and generates an authorized/unauthorized decision.
8585+ In case of an authorized decision, the Authorizer can also associate
8686+ name-value pairs with the HTTP request.
8787+8888+ @param request FastCGI request with authentication context
8989+ @param response Output streams for authorization response
9090+ @return Response result indicating authorization decision *)
9191+ type 'a authorizer = 'a request -> 'a response -> response_result
9292+9393+ (** Filter handler: process data stream with filtering.
9494+9595+ A Filter FastCGI application receives all the information associated
9696+ with an HTTP request, plus an extra stream of data from a file stored
9797+ on the Web server, and generates a 'filtered' version of the data stream
9898+ as an HTTP response.
9999+100100+ @param request FastCGI request including both HTTP context and file data
101101+ @param response Output streams for filtered response
102102+ @return Response result with filtered content status *)
103103+ type 'a filter = 'a request -> 'a response -> response_result
104104+105105+ (** Generic handler that can handle any role.
106106+107107+ This variant type allows applications to support multiple roles or
108108+ to be configured at runtime for different roles. The web server
109109+ specifies the desired role in each Begin_request record. *)
110110+ type 'a handler =
111111+ | Responder of 'a responder (** Handle HTTP requests and responses *)
112112+ | Authorizer of 'a authorizer (** Handle authorization decisions *)
113113+ | Filter of 'a filter (** Handle data filtering *)
114114+end
115115+116116+(** Application configuration.
117117+118118+ This type encapsulates all the settings needed to configure a FastCGI
119119+ application's behavior. It includes both resource limits and the
120120+ application logic (handler function).
121121+122122+ The configuration values affect how the application responds to
123123+ FCGI_GET_VALUES management queries from the web server. *)
124124+type 'a app_config = {
125125+ max_connections : int; (** Maximum concurrent transport connections
126126+ this application will accept. Corresponds to
127127+ FCGI_MAX_CONNS management variable. *)
128128+ max_requests : int; (** Maximum concurrent requests this application
129129+ will accept across all connections. Corresponds
130130+ to FCGI_MAX_REQS management variable. *)
131131+ multiplex_connections : bool; (** Whether this application can multiplex
132132+ connections (handle concurrent requests over
133133+ each connection). Corresponds to FCGI_MPXS_CONNS
134134+ management variable. *)
135135+ handler : 'a Handler.handler; (** Application request handler that implements
136136+ the core application logic. *)
137137+}
138138+139139+(** {1 Connection Management} *)
140140+141141+(** Connection manager for handling FastCGI protocol.
142142+143143+ This module provides low-level connection management for FastCGI applications.
144144+ It handles the binary protocol details, record parsing/serialization, and
145145+ request multiplexing over individual transport connections.
146146+147147+ After a FastCGI process accepts a connection on its listening socket, the
148148+ process executes a simple protocol to receive and send data. The protocol
149149+ serves two purposes: First, it multiplexes a single transport connection
150150+ between several independent FastCGI requests. Second, within each request
151151+ the protocol provides several independent data streams in each direction. *)
152152+module Connection : sig
153153+ (** Opaque connection type.
154154+155155+ Represents a single transport connection from a web server. The connection
156156+ handles protocol parsing, request demultiplexing, and stream management.
157157+ Each connection can handle multiple concurrent requests if the application
158158+ supports multiplexing. *)
159159+ type 'a t
160160+161161+ (** Connection statistics.
162162+163163+ Provides runtime metrics about connection usage for monitoring and
164164+ debugging purposes. These statistics can help tune application
165165+ performance and detect potential issues. *)
166166+ type stats = {
167167+ active_requests : int; (** Number of requests currently being processed
168168+ on this connection. *)
169169+ total_requests : int; (** Total number of requests processed since
170170+ connection establishment. *)
171171+ bytes_sent : int; (** Total bytes sent to the web server (responses). *)
172172+ bytes_received : int; (** Total bytes received from the web server (requests). *)
173173+ }
174174+175175+ (** Create a connection from a network flow.
176176+177177+ Initializes a new FastCGI connection over an established transport.
178178+ The connection will parse incoming records and manage request state
179179+ according to the FastCGI protocol.
180180+181181+ The connection handles a simple protocol to receive and send data,
182182+ including record headers, content data, and proper multiplexing.
183183+184184+ @param sw Switch for managing connection lifetime and automatic cleanup
185185+ @param flow Two-way network flow for bidirectional communication
186186+ @return New connection ready to process FastCGI requests
187187+ @raise Invalid_argument if the flow is already closed *)
188188+ val create : sw:Eio.Switch.t -> 'a Eio.Flow.two_way -> 'a t
189189+190190+ (** Accept and process a single request on the connection.
191191+192192+ Waits for the next FastCGI request to arrive on this connection,
193193+ then processes it using the provided handler. This function handles
194194+ all protocol details including record parsing, stream management,
195195+ and response generation.
196196+197197+ The function is concurrent-safe and can be called multiple times
198198+ if the application supports request multiplexing.
199199+200200+ @param conn Connection to process request on
201201+ @param handler Application handler for the request
202202+ @return Promise that resolves to the response result when processing completes
203203+ @raise Fastcgi.Error.Fastcgi_error on protocol violations *)
204204+ val process_request : 'a t -> 'a Handler.handler -> response_result Eio.Promise.t
205205+206206+ (** Get connection statistics.
207207+208208+ Returns current runtime statistics for this connection. This information
209209+ can be used for monitoring, load balancing decisions, and performance
210210+ tuning.
211211+212212+ @param conn Connection to query
213213+ @return Current statistics snapshot *)
214214+ val stats : 'a t -> stats
215215+216216+ (** Close the connection gracefully.
217217+218218+ Closes the transport connection after completing any active requests.
219219+ The Web server controls the lifetime of transport connections and can
220220+ close a connection when no requests are active.
221221+222222+ @param conn Connection to close *)
223223+ val close : 'a t -> unit
224224+end
225225+226226+(** FastCGI server for accepting and managing connections.
227227+228228+ This module provides a high-level server that listens for incoming
229229+ connections and manages them according to FastCGI protocol requirements.
230230+ It handles connection acceptance, lifecycle management, and graceful
231231+ shutdown.
232232+233233+ The server supports both Unix domain sockets and TCP sockets, as
234234+ commonly used by web servers like nginx, Apache, and lighttpd. *)
235235+module Server : sig
236236+ (** Server configuration.
237237+238238+ Complete configuration for a FastCGI server, including application
239239+ settings, network binding, and resource limits. *)
240240+ type 'a config = {
241241+ app : 'a app_config; (** Application configuration including handlers
242242+ and capability limits. *)
243243+ listen_address : [
244244+ | `Unix of string (** Unix domain socket path. Common for local
245245+ communication with web servers. *)
246246+ | `Tcp of Eio.Net.Sockaddr.stream * int (** TCP socket address and port.
247247+ Used for remote FastCGI servers. *)
248248+ ];
249249+ backlog : int; (** Listen socket backlog size. Controls how
250250+ many pending connections can be queued. *)
251251+ max_connections : int; (** Maximum concurrent connections to accept.
252252+ Should align with app.max_connections. *)
253253+ }
254254+255255+ (** Run a FastCGI server.
256256+257257+ Starts a FastCGI server with the specified configuration. The server
258258+ will listen for connections, accept them within the configured limits,
259259+ and process requests using the application handler.
260260+261261+ The server implements the standard FastCGI application lifecycle:
262262+ a FastCGI application calls accept() on the socket referred to by file
263263+ descriptor FCGI_LISTENSOCK_FILENO to accept a new transport connection.
264264+265265+ This function blocks until the switch is cancelled or an error occurs.
266266+267267+ @param sw Switch for managing server lifetime and automatic cleanup
268268+ @param net Network capability for creating listening sockets
269269+ @param config Complete server configuration
270270+ @raise Sys_error if unable to bind to the specified address *)
271271+ val run :
272272+ sw:Eio.Switch.t ->
273273+ net:'a Eio.Net.t ->
274274+ 'a config ->
275275+ unit
276276+277277+ (** Run server with default configuration.
278278+279279+ Convenience function to start a FastCGI server with sensible defaults.
280280+ Useful for simple applications that don't need custom configuration.
281281+282282+ Default settings:
283283+ - max_connections: 10
284284+ - max_requests: 50
285285+ - multiplex_connections: true
286286+ - backlog: 5
287287+288288+ @param sw Switch for managing server lifetime
289289+ @param net Network capability for creating sockets
290290+ @param handler Application handler function
291291+ @param listen_address Address to listen on (Unix socket or TCP)
292292+ @raise Sys_error if unable to bind to the specified address *)
293293+ val run_default :
294294+ sw:Eio.Switch.t ->
295295+ net:'a Eio.Net.t ->
296296+ handler:'a Handler.handler ->
297297+ listen_address:[`Unix of string | `Tcp of Eio.Net.Sockaddr.stream * int] ->
298298+ unit
299299+end
300300+301301+(** {1 Error Handling} *)
302302+303303+(** FastCGI specific errors. *)
304304+module Error : sig
305305+ (** Error types. *)
306306+ type t =
307307+ | Protocol_error of string (** Protocol violation *)
308308+ | Invalid_record of string (** Malformed record *)
309309+ | Unsupported_version of int (** Unsupported protocol version *)
310310+ | Unknown_record_type of int (** Unknown record type *)
311311+ | Request_id_conflict of request_id (** Duplicate request ID *)
312312+ | Connection_closed (** Connection unexpectedly closed *)
313313+ | Application_error of string (** Application-specific error *)
314314+315315+ (** FastCGI exception. *)
316316+ exception Fastcgi_error of t
317317+318318+ (** Convert error to string description. *)
319319+ val to_string : t -> string
320320+321321+ (** Raise a FastCGI error. *)
322322+ val raise : t -> 'a
323323+end
324324+325325+(** {1 Resource Management} *)
326326+327327+(** Resource management utilities. *)
328328+module Resource : sig
329329+ (** Request context with automatic cleanup. *)
330330+ type 'a request_context = {
331331+ request : 'a request;
332332+ response : 'a response;
333333+ switch : Eio.Switch.t; (** Switch for request-scoped resources *)
334334+ }
335335+336336+ (** Create a request context with automatic resource management.
337337+338338+ @param sw Parent switch
339339+ @param request FastCGI request
340340+ @param f Function to execute with request context
341341+ @return Result of function execution *)
342342+ val with_request_context :
343343+ sw:Eio.Switch.t ->
344344+ 'a request ->
345345+ ('a request_context -> 'b) ->
346346+ 'b
347347+348348+ (** Buffer management for efficient I/O. *)
349349+ module Buffer : sig
350350+ (** Buffer type. *)
351351+ type t
352352+353353+ (** Create a buffer with specified size. *)
354354+ val create : size:int -> t
355355+356356+ (** Read data into buffer from source.
357357+358358+ @param buffer Buffer to read into
359359+ @param source Source to read from
360360+ @return Number of bytes read *)
361361+ val read_into : t -> 'a Eio.Flow.source -> int
362362+363363+ (** Write data from buffer to sink.
364364+365365+ @param buffer Buffer to write from
366366+ @param sink Sink to write to
367367+ @param length Number of bytes to write *)
368368+ val write_from : t -> 'a Eio.Flow.sink -> int -> unit
369369+370370+ (** Clear buffer contents. *)
371371+ val clear : t -> unit
372372+ end
373373+end
+229
lib/fastcgi_authorizer.mli
···11+(** Authorizer role implementation for FastCGI.
22+33+ The Authorizer role performs access control decisions for web requests.
44+ An Authorizer FastCGI application receives all the information associated
55+ with an HTTP request and generates an authorized/unauthorized decision.
66+77+ In case of an authorized decision, the Authorizer can associate name-value
88+ pairs with the HTTP request for use by subsequent processing stages. When
99+ giving an unauthorized decision, the Authorizer sends a complete response
1010+ to the HTTP client with appropriate error information.
1111+1212+ This role is commonly used for:
1313+ - Authentication and authorization checks
1414+ - Access control based on IP addresses, user roles, or request attributes
1515+ - Rate limiting and quota enforcement
1616+ - Custom security policies
1717+1818+ The web server may proceed with additional access checks after a successful
1919+ authorization, including requests to other Authorizers, depending on its
2020+ configuration. *)
2121+2222+(** {1 Authorization Types} *)
2323+2424+(** Authorization result.
2525+2626+ Represents the outcome of an authorization decision. The Authorizer can
2727+ either grant access (possibly with additional variables) or deny access
2828+ with a complete error response. *)
2929+type auth_result =
3030+ | Authorized of (string * string) list (** Request is authorized. The list contains
3131+ variable bindings that will be added to
3232+ the request environment for subsequent
3333+ processing stages. *)
3434+ | Unauthorized of {
3535+ status : int; (** HTTP status code for the error response
3636+ (typically 401, 403, or 429). *)
3737+ headers : (string * string) list; (** HTTP headers for the error response.
3838+ May include WWW-Authenticate, etc. *)
3939+ body : string; (** Error response body content sent to the client. *)
4040+ } (** Request is denied. The web server will send this error
4141+ response directly to the client without further processing. *)
4242+4343+(** Authorization request information.
4444+4545+ Contains the relevant information from an HTTP request needed to make
4646+ authorization decisions. This is extracted from the CGI environment
4747+ variables provided by the web server. *)
4848+type auth_request = {
4949+ method_ : string; (** HTTP method (GET, POST, etc.). *)
5050+ uri : string; (** Request URI being accessed. *)
5151+ remote_addr : string option; (** Client IP address, if available.
5252+ Useful for IP-based access control. *)
5353+ remote_user : string option; (** Authenticated username, if any.
5454+ Set by prior authentication stages. *)
5555+ auth_type : string option; (** Authentication method used (Basic, Bearer, etc.).
5656+ Indicates how the user was authenticated. *)
5757+ headers : (string * string) list; (** HTTP headers from the request.
5858+ May contain authorization headers, user agents, etc. *)
5959+}
6060+6161+(** {1 Conversion Functions} *)
6262+6363+(** Convert FastCGI request to authorization request.
6464+6565+ Extracts authorization-relevant information from FastCGI
6666+ parameters and creates an auth request object.
6767+6868+ @param request FastCGI request
6969+ @return Authorization request *)
7070+val request_of_fastcgi : 'a Fastcgi_types.request -> auth_request
7171+7272+(** Convert authorization result to FastCGI response.
7373+7474+ Writes the authorization decision to the FastCGI response
7575+ streams in the correct format.
7676+7777+ @param result Authorization decision
7878+ @param response FastCGI response
7979+ @return Response result *)
8080+val response_of_result : auth_result -> 'a Fastcgi_types.response -> Fastcgi_types.response_result
8181+8282+(** {1 Handler Utilities} *)
8383+8484+(** Authorizer handler type. *)
8585+type 'a authorizer_handler = 'a Fastcgi_types.request -> 'a Fastcgi_types.response -> Fastcgi_types.response_result
8686+8787+(** Convenience handler wrapper for authorization handlers.
8888+8989+ Converts an authorization handler function into a FastCGI handler.
9090+ This allows writing handlers that work with auth request/result
9191+ types instead of raw FastCGI types.
9292+9393+ @param handler Authorization handler function
9494+ @return FastCGI authorizer handler *)
9595+val auth_handler :
9696+ (auth_request -> auth_result) ->
9797+ 'a authorizer_handler
9898+9999+(** {1 Common Authorization Patterns} *)
100100+101101+(** Create a simple allow/deny authorizer.
102102+103103+ @param predicate Function that returns true for authorized requests
104104+ @return Authorization result *)
105105+val simple_authorizer : (auth_request -> bool) -> (auth_request -> auth_result)
106106+107107+(** IP-based authorization.
108108+109109+ @param allowed_ips List of allowed IP addresses/ranges
110110+ @param request Authorization request
111111+ @return Authorization result *)
112112+val ip_authorizer : string list -> auth_request -> auth_result
113113+114114+(** User-based authorization.
115115+116116+ @param allowed_users List of allowed usernames
117117+ @param request Authorization request
118118+ @return Authorization result *)
119119+val user_authorizer : string list -> auth_request -> auth_result
120120+121121+(** Role-based authorization.
122122+123123+ @param get_user_roles Function to get roles for a user
124124+ @param required_roles Roles required for access
125125+ @param request Authorization request
126126+ @return Authorization result *)
127127+val role_authorizer :
128128+ get_user_roles:(string -> string list) ->
129129+ required_roles:string list ->
130130+ auth_request ->
131131+ auth_result
132132+133133+(** Time-based authorization.
134134+135135+ @param allowed_hours List of allowed hours (0-23)
136136+ @param request Authorization request
137137+ @return Authorization result *)
138138+val time_authorizer : int list -> auth_request -> auth_result
139139+140140+(** {1 Authentication Integration} *)
141141+142142+(** Basic authentication handler.
143143+144144+ @param realm Authentication realm
145145+ @param verify_credentials Function to verify username/password
146146+ @param request Authorization request
147147+ @return Authorization result *)
148148+val basic_auth :
149149+ realm:string ->
150150+ verify_credentials:(string -> string -> bool) ->
151151+ auth_request ->
152152+ auth_result
153153+154154+(** Bearer token authentication.
155155+156156+ @param verify_token Function to verify and decode token
157157+ @param request Authorization request
158158+ @return Authorization result *)
159159+val bearer_auth :
160160+ verify_token:(string -> (string * (string * string) list) option) ->
161161+ auth_request ->
162162+ auth_result
163163+164164+(** API key authentication.
165165+166166+ @param header_name Header containing API key
167167+ @param verify_key Function to verify API key
168168+ @param request Authorization request
169169+ @return Authorization result *)
170170+val api_key_auth :
171171+ header_name:string ->
172172+ verify_key:(string -> (string * (string * string) list) option) ->
173173+ auth_request ->
174174+ auth_result
175175+176176+(** {1 Response Helpers} *)
177177+178178+(** Create a standard 401 Unauthorized response.
179179+180180+ @param realm Authentication realm
181181+ @param message Error message
182182+ @return Unauthorized result *)
183183+val unauthorized_response :
184184+ realm:string ->
185185+ message:string ->
186186+ auth_result
187187+188188+(** Create a standard 403 Forbidden response.
189189+190190+ @param message Error message
191191+ @return Unauthorized result *)
192192+val forbidden_response :
193193+ message:string ->
194194+ auth_result
195195+196196+(** Create a custom error response.
197197+198198+ @param status HTTP status code
199199+ @param headers Additional headers
200200+ @param body Response body
201201+ @return Unauthorized result *)
202202+val error_response :
203203+ status:int ->
204204+ headers:(string * string) list ->
205205+ body:string ->
206206+ auth_result
207207+208208+(** {1 Variable Binding} *)
209209+210210+(** Create authorized response with variables.
211211+212212+ Variables are passed to subsequent FastCGI applications
213213+ as environment variables with "Variable-" prefix.
214214+215215+ @param variables Name-value pairs to bind
216216+ @return Authorized result *)
217217+val authorized_with_variables : (string * string) list -> auth_result
218218+219219+(** Add authentication information as variables.
220220+221221+ @param user Authenticated username
222222+ @param auth_type Authentication method
223223+ @param additional Additional variables
224224+ @return Variable bindings *)
225225+val auth_variables :
226226+ user:string ->
227227+ auth_type:string ->
228228+ additional:(string * string) list ->
229229+ (string * string) list
+329
lib/fastcgi_filter.mli
···11+(** Filter role implementation for FastCGI.
22+33+ The Filter role processes data streams with filtering capabilities.
44+ A Filter FastCGI application receives all the information associated with
55+ an HTTP request, plus an extra stream of data from a file stored on the
66+ web server, and generates a "filtered" version of the data stream as an
77+ HTTP response.
88+99+ This role is useful for:
1010+ - Dynamic content transformation (e.g., server-side includes, templating)
1111+ - Format conversion (e.g., Markdown to HTML, image resizing)
1212+ - Content compression and optimization
1313+ - Real-time content modification based on request context
1414+1515+ A Filter is similar in functionality to a Responder that takes a data file
1616+ as a parameter. The key difference is that with a Filter, both the data file
1717+ and the Filter itself can be access controlled using the web server's access
1818+ control mechanisms, while a Responder that takes the name of a data file as
1919+ a parameter must perform its own access control checks on the data file.
2020+2121+ The web server presents the Filter with environment variables first, then
2222+ standard input (normally form POST data), and finally the data file input
2323+ that needs to be processed. *)
2424+2525+(** {1 Filter Types} *)
2626+2727+(** Filter request with data stream.
2828+2929+ Represents a complete Filter request including both the HTTP request
3030+ context and the data stream that needs to be processed. *)
3131+type 'a filter_request = {
3232+ request : 'a Fastcgi_types.request; (** Base FastCGI request containing HTTP context,
3333+ parameters, and form data. *)
3434+ data_stream : 'a Eio.Flow.source; (** File data stream to be filtered.
3535+ This is the content that needs processing. *)
3636+ data_last_modified : float option; (** File modification time as seconds since epoch.
3737+ Useful for caching and conditional requests. *)
3838+ data_length : int option; (** Expected length of the data stream in bytes.
3939+ May be None if length is unknown. *)
4040+}
4141+4242+(** Filter metadata about the data being processed. *)
4343+type filter_metadata = {
4444+ filename : string option; (** Original filename *)
4545+ mime_type : string option; (** MIME type of data *)
4646+ last_modified : float option; (** Last modification time *)
4747+ size : int option; (** Data size in bytes *)
4848+ etag : string option; (** Entity tag for caching *)
4949+}
5050+5151+(** Filter context with additional processing information. *)
5252+type 'a filter_context = {
5353+ filter_request : 'a filter_request; (** Request and data *)
5454+ metadata : filter_metadata; (** File metadata *)
5555+ cache_control : cache_policy; (** Caching policy *)
5656+}
5757+5858+(** Cache policy for filtered content. *)
5959+and cache_policy =
6060+ | No_cache (** No caching *)
6161+ | Cache_for of int (** Cache for N seconds *)
6262+ | Cache_until of float (** Cache until timestamp *)
6363+ | Conditional_cache of (filter_metadata -> bool) (** Conditional caching *)
6464+6565+(** {1 Conversion Functions} *)
6666+6767+(** Convert FastCGI request to filter request.
6868+6969+ Extracts filter-specific information from FastCGI streams
7070+ and creates a filter request object.
7171+7272+ @param request FastCGI request
7373+ @return Filter request with data stream *)
7474+val request_of_fastcgi : 'a Fastcgi_types.request -> 'a filter_request
7575+7676+(** Create filter context with metadata.
7777+7878+ @param filter_request Filter request
7979+ @param metadata File metadata
8080+ @param cache_control Caching policy
8181+ @return Filter context *)
8282+val context_of_request :
8383+ 'a filter_request ->
8484+ metadata:filter_metadata ->
8585+ cache_control:cache_policy ->
8686+ 'a filter_context
8787+8888+(** {1 Handler Utilities} *)
8989+9090+(** Filter handler type. *)
9191+type 'a filter_handler = 'a Fastcgi_types.request -> 'a Fastcgi_types.response -> Fastcgi_types.response_result
9292+9393+(** Convenience handler wrapper for filter handlers.
9494+9595+ Converts a filter handler function into a FastCGI handler.
9696+ This allows writing handlers that work with filter request/response
9797+ types instead of raw FastCGI types.
9898+9999+ @param handler Filter handler function
100100+ @return FastCGI filter handler *)
101101+102102+val filter_handler :
103103+ ('a filter_request -> 'a Fastcgi_types.response -> unit) ->
104104+ 'a filter_handler
105105+106106+(** Context-aware filter handler.
107107+108108+ Similar to filter_handler but provides additional context
109109+ including metadata and caching information.
110110+111111+ @param handler Context-aware filter handler
112112+ @return FastCGI filter handler *)
113113+val context_filter_handler :
114114+ ('a filter_context -> 'a Fastcgi_types.response -> unit) ->
115115+ 'a filter_handler
116116+117117+(** {1 Common Filter Operations} *)
118118+119119+(** Text processing filters. *)
120120+module Text : sig
121121+ (** Convert text encoding.
122122+123123+ @param from_encoding Source encoding
124124+ @param to_encoding Target encoding
125125+ @param input Text stream
126126+ @param output Filtered stream *)
127127+ val convert_encoding :
128128+ from_encoding:string ->
129129+ to_encoding:string ->
130130+ input:'a Eio.Flow.source ->
131131+ output:'a Eio.Flow.sink ->
132132+ unit
133133+134134+ (** Find and replace text patterns.
135135+136136+ @param pattern Regular expression pattern
137137+ @param replacement Replacement text
138138+ @param input Text stream
139139+ @param output Filtered stream *)
140140+ val find_replace :
141141+ pattern:string ->
142142+ replacement:string ->
143143+ input:'a Eio.Flow.source ->
144144+ output:'a Eio.Flow.sink ->
145145+ unit
146146+147147+ (** Template substitution.
148148+149149+ @param variables Variable substitutions
150150+ @param input Template stream
151151+ @param output Processed stream *)
152152+ val template_substitute :
153153+ variables:(string * string) list ->
154154+ input:'a Eio.Flow.source ->
155155+ output:'a Eio.Flow.sink ->
156156+ unit
157157+158158+ (** Markdown to HTML conversion.
159159+160160+ @param options Markdown processing options
161161+ @param input Markdown stream
162162+ @param output HTML stream *)
163163+ val markdown_to_html :
164164+ options:string list ->
165165+ input:'a Eio.Flow.source ->
166166+ output:'a Eio.Flow.sink ->
167167+ unit
168168+end
169169+170170+(** Image processing filters. *)
171171+module Image : sig
172172+ (** Image resize operation.
173173+174174+ @param width Target width
175175+ @param height Target height
176176+ @param input Image stream
177177+ @param output Resized stream *)
178178+ val resize :
179179+ width:int ->
180180+ height:int ->
181181+ input:'a Eio.Flow.source ->
182182+ output:'a Eio.Flow.sink ->
183183+ unit
184184+185185+ (** Image format conversion.
186186+187187+ @param format Target format (jpeg, png, etc.)
188188+ @param quality Quality setting (for lossy formats)
189189+ @param input Image stream
190190+ @param output Converted stream *)
191191+ val convert_format :
192192+ format:string ->
193193+ quality:int option ->
194194+ input:'a Eio.Flow.source ->
195195+ output:'a Eio.Flow.sink ->
196196+ unit
197197+198198+ (** Image compression.
199199+200200+ @param level Compression level
201201+ @param input Image stream
202202+ @param output Compressed stream *)
203203+ val compress :
204204+ level:int ->
205205+ input:'a Eio.Flow.source ->
206206+ output:'a Eio.Flow.sink ->
207207+ unit
208208+end
209209+210210+(** Data compression filters. *)
211211+module Compression : sig
212212+ (** Gzip compression.
213213+214214+ @param level Compression level (1-9)
215215+ @param input Data stream
216216+ @param output Compressed stream *)
217217+ val gzip :
218218+ level:int ->
219219+ input:'a Eio.Flow.source ->
220220+ output:'a Eio.Flow.sink ->
221221+ unit
222222+223223+ (** Brotli compression.
224224+225225+ @param level Compression level
226226+ @param input Data stream
227227+ @param output Compressed stream *)
228228+ val brotli :
229229+ level:int ->
230230+ input:'a Eio.Flow.source ->
231231+ output:'a Eio.Flow.sink ->
232232+ unit
233233+234234+ (** Auto-detect and compress.
235235+236236+ @param preferred_formats Preferred compression formats
237237+ @param accept_encoding Client Accept-Encoding header
238238+ @param input Data stream
239239+ @param output Compressed stream *)
240240+ val auto_compress :
241241+ preferred_formats:string list ->
242242+ accept_encoding:string option ->
243243+ input:'a Eio.Flow.source ->
244244+ output:'a Eio.Flow.sink ->
245245+ string option (** Returns content-encoding used *)
246246+end
247247+248248+(** {1 Caching and Optimization} *)
249249+250250+(** Check if content should be served from cache.
251251+252252+ @param metadata File metadata
253253+ @param if_modified_since Client If-Modified-Since header
254254+ @param if_none_match Client If-None-Match header
255255+ @return True if content is not modified *)
256256+val check_not_modified :
257257+ metadata:filter_metadata ->
258258+ if_modified_since:string option ->
259259+ if_none_match:string option ->
260260+ bool
261261+262262+(** Generate appropriate cache headers.
263263+264264+ @param metadata File metadata
265265+ @param cache_policy Caching policy
266266+ @return List of cache-related headers *)
267267+val generate_cache_headers :
268268+ metadata:filter_metadata ->
269269+ cache_policy:cache_policy ->
270270+ (string * string) list
271271+272272+(** {1 Streaming Operations} *)
273273+274274+(** Stream processor for chunk-by-chunk filtering. *)
275275+type 'a stream_processor = {
276276+ process_chunk : bytes -> bytes option; (** Process a data chunk *)
277277+ finalize : unit -> bytes option; (** Finalize and get remaining data *)
278278+ reset : unit -> unit; (** Reset processor state *)
279279+}
280280+281281+(** Create a streaming filter.
282282+283283+ @param processor Stream processor
284284+ @param input Source stream
285285+ @param output Target stream *)
286286+val streaming_filter :
287287+ processor:'a stream_processor ->
288288+ input:'a Eio.Flow.source ->
289289+ output:'a Eio.Flow.sink ->
290290+ unit
291291+292292+(** Chain multiple filters together.
293293+294294+ @param filters List of filter functions
295295+ @param input Source stream
296296+ @param output Target stream *)
297297+val chain_filters :
298298+ filters:(('a Eio.Flow.source -> 'a Eio.Flow.sink -> unit) list) ->
299299+ input:'a Eio.Flow.source ->
300300+ output:'a Eio.Flow.sink ->
301301+ unit
302302+303303+(** {1 Error Handling} *)
304304+305305+(** Filter-specific errors. *)
306306+type filter_error =
307307+ | Data_corruption of string (** Data corruption detected *)
308308+ | Unsupported_format of string (** Unsupported file format *)
309309+ | Processing_failed of string (** Filter processing failed *)
310310+ | Resource_exhausted of string (** Out of memory/disk space *)
311311+312312+(** Filter exception. *)
313313+exception Filter_error of filter_error
314314+315315+(** Convert filter error to string. *)
316316+val filter_error_to_string : filter_error -> string
317317+318318+(** Safe filter wrapper that handles errors gracefully.
319319+320320+ @param fallback Fallback function if filter fails
321321+ @param filter Primary filter function
322322+ @param input Source stream
323323+ @param output Target stream *)
324324+val safe_filter :
325325+ fallback:('a Eio.Flow.source -> 'a Eio.Flow.sink -> unit) ->
326326+ filter:('a Eio.Flow.source -> 'a Eio.Flow.sink -> unit) ->
327327+ input:'a Eio.Flow.source ->
328328+ output:'a Eio.Flow.sink ->
329329+ unit
+414
lib/fastcgi_protocol.mli
···11+(** FastCGI wire protocol parsing and serialization.
22+33+ This module handles the low-level FastCGI protocol details including
44+ record parsing, name-value pair encoding, and binary data serialization
55+ using Eio's Buf_read and Buf_write modules.
66+77+ The FastCGI protocol uses a binary record format where all data is
88+ transmitted as 8-byte fixed headers followed by variable-length content
99+ and optional padding. Multi-byte integers use network byte order for
1010+ platform independence.
1111+1212+ The protocol supports several key features:
1313+ - Request multiplexing over single connections
1414+ - Variable-length encoding for efficient name-value pairs
1515+ - Stream-based data transmission with proper termination
1616+ - Alignment padding for optimal performance
1717+1818+ This module provides the low-level primitives for encoding and decoding
1919+ these protocol elements, allowing higher-level modules to focus on
2020+ application logic rather than binary protocol details. *)
2121+2222+(** Protocol parsing error.
2323+2424+ Raised when invalid or malformed protocol data is encountered during
2525+ parsing operations. This includes version mismatches, invalid record
2626+ structures, malformed length encodings, and other protocol violations. *)
2727+exception Protocol_error of string
2828+2929+(** {1 Protocol Parsing}
3030+3131+ These functions parse incoming FastCGI records and protocol elements
3232+ from binary data streams. They validate protocol compliance and convert
3333+ binary data into OCaml types for processing. *)
3434+3535+(** Parse a FastCGI record header from a buffer.
3636+3737+ Reads exactly 8 bytes from the buffer to construct a record header.
3838+ The header contains version, record type, request ID, content length,
3939+ and padding length fields using network byte order.
4040+4141+ The function validates that the version is supported (currently only
4242+ version 1) and that the record type is recognized.
4343+4444+ @param buf Input buffer positioned at the start of a record header
4545+ @return Parsed record header with validated fields
4646+ @raise Protocol_error if version is unsupported or data is malformed *)
4747+val parse_record_header : Eio.Buf_read.t -> Fastcgi_types.record_header
4848+4949+(** Parse a complete FastCGI record from a buffer.
5050+5151+ Reads a record header followed by the specified amount of content data
5252+ and padding. This is the primary function for reading FastCGI records
5353+ from network streams.
5454+5555+ The function ensures that exactly the number of content and padding
5656+ bytes specified in the header are read, maintaining proper stream
5757+ alignment for subsequent records.
5858+5959+ @param buf Input buffer positioned at the start of a complete record
6060+ @return Complete parsed record with header, content, and optional padding
6161+ @raise Protocol_error if the record structure is invalid *)
6262+val parse_record : Eio.Buf_read.t -> Fastcgi_types.record
6363+6464+(** Parse begin request body from record content.
6565+6666+ Extracts role and connection flags from the 8-byte Begin_request record
6767+ body. The role indicates whether the application should act as a
6868+ Responder, Authorizer, or Filter. The flags control connection lifetime
6969+ management.
7070+7171+ @param content Record content bytes (must be exactly 8 bytes)
7272+ @return Begin request body with role and flags
7373+ @raise Protocol_error if content length is wrong or role is unknown *)
7474+val parse_begin_request : bytes -> Fastcgi_types.begin_request_body
7575+7676+(** Parse end request body from record content.
7777+7878+ Extracts application status and protocol status from the 8-byte
7979+ End_request record body. The application status is similar to a
8080+ program exit code, while protocol status indicates completion
8181+ or rejection reasons.
8282+8383+ @param content Record content bytes (must be exactly 8 bytes)
8484+ @return End request body with status codes
8585+ @raise Protocol_error if content length is wrong or status is invalid *)
8686+val parse_end_request : bytes -> Fastcgi_types.end_request_body
8787+8888+(** Parse name-value pairs from record content.
8989+9090+ Decodes the compact binary encoding used for parameter transmission.
9191+ Names and values can be up to 127 bytes (1-byte length) or longer
9292+ (4-byte length with high bit set). This encoding allows efficient
9393+ transmission of CGI environment variables and other parameters.
9494+9595+ @param content Record content bytes containing encoded name-value pairs
9696+ @return List of decoded name-value pairs
9797+ @raise Protocol_error if the encoding is malformed *)
9898+val parse_name_value_pairs : bytes -> Fastcgi_types.name_value_pair list
9999+100100+(** {1 Protocol Serialization}
101101+102102+ These functions serialize OCaml types into the binary FastCGI protocol
103103+ format for transmission to web servers. All multi-byte integers are
104104+ written in network byte order for platform independence. *)
105105+106106+(** Write a FastCGI record header to a buffer.
107107+108108+ Serializes a record header into exactly 8 bytes using network byte order.
109109+ The header format is: version (1 byte), type (1 byte), request ID (2 bytes),
110110+ content length (2 bytes), padding length (1 byte), reserved (1 byte).
111111+112112+ @param buf Output buffer to write the header to
113113+ @param header Record header to serialize *)
114114+val write_record_header : Eio.Buf_write.t -> Fastcgi_types.record_header -> unit
115115+116116+(** Write a complete FastCGI record to a buffer.
117117+118118+ Serializes a complete record including header, content data, and padding.
119119+ This is the primary function for sending FastCGI records over network
120120+ connections. The function ensures proper alignment by writing any
121121+ specified padding bytes.
122122+123123+ @param buf Output buffer to write the complete record to
124124+ @param record Complete record with header, content, and optional padding *)
125125+val write_record : Eio.Buf_write.t -> Fastcgi_types.record -> unit
126126+127127+(** Write begin request body to bytes.
128128+129129+ Serializes role and connection flags into the 8-byte Begin_request record
130130+ body format. The first 2 bytes contain the role, the next byte contains
131131+ flags, and the remaining 5 bytes are reserved (set to zero).
132132+133133+ @param body Begin request body with role and flags
134134+ @return 8-byte serialized record body *)
135135+val write_begin_request : Fastcgi_types.begin_request_body -> bytes
136136+137137+(** Write end request body to bytes.
138138+139139+ Serializes application and protocol status into the 8-byte End_request
140140+ record body format. The first 4 bytes contain the application status,
141141+ the next byte contains the protocol status, and the remaining 3 bytes
142142+ are reserved.
143143+144144+ @param body End request body with status codes
145145+ @return 8-byte serialized record body *)
146146+val write_end_request : Fastcgi_types.end_request_body -> bytes
147147+148148+(** Write name-value pairs to bytes.
149149+150150+ Serializes name-value pairs using the compact binary encoding where
151151+ each pair is encoded as: name length, value length, name data, value data.
152152+ Lengths up to 127 bytes use 1-byte encoding; longer lengths use 4-byte
153153+ encoding with the high bit set.
154154+155155+ @param pairs List of name-value pairs to encode
156156+ @return Serialized bytes containing all encoded pairs *)
157157+val write_name_value_pairs : Fastcgi_types.name_value_pair list -> bytes
158158+159159+(** {1 Type Conversions} *)
160160+161161+(** Convert record type to integer. *)
162162+val record_type_to_int : Fastcgi_types.record_type -> int
163163+164164+(** Convert integer to record type.
165165+166166+ @param i Integer value
167167+ @return Record type
168168+ @raise Protocol_error if unknown *)
169169+val record_type_of_int : int -> Fastcgi_types.record_type
170170+171171+(** Convert role to integer. *)
172172+val role_to_int : Fastcgi_types.role -> int
173173+174174+(** Convert integer to role.
175175+176176+ @param i Integer value
177177+ @return Role
178178+ @raise Protocol_error if unknown *)
179179+val role_of_int : int -> Fastcgi_types.role
180180+181181+(** Convert protocol status to integer. *)
182182+val protocol_status_to_int : Fastcgi_types.protocol_status -> int
183183+184184+(** Convert integer to protocol status.
185185+186186+ @param i Integer value
187187+ @return Protocol status
188188+ @raise Protocol_error if unknown *)
189189+val protocol_status_of_int : int -> Fastcgi_types.protocol_status
190190+191191+(** {1 Length Encoding}
192192+193193+ FastCGI uses a variable-length encoding for efficient transmission of
194194+ length values in name-value pairs. This encoding minimizes overhead
195195+ for short strings while supporting arbitrarily long values. *)
196196+197197+(** Encode a length value using FastCGI variable-length encoding.
198198+199199+ Short lengths (0-127) are encoded in a single byte with the high bit
200200+ clear. Longer lengths (128 and above) are encoded in 4 bytes with the
201201+ high bit of the first byte set to 1, and the remaining 31 bits containing
202202+ the actual length value.
203203+204204+ This encoding provides optimal space efficiency for typical use cases
205205+ where most parameter names and values are relatively short.
206206+207207+ @param length Length value to encode (must be non-negative)
208208+ @return 1-byte or 4-byte encoded length
209209+ @raise Invalid_argument if length is negative *)
210210+val encode_length : int -> bytes
211211+212212+(** Decode a length value from FastCGI variable-length encoding.
213213+214214+ Reads either 1 or 4 bytes from the buffer depending on the high bit
215215+ of the first byte. Returns both the decoded length and the number of
216216+ bytes consumed to allow proper buffer advancement.
217217+218218+ @param buf Input buffer positioned at the start of an encoded length
219219+ @return Tuple of (decoded length, bytes consumed)
220220+ @raise Protocol_error if the encoding is invalid or buffer is too short *)
221221+val decode_length : Eio.Buf_read.t -> int * int
222222+223223+(** {1 Record Construction}
224224+225225+ These convenience functions create properly formatted FastCGI records
226226+ with correct headers and content. They handle the binary encoding details
227227+ and ensure protocol compliance. *)
228228+229229+(** Create a begin request record.
230230+231231+ Constructs a Begin_request record to initiate a new FastCGI request.
232232+ This record type is sent by web servers to start request processing
233233+ and specifies the role the application should play.
234234+235235+ The record contains the application role (Responder, Authorizer, or Filter)
236236+ and connection flags that control whether the connection should be kept
237237+ alive after the request completes.
238238+239239+ @param request_id Unique request identifier for multiplexing
240240+ @param role Role the application should play for this request
241241+ @param flags Connection management flags
242242+ @return Complete Begin_request record ready for transmission *)
243243+val make_begin_request :
244244+ request_id:Fastcgi_types.request_id ->
245245+ role:Fastcgi_types.role ->
246246+ flags:Fastcgi_types.connection_flags ->
247247+ Fastcgi_types.record
248248+249249+(** Create an end request record.
250250+251251+ Constructs an End_request record to complete a FastCGI request.
252252+ This record is sent by applications to indicate request completion
253253+ and provide both application-level and protocol-level status information.
254254+255255+ The application status is similar to a program exit code, where 0
256256+ indicates success and non-zero values indicate errors. The protocol
257257+ status indicates whether the request was completed normally or rejected
258258+ for protocol-related reasons.
259259+260260+ @param request_id Request ID that is being completed
261261+ @param app_status Application exit status (0 for success)
262262+ @param protocol_status Protocol completion status
263263+ @return Complete End_request record ready for transmission *)
264264+val make_end_request :
265265+ request_id:Fastcgi_types.request_id ->
266266+ app_status:Fastcgi_types.app_status ->
267267+ protocol_status:Fastcgi_types.protocol_status ->
268268+ Fastcgi_types.record
269269+270270+(** Create a params record.
271271+272272+ @param request_id Request ID
273273+ @param params Parameter name-value pairs
274274+ @return Params record *)
275275+val make_params_record :
276276+ request_id:Fastcgi_types.request_id ->
277277+ params:(string * string) list ->
278278+ Fastcgi_types.record
279279+280280+(** Create a stream record (stdin, stdout, stderr, data).
281281+282282+ @param record_type Stream record type
283283+ @param request_id Request ID
284284+ @param data Stream data
285285+ @return Stream record *)
286286+val make_stream_record :
287287+ record_type:Fastcgi_types.record_type ->
288288+ request_id:Fastcgi_types.request_id ->
289289+ data:bytes ->
290290+ Fastcgi_types.record
291291+292292+(** Create an empty stream record (marks end of stream).
293293+294294+ @param record_type Stream record type
295295+ @param request_id Request ID
296296+ @return Empty stream record *)
297297+val make_empty_stream_record :
298298+ record_type:Fastcgi_types.record_type ->
299299+ request_id:Fastcgi_types.request_id ->
300300+ Fastcgi_types.record
301301+302302+(** Create a get values record.
303303+304304+ @param variables Variable names to query
305305+ @return Get values record *)
306306+val make_get_values_record :
307307+ variables:string list ->
308308+ Fastcgi_types.record
309309+310310+(** Create a get values result record.
311311+312312+ @param values Variable name-value pairs
313313+ @return Get values result record *)
314314+val make_get_values_result_record :
315315+ values:(string * string) list ->
316316+ Fastcgi_types.record
317317+318318+(** Create an unknown type record.
319319+320320+ @param unknown_type Unknown record type value
321321+ @return Unknown type record *)
322322+val make_unknown_type_record :
323323+ unknown_type:int ->
324324+ Fastcgi_types.record
325325+326326+(** Create an abort request record.
327327+328328+ @param request_id Request ID to abort
329329+ @return Abort request record *)
330330+val make_abort_request_record :
331331+ request_id:Fastcgi_types.request_id ->
332332+ Fastcgi_types.record
333333+334334+(** {1 Validation}
335335+336336+ These functions validate protocol elements for compliance with FastCGI
337337+ requirements. They help detect malformed data and ensure protocol
338338+ correctness during parsing and construction. *)
339339+340340+(** Validate a record header.
341341+342342+ Checks that a record header contains valid values for all fields.
343343+ This includes verifying the protocol version, record type bounds,
344344+ content length limits, and padding length constraints.
345345+346346+ @param header Record header to validate
347347+ @return True if the header is valid and protocol-compliant
348348+ @raise Protocol_error if any field contains invalid values *)
349349+val validate_record_header : Fastcgi_types.record_header -> bool
350350+351351+(** Validate a complete record.
352352+353353+ Performs comprehensive validation of a complete record including
354354+ header validation and content/padding length consistency checks.
355355+ Ensures the record can be safely transmitted or processed.
356356+357357+ @param record Complete record to validate
358358+ @return True if the entire record is valid and well-formed
359359+ @raise Protocol_error if any part of the record is invalid *)
360360+val validate_record : Fastcgi_types.record -> bool
361361+362362+(** Check if a record type is a management record.
363363+364364+ Management records use request ID 0 and contain protocol-level information
365365+ such as capability queries (Get_values) and unknown type responses.
366366+ They are not associated with any specific request.
367367+368368+ @param record_type Record type to classify
369369+ @return True if this is a management record type *)
370370+val is_management_record : Fastcgi_types.record_type -> bool
371371+372372+(** Check if a record type is a stream record.
373373+374374+ Stream records (Params, Stdin, Stdout, Stderr, Data) can be sent in
375375+ multiple parts and are terminated with an empty record of the same type.
376376+ This allows streaming of arbitrarily large data without buffering.
377377+378378+ @param record_type Record type to classify
379379+ @return True if this is a stream record type *)
380380+val is_stream_record : Fastcgi_types.record_type -> bool
381381+382382+(** {1 Protocol Constants}
383383+384384+ Essential constants and utility functions for FastCGI protocol
385385+ implementation. These values are defined by the protocol specification. *)
386386+387387+(** Null request ID for management records.
388388+389389+ Management records always use request ID 0 to indicate they are not
390390+ associated with any specific request. Applications must use non-zero
391391+ request IDs for all application records. *)
392392+val null_request_id : Fastcgi_types.request_id
393393+394394+(** Maximum content length for a single record.
395395+396396+ FastCGI records can contain at most 65535 bytes of content data.
397397+ Larger data must be split across multiple records of the same type. *)
398398+val max_content_length : int
399399+400400+(** Maximum padding length for a record.
401401+402402+ Records can have at most 255 bytes of padding for alignment purposes.
403403+ Padding bytes are ignored by the receiver. *)
404404+val max_padding_length : int
405405+406406+(** Calculate optimal padding for 8-byte alignment.
407407+408408+ Computes the number of padding bytes needed to align the total record
409409+ size to an 8-byte boundary. This provides optimal performance on most
410410+ architectures by ensuring proper memory alignment.
411411+412412+ @param content_length Length of the record content data
413413+ @return Number of padding bytes needed (0-7) *)
414414+val calculate_padding : int -> int
+222
lib/fastcgi_responder.mli
···11+(** Responder role implementation for FastCGI.
22+33+ The Responder role is the most common FastCGI role, equivalent to
44+ traditional CGI applications. It handles HTTP requests and generates
55+ HTTP responses.
66+77+ A Responder FastCGI application has the same purpose as a CGI/1.1 program:
88+ it receives all the information associated with an HTTP request and generates
99+ an HTTP response. This includes CGI environment variables, request headers,
1010+ request body data, and produces HTTP response headers and body content.
1111+1212+ The key difference from traditional CGI is that Responder applications are
1313+ long-lived processes that can handle multiple requests efficiently, avoiding
1414+ the overhead of process creation for each request.
1515+1616+ This module provides high-level abstractions for working with HTTP requests
1717+ and responses, automatically handling the conversion between FastCGI protocol
1818+ elements and familiar HTTP concepts. *)
1919+2020+(** {1 HTTP Request/Response Types} *)
2121+2222+(** CGI-style environment variables.
2323+2424+ A list of name-value pairs containing the CGI environment variables
2525+ passed from the web server. These typically include variables like
2626+ REQUEST_METHOD, REQUEST_URI, HTTP_HOST, CONTENT_TYPE, etc. *)
2727+type cgi_env = (string * string) list
2828+2929+(** HTTP request information extracted from FastCGI parameters.
3030+3131+ This type represents an HTTP request in a convenient form for application
3232+ processing. It extracts and parses the most commonly needed information
3333+ from the CGI environment variables provided by the web server. *)
3434+type 'a http_request = {
3535+ method_ : string; (** HTTP method (GET, POST, PUT, DELETE, etc.).
3636+ Extracted from REQUEST_METHOD CGI variable. *)
3737+ uri : string; (** Request URI path component, without query string.
3838+ Extracted from REQUEST_URI or SCRIPT_NAME + PATH_INFO. *)
3939+ query_string : string; (** URL query string parameters (after the '?' in the URL).
4040+ Extracted from QUERY_STRING CGI variable. *)
4141+ content_type : string option; (** MIME type of the request body, if present.
4242+ Extracted from CONTENT_TYPE CGI variable. *)
4343+ content_length : int option; (** Length of the request body in bytes, if known.
4444+ Extracted from CONTENT_LENGTH CGI variable. *)
4545+ headers : (string * string) list; (** HTTP headers sent by the client. Extracted from
4646+ CGI variables with HTTP_ prefix. *)
4747+ body : 'a Eio.Flow.source; (** Request body data stream. For POST requests,
4848+ this contains form data or payload content. *)
4949+}
5050+5151+(** HTTP response builder for constructing responses.
5252+5353+ This type provides a streaming interface for generating HTTP responses.
5454+ It handles proper HTTP formatting including status line, headers, and
5555+ body content. The response is written incrementally to avoid buffering
5656+ large responses in memory. *)
5757+type 'a http_response = {
5858+ write_status : int -> unit; (** Set the HTTP status code (200, 404, 500, etc.).
5959+ Must be called before writing headers or body. *)
6060+ write_header : string -> string -> unit; (** Add an HTTP response header.
6161+ Common headers include Content-Type, Set-Cookie, etc. *)
6262+ write_body : string -> unit; (** Write string content to the response body.
6363+ Handles encoding and streaming automatically. *)
6464+ write_body_chunk : bytes -> unit; (** Write binary data to the response body.
6565+ Useful for file downloads or binary content. *)
6666+ finish : unit -> unit; (** Complete the response and close the connection.
6767+ Must be called to ensure proper termination. *)
6868+}
6969+7070+(** {1 Conversion Functions} *)
7171+7272+(** Convert FastCGI request to HTTP request.
7373+7474+ Extracts HTTP-specific information from FastCGI parameters
7575+ and creates an HTTP request object.
7676+7777+ @param request FastCGI request
7878+ @return HTTP request with extracted information *)
7979+val request_of_fastcgi : 'a Fastcgi_types.request -> 'a http_request
8080+8181+(** Create HTTP response writer from FastCGI response.
8282+8383+ Wraps FastCGI response streams to provide HTTP-style
8484+ response writing interface.
8585+8686+ @param response FastCGI response
8787+ @return HTTP response writer *)
8888+val response_of_fastcgi : 'a Fastcgi_types.response -> 'a http_response
8989+9090+(** {1 Handler Utilities} *)
9191+9292+(** Responder handler type. *)
9393+type 'a responder_handler = 'a Fastcgi_types.request -> 'a Fastcgi_types.response -> Fastcgi_types.response_result
9494+9595+(** Convenience handler wrapper for HTTP-style handlers.
9696+9797+ Converts an HTTP-style handler function into a FastCGI handler.
9898+ This allows writing handlers that work with HTTP request/response
9999+ objects instead of raw FastCGI types.
100100+101101+ @param handler HTTP handler function
102102+ @return FastCGI responder handler *)
103103+val http_handler :
104104+ ('a http_request -> 'a http_response -> unit) ->
105105+ 'a responder_handler
106106+107107+(** {1 Common HTTP Operations} *)
108108+109109+(** Send a simple text response.
110110+111111+ @param response HTTP response writer
112112+ @param status HTTP status code
113113+ @param content_type MIME type
114114+ @param body Response body text *)
115115+val send_text_response :
116116+ 'a http_response ->
117117+ status:int ->
118118+ content_type:string ->
119119+ body:string ->
120120+ unit
121121+122122+(** Send a JSON response.
123123+124124+ @param response HTTP response writer
125125+ @param status HTTP status code
126126+ @param json JSON string *)
127127+val send_json_response :
128128+ 'a http_response ->
129129+ status:int ->
130130+ json:string ->
131131+ unit
132132+133133+(** Send an HTML response.
134134+135135+ @param response HTTP response writer
136136+ @param status HTTP status code
137137+ @param html HTML content *)
138138+val send_html_response :
139139+ 'a http_response ->
140140+ status:int ->
141141+ html:string ->
142142+ unit
143143+144144+(** Send an error response.
145145+146146+ @param response HTTP response writer
147147+ @param status HTTP error status code
148148+ @param message Error message *)
149149+val send_error_response :
150150+ 'a http_response ->
151151+ status:int ->
152152+ message:string ->
153153+ unit
154154+155155+(** Send a redirect response.
156156+157157+ @param response HTTP response writer
158158+ @param status Redirect status code (301, 302, etc.)
159159+ @param location Target URL *)
160160+val send_redirect_response :
161161+ 'a http_response ->
162162+ status:int ->
163163+ location:string ->
164164+ unit
165165+166166+(** {1 Request Parsing} *)
167167+168168+(** Parse query string into parameter map.
169169+170170+ @param query_string URL-encoded query string
171171+ @return Association list of parameter name-value pairs *)
172172+val parse_query_string : string -> (string * string) list
173173+174174+(** Parse form data from request body.
175175+176176+ Supports both application/x-www-form-urlencoded and
177177+ multipart/form-data content types.
178178+179179+ @param request HTTP request
180180+ @return Association list of form field name-value pairs *)
181181+val parse_form_data : 'a http_request -> (string * string) list
182182+183183+(** Get request header value.
184184+185185+ @param request HTTP request
186186+ @param name Header name (case-insensitive)
187187+ @return Header value if present *)
188188+val get_header : 'a http_request -> string -> string option
189189+190190+(** Get request parameter from query string or form data.
191191+192192+ @param request HTTP request
193193+ @param name Parameter name
194194+ @return Parameter value if present *)
195195+val get_param : 'a http_request -> string -> string option
196196+197197+(** {1 File Operations} *)
198198+199199+(** File upload information. *)
200200+type 'a file_upload = {
201201+ filename : string option; (** Original filename *)
202202+ content_type : string option; (** MIME type *)
203203+ size : int; (** File size in bytes *)
204204+ data : 'a Eio.Flow.source; (** File content stream *)
205205+}
206206+207207+(** Parse file uploads from multipart form data.
208208+209209+ @param request HTTP request with multipart content
210210+ @return Association list of field name to file upload *)
211211+val parse_file_uploads : 'a http_request -> (string * 'a file_upload) list
212212+213213+(** Save uploaded file to filesystem.
214214+215215+ @param fs Filesystem capability
216216+ @param path Destination path
217217+ @param upload File upload to save *)
218218+val save_upload :
219219+ fs:Eio.Fs.dir_ty Eio.Path.t ->
220220+ path:string ->
221221+ upload:'a file_upload ->
222222+ unit
+444
lib/fastcgi_types.mli
···11+(** Core FastCGI types and constants.
22+33+ This module defines the fundamental types used throughout the
44+ FastCGI protocol implementation.
55+66+ FastCGI is an open extension to CGI that provides high performance for
77+ all Internet applications without the penalties of Web server APIs.
88+ Unlike traditional CGI programs that are started for each request,
99+ FastCGI applications are long-lived processes that can handle multiple
1010+ requests over persistent connections. *)
1111+1212+(** {1 Core Types} *)
1313+1414+(** FastCGI protocol version.
1515+1616+ The current protocol uses version 1. Future versions of the
1717+ protocol may increment this value. Applications should check the version
1818+ field in incoming records and reject unsupported versions.
1919+2020+ Version 1 is represented by the value [1]. *)
2121+type version = int
2222+2323+(** FastCGI record types.
2424+2525+ All data transmitted over a FastCGI connection is packaged in records.
2626+ Each record has a type that determines how the record's content should
2727+ be interpreted. The protocol defines both management records (for
2828+ protocol-level communication) and application records (for request
2929+ processing).
3030+3131+ Management records contain information that is not specific to any web
3232+ server request, such as capability queries and unknown type responses.
3333+ Application records contain information about a particular request,
3434+ identified by a non-zero request ID. *)
3535+type record_type =
3636+ | Begin_request (** Starts a new request. Sent by the web server to begin
3737+ processing. Contains the role and connection flags. *)
3838+ | Abort_request (** Aborts an existing request. Sent by the web server
3939+ when an HTTP client closes its connection while the
4040+ request is still being processed. *)
4141+ | End_request (** Completes a request. Sent by the application to
4242+ terminate processing, either normally or due to
4343+ an error condition. *)
4444+ | Params (** Parameter name-value pairs. Used to transmit CGI-style
4545+ environment variables from the web server to the
4646+ application. Sent as a stream. *)
4747+ | Stdin (** Standard input data. Contains the request body data
4848+ that would normally be available on stdin in CGI.
4949+ Sent as a stream. *)
5050+ | Stdout (** Standard output data. Response data from the application
5151+ to the web server. This becomes the HTTP response.
5252+ Sent as a stream. *)
5353+ | Stderr (** Standard error data. Error messages from the application.
5454+ Used for logging and debugging. Sent as a stream. *)
5555+ | Data (** Additional data stream. Used only in the Filter role
5656+ to transmit file data that needs to be filtered.
5757+ Sent as a stream. *)
5858+ | Get_values (** Management record to query application variables.
5959+ Allows the web server to discover application
6060+ capabilities like max connections and multiplexing. *)
6161+ | Get_values_result (** Management record response to Get_values. Contains
6262+ the requested variable values. *)
6363+ | Unknown_type (** Management record for unknown type handling. Sent by
6464+ the application when it receives a record type it
6565+ doesn't understand. *)
6666+6767+(** FastCGI application roles.
6868+6969+ A FastCGI application can play one of several well-defined roles.
7070+ The role determines what information the application receives and
7171+ what it's expected to produce.
7272+7373+ A FastCGI application plays one of several well-defined roles. The most
7474+ familiar is the Responder role, in which the application receives all
7575+ the information associated with an HTTP request and generates an HTTP
7676+ response. *)
7777+type role =
7878+ | Responder (** The most common role, equivalent to traditional CGI.
7979+ The application receives all information associated with
8080+ an HTTP request and generates an HTTP response. This
8181+ includes environment variables, request headers, and
8282+ request body data. *)
8383+ | Authorizer (** Performs access control decisions. The application
8484+ receives HTTP request information and generates an
8585+ authorized/unauthorized decision. In case of authorization,
8686+ it can associate additional variables with the request.
8787+ For unauthorized requests, it provides a complete HTTP
8888+ error response. *)
8989+ | Filter (** Processes data streams with filtering. The application
9090+ receives HTTP request information plus an additional
9191+ data stream from a file stored on the web server, and
9292+ generates a "filtered" version of the data as an HTTP
9393+ response. Both the file and the filter can be access
9494+ controlled. *)
9595+9696+(** Request ID for multiplexing multiple requests over a single connection.
9797+9898+ FastCGI supports multiplexing, allowing multiple concurrent requests
9999+ to be processed over a single transport connection. Each request is
100100+ identified by a unique request ID within the scope of that connection.
101101+102102+ The Web server re-uses FastCGI request IDs; the application keeps track
103103+ of the current state of each request ID on a given transport connection.
104104+ Request IDs should be small integers to allow efficient tracking using
105105+ arrays rather than hash tables.
106106+107107+ The value [0] is reserved for management records and is called the
108108+ "null request ID". *)
109109+type request_id = int
110110+111111+(** Application-level status code.
112112+113113+ When an application completes a request, it provides an application
114114+ status code similar to the exit status of a traditional CGI program.
115115+ A value of [0] indicates success, while non-zero values indicate
116116+ various error conditions.
117117+118118+ The application sets the appStatus component to the status code that
119119+ the CGI program would have returned via the exit system call. *)
120120+type app_status = int
121121+122122+(** Protocol-level status codes.
123123+124124+ In addition to application status, each request completion includes
125125+ a protocol-level status that indicates whether the request was
126126+ processed normally or rejected for protocol-related reasons.
127127+128128+ These status codes allow the web server to understand why a request
129129+ was not processed and take appropriate action. *)
130130+type protocol_status =
131131+ | Request_complete (** Normal end of request. The application successfully
132132+ processed the request and the appStatus field
133133+ indicates the application-level result. *)
134134+ | Cant_mpx_conn (** Rejecting a new request because the application
135135+ cannot multiplex connections. This happens when
136136+ a web server sends concurrent requests over one
137137+ connection to an application that processes only
138138+ one request at a time per connection. *)
139139+ | Overloaded (** Rejecting a new request because the application
140140+ is overloaded. This occurs when the application
141141+ runs out of some resource, such as database
142142+ connections or memory. *)
143143+ | Unknown_role (** Rejecting a new request because the requested
144144+ role is unknown to the application. This happens
145145+ when the web server specifies a role that the
146146+ application doesn't implement. *)
147147+148148+(** Connection flags for controlling connection behavior.
149149+150150+ These flags are sent in Begin_request records to control how the
151151+ connection should be managed after the request completes. *)
152152+type connection_flags = {
153153+ keep_conn : bool; (** Keep connection open after request completion.
154154+155155+ If false, the application closes the connection after
156156+ responding to this request. If true, the application
157157+ does not close the connection after responding to this
158158+ request; the Web server retains responsibility for the
159159+ connection.
160160+161161+ This flag enables connection reuse for better performance,
162162+ especially important for high-traffic applications. *)
163163+}
164164+165165+(** {1 Record Types} *)
166166+167167+(** FastCGI record header.
168168+169169+ Every FastCGI record begins with an 8-byte header that identifies
170170+ the record type, request ID, and content length. This fixed-length
171171+ prefix allows efficient parsing and proper demultiplexing of records.
172172+173173+ A FastCGI record consists of a fixed-length prefix followed by a
174174+ variable number of content and padding bytes.
175175+176176+ The header format is platform-independent and uses network byte order
177177+ for multi-byte integers. *)
178178+type record_header = {
179179+ version : int; (** Protocol version. Must be [1] for this specification.
180180+ Future versions may increment this value. *)
181181+ record_type : record_type; (** Type of this record, determining how to interpret
182182+ the content data. *)
183183+ request_id : request_id; (** Request ID this record belongs to. Value [0] is
184184+ reserved for management records. *)
185185+ content_length : int; (** Number of bytes in the content data. Must be
186186+ between [0] and [65535]. *)
187187+ padding_length : int; (** Number of padding bytes following content.
188188+ Must be between [0] and [255]. Used for alignment. *)
189189+}
190190+191191+(** Begin request record body.
192192+193193+ This record marks the start of a new request and specifies the role
194194+ the application should play and connection management flags.
195195+196196+ The Web server sends a FCGI_BEGIN_REQUEST record to start a request.
197197+ The record body contains the role and flags that control request
198198+ processing. *)
199199+type begin_request_body = {
200200+ role : role; (** The role the web server expects the application
201201+ to play for this request. *)
202202+ flags : connection_flags; (** Flags controlling connection behavior after
203203+ request completion. *)
204204+}
205205+206206+(** End request record body.
207207+208208+ This record marks the completion of a request and provides both
209209+ application-level and protocol-level status information.
210210+211211+ The application sends a FCGI_END_REQUEST record to terminate a request,
212212+ either because the application has processed the request or because the
213213+ application has rejected the request. *)
214214+type end_request_body = {
215215+ app_status : app_status; (** Application-level status code, similar to
216216+ a CGI program's exit status. *)
217217+ protocol_status : protocol_status; (** Protocol-level status indicating normal
218218+ completion or rejection reason. *)
219219+}
220220+221221+(** Complete FastCGI record.
222222+223223+ A complete record consists of the header, content data, and optional
224224+ padding. The content interpretation depends on the record type.
225225+226226+ Records support padding to allow senders to keep data aligned for more
227227+ efficient processing. Experience with the X window system protocols shows
228228+ the performance benefit of such alignment. *)
229229+type record = {
230230+ header : record_header; (** Fixed 8-byte header with record metadata. *)
231231+ content : bytes; (** Variable-length content data. Length must match
232232+ header.content_length. *)
233233+ padding : bytes option; (** Optional padding data for alignment. Length must
234234+ match header.padding_length if present. *)
235235+}
236236+237237+(** Name-value pair for parameters.
238238+239239+ FastCGI uses a compact binary encoding for transmitting name-value pairs
240240+ such as CGI environment variables. This encoding supports both short
241241+ and long names/values efficiently.
242242+243243+ FastCGI transmits a name-value pair as the length of the name, followed
244244+ by the length of the value, followed by the name, followed by the value.
245245+ Lengths of 127 bytes and less can be encoded in one byte, while longer
246246+ lengths are always encoded in four bytes. *)
247247+type name_value_pair = {
248248+ name : string; (** Parameter name. For CGI compatibility, these are typically
249249+ uppercase environment variable names like "REQUEST_METHOD". *)
250250+ value : string; (** Parameter value. The value does not include a terminating
251251+ null byte in the FastCGI encoding. *)
252252+}
253253+254254+(** {1 Request/Response Model} *)
255255+256256+(** Request context containing all information for a FastCGI request.
257257+258258+ This high-level type aggregates all the information needed to process
259259+ a FastCGI request. It combines the protocol-level details (request ID,
260260+ role, flags) with the application data (parameters and input streams).
261261+262262+ The request follows a two-level processing model: First, the protocol
263263+ multiplexes a single transport connection between several independent
264264+ FastCGI requests. Second, within each request the protocol provides
265265+ several independent data streams in each direction. *)
266266+type 'a request = {
267267+ request_id : request_id; (** Unique identifier for this request within
268268+ the connection scope. Used for multiplexing. *)
269269+ role : role; (** The role this application should play for
270270+ this request (Responder, Authorizer, or Filter). *)
271271+ flags : connection_flags; (** Connection management flags from the web server. *)
272272+ params : (string * string) list; (** CGI-style environment variables transmitted
273273+ via FCGI_PARAMS records. These provide request
274274+ context like HTTP headers, server info, etc. *)
275275+ stdin : 'a Eio.Flow.source; (** Standard input stream, containing request body
276276+ data (equivalent to CGI stdin). For HTTP POST
277277+ requests, this contains the form data or payload. *)
278278+ data : 'a Eio.Flow.source option; (** Additional data stream, used only in Filter
279279+ role. Contains file data that needs to be
280280+ filtered. [None] for Responder and Authorizer. *)
281281+}
282282+283283+(** Response builder for constructing FastCGI responses.
284284+285285+ This type provides the output streams for sending response data back
286286+ to the web server. Following CGI conventions, it separates normal
287287+ output from error output.
288288+289289+ Both stdout and stderr data pass over a single transport connection from
290290+ the application to the Web server, rather than requiring separate pipes
291291+ as with CGI/1.1. *)
292292+type 'a response = {
293293+ stdout : 'a Eio.Flow.sink; (** Standard output stream for response data.
294294+ In Responder role, this contains the HTTP
295295+ response including headers and body. *)
296296+ stderr : 'a Eio.Flow.sink; (** Standard error stream for logging and debugging.
297297+ All role protocols use the FCGI_STDERR stream
298298+ just the way stderr is used in conventional
299299+ applications programming: to report application-level
300300+ errors in an intelligible way. *)
301301+}
302302+303303+(** Complete response with status.
304304+305305+ When an application finishes processing a request, it must provide
306306+ both application-level and protocol-level status information. This
307307+ allows the web server to understand the outcome and take appropriate
308308+ action.
309309+310310+ This corresponds to the FCGI_END_REQUEST record sent by the application. *)
311311+type response_result = {
312312+ app_status : app_status; (** Application exit status, equivalent to what
313313+ a CGI program would return via exit(). *)
314314+ protocol_status : protocol_status; (** Protocol-level completion status, indicating
315315+ normal completion or various rejection reasons. *)
316316+}
317317+318318+(** {1 Protocol Constants} *)
319319+320320+(** Protocol version constant.
321321+322322+ This constant represents FCGI_VERSION_1. This value should be used in
323323+ the version field of all record headers. *)
324324+val version_1 : int
325325+326326+(** Standard file descriptor for FastCGI listening socket.
327327+328328+ The Web server leaves a single file descriptor, FCGI_LISTENSOCK_FILENO,
329329+ open when the application begins execution. This descriptor refers to a
330330+ listening socket created by the Web server.
331331+332332+ The value equals STDIN_FILENO (0). Applications can distinguish between
333333+ CGI and FastCGI invocation by calling getpeername() on this descriptor. *)
334334+val listensock_fileno : int
335335+336336+(** {2 Record Type Constants}
337337+338338+ These integer constants correspond to the record_type variants and are
339339+ used in the binary protocol encoding. These are the values transmitted
340340+ in the type field of record headers. *)
341341+342342+(** Value [1]. Starts a new request. *)
343343+val fcgi_begin_request : int
344344+345345+(** Value [2]. Aborts an existing request. *)
346346+val fcgi_abort_request : int
347347+348348+(** Value [3]. Completes a request. *)
349349+val fcgi_end_request : int
350350+351351+(** Value [4]. Parameter name-value pairs. *)
352352+val fcgi_params : int
353353+354354+(** Value [5]. Standard input data. *)
355355+val fcgi_stdin : int
356356+357357+(** Value [6]. Standard output data. *)
358358+val fcgi_stdout : int
359359+360360+(** Value [7]. Standard error data. *)
361361+val fcgi_stderr : int
362362+363363+(** Value [8]. Additional data stream (Filter). *)
364364+val fcgi_data : int
365365+366366+(** Value [9]. Query application variables. *)
367367+val fcgi_get_values : int
368368+369369+(** Value [10]. Response to Get_values. *)
370370+val fcgi_get_values_result : int
371371+372372+(** Value [11]. Unknown record type response. *)
373373+val fcgi_unknown_type : int
374374+375375+(** {2 Role Constants}
376376+377377+ These integer constants correspond to the role variants and are used
378378+ in Begin_request record bodies. These identify the role the web server
379379+ expects the application to play. *)
380380+381381+(** Value [1]. Handle HTTP requests and generate responses. *)
382382+val fcgi_responder : int
383383+384384+(** Value [2]. Perform authorization decisions. *)
385385+val fcgi_authorizer : int
386386+387387+(** Value [3]. Process data streams with filtering. *)
388388+val fcgi_filter : int
389389+390390+(** {2 Flag Constants}
391391+392392+ These constants are used in the flags field of Begin_request records
393393+ to control connection behavior. *)
394394+395395+(** Value [1]. Keep connection open after request.
396396+ If zero, the application closes the connection after
397397+ responding to this request. If not zero, the application
398398+ does not close the connection after responding to this
399399+ request. *)
400400+val fcgi_keep_conn : int
401401+402402+(** {2 Protocol Limits}
403403+404404+ These constants define the maximum sizes for various protocol elements,
405405+ ensuring compatibility and preventing buffer overflows. *)
406406+407407+(** Value [65535]. Maximum bytes in record content.
408408+ Between 0 and 65535 bytes of data, interpreted
409409+ according to the record type. *)
410410+val max_content_length : int
411411+412412+(** Value [255]. Maximum bytes in record padding.
413413+ Between 0 and 255 bytes of data, which are ignored. *)
414414+val max_padding_length : int
415415+416416+(** Value [8]. Fixed size of record headers.
417417+ Number of bytes in a FCGI_Header. Future versions
418418+ of the protocol will not reduce this number. *)
419419+val header_length : int
420420+421421+(** {2 Management Record Variables}
422422+423423+ These string constants identify the standard management variables that
424424+ can be queried using FCGI_GET_VALUES records. They allow the web server
425425+ to discover application capabilities.
426426+427427+ The initial set provides information to help the server perform application
428428+ and connection management. *)
429429+430430+(** Variable name "FCGI_MAX_CONNS". The maximum number
431431+ of concurrent transport connections this application
432432+ will accept, e.g. "1" or "10". *)
433433+val fcgi_max_conns : string
434434+435435+(** Variable name "FCGI_MAX_REQS". The maximum number
436436+ of concurrent requests this application will accept,
437437+ e.g. "1" or "50". *)
438438+val fcgi_max_reqs : string
439439+440440+(** Variable name "FCGI_MPXS_CONNS". "0" if this
441441+ application does not multiplex connections (i.e.
442442+ handle concurrent requests over each connection),
443443+ "1" otherwise. *)
444444+val fcgi_mpxs_conns : string