FastCGI implementation in OCaml
1(** Responder role implementation for FastCGI. 2 3 The Responder role is the most common FastCGI role, equivalent to 4 traditional CGI applications. It handles HTTP requests and generates 5 HTTP responses. 6 7 A Responder FastCGI application has the same purpose as a CGI/1.1 program: 8 it receives all the information associated with an HTTP request and generates 9 an HTTP response. This includes CGI environment variables, request headers, 10 request body data, and produces HTTP response headers and body content. 11 12 The key difference from traditional CGI is that Responder applications are 13 long-lived processes that can handle multiple requests efficiently, avoiding 14 the overhead of process creation for each request. 15 16 This module provides high-level abstractions for working with HTTP requests 17 and responses, automatically handling the conversion between FastCGI protocol 18 elements and familiar HTTP concepts. *) 19 20(** {1 HTTP Request/Response Types} *) 21 22(** CGI-style environment variables. 23 24 A list of name-value pairs containing the CGI environment variables 25 passed from the web server. These typically include variables like 26 REQUEST_METHOD, REQUEST_URI, HTTP_HOST, CONTENT_TYPE, etc. *) 27type cgi_env = (string * string) list 28 29(** HTTP request information extracted from FastCGI parameters. 30 31 This type represents an HTTP request in a convenient form for application 32 processing. It extracts and parses the most commonly needed information 33 from the CGI environment variables provided by the web server. *) 34type 'a http_request = { 35 method_ : string; (** HTTP method (GET, POST, PUT, DELETE, etc.). 36 Extracted from REQUEST_METHOD CGI variable. *) 37 uri : string; (** Request URI path component, without query string. 38 Extracted from REQUEST_URI or SCRIPT_NAME + PATH_INFO. *) 39 query_string : string; (** URL query string parameters (after the '?' in the URL). 40 Extracted from QUERY_STRING CGI variable. *) 41 content_type : string option; (** MIME type of the request body, if present. 42 Extracted from CONTENT_TYPE CGI variable. *) 43 content_length : int option; (** Length of the request body in bytes, if known. 44 Extracted from CONTENT_LENGTH CGI variable. *) 45 headers : (string * string) list; (** HTTP headers sent by the client. Extracted from 46 CGI variables with HTTP_ prefix. *) 47 body : 'a Eio.Flow.source; (** Request body data stream. For POST requests, 48 this contains form data or payload content. *) 49} 50 51(** HTTP response builder for constructing responses. 52 53 This type provides a streaming interface for generating HTTP responses. 54 It handles proper HTTP formatting including status line, headers, and 55 body content. The response is written incrementally to avoid buffering 56 large responses in memory. *) 57type 'a http_response = { 58 write_status : int -> unit; (** Set the HTTP status code (200, 404, 500, etc.). 59 Must be called before writing headers or body. *) 60 write_header : string -> string -> unit; (** Add an HTTP response header. 61 Common headers include Content-Type, Set-Cookie, etc. *) 62 write_body : string -> unit; (** Write string content to the response body. 63 Handles encoding and streaming automatically. *) 64 write_body_chunk : bytes -> unit; (** Write binary data to the response body. 65 Useful for file downloads or binary content. *) 66 finish : unit -> unit; (** Complete the response and close the connection. 67 Must be called to ensure proper termination. *) 68} 69 70(** {1 Conversion Functions} *) 71 72(** Convert FastCGI request to HTTP request. 73 74 Extracts HTTP-specific information from FastCGI parameters 75 and creates an HTTP request object. 76 77 @param request FastCGI request 78 @return HTTP request with extracted information *) 79val request_of_fastcgi : 'a Fastcgi_types.request -> 'a http_request 80 81(** Create HTTP response writer from FastCGI response. 82 83 Wraps FastCGI response streams to provide HTTP-style 84 response writing interface. 85 86 @param response FastCGI response 87 @return HTTP response writer *) 88val response_of_fastcgi : 'a Fastcgi_types.response -> 'a http_response 89 90(** {1 Handler Utilities} *) 91 92(** Responder handler type. *) 93type 'a responder_handler = 'a Fastcgi_types.request -> 'a Fastcgi_types.response -> Fastcgi_types.response_result 94 95(** Convenience handler wrapper for HTTP-style handlers. 96 97 Converts an HTTP-style handler function into a FastCGI handler. 98 This allows writing handlers that work with HTTP request/response 99 objects instead of raw FastCGI types. 100 101 @param handler HTTP handler function 102 @return FastCGI responder handler *) 103val http_handler : 104 ('a http_request -> 'a http_response -> unit) -> 105 'a responder_handler 106 107(** {1 Common HTTP Operations} *) 108 109(** Send a simple text response. 110 111 @param response HTTP response writer 112 @param status HTTP status code 113 @param content_type MIME type 114 @param body Response body text *) 115val send_text_response : 116 'a http_response -> 117 status:int -> 118 content_type:string -> 119 body:string -> 120 unit 121 122(** Send a JSON response. 123 124 @param response HTTP response writer 125 @param status HTTP status code 126 @param json JSON string *) 127val send_json_response : 128 'a http_response -> 129 status:int -> 130 json:string -> 131 unit 132 133(** Send an HTML response. 134 135 @param response HTTP response writer 136 @param status HTTP status code 137 @param html HTML content *) 138val send_html_response : 139 'a http_response -> 140 status:int -> 141 html:string -> 142 unit 143 144(** Send an error response. 145 146 @param response HTTP response writer 147 @param status HTTP error status code 148 @param message Error message *) 149val send_error_response : 150 'a http_response -> 151 status:int -> 152 message:string -> 153 unit 154 155(** Send a redirect response. 156 157 @param response HTTP response writer 158 @param status Redirect status code (301, 302, etc.) 159 @param location Target URL *) 160val send_redirect_response : 161 'a http_response -> 162 status:int -> 163 location:string -> 164 unit 165 166(** {1 Request Parsing} *) 167 168(** Parse query string into parameter map. 169 170 @param query_string URL-encoded query string 171 @return Association list of parameter name-value pairs *) 172val parse_query_string : string -> (string * string) list 173 174(** Parse form data from request body. 175 176 Supports both application/x-www-form-urlencoded and 177 multipart/form-data content types. 178 179 @param request HTTP request 180 @return Association list of form field name-value pairs *) 181val parse_form_data : 'a http_request -> (string * string) list 182 183(** Get request header value. 184 185 @param request HTTP request 186 @param name Header name (case-insensitive) 187 @return Header value if present *) 188val get_header : 'a http_request -> string -> string option 189 190(** Get request parameter from query string or form data. 191 192 @param request HTTP request 193 @param name Parameter name 194 @return Parameter value if present *) 195val get_param : 'a http_request -> string -> string option 196 197(** {1 File Operations} *) 198 199(** File upload information. *) 200type 'a file_upload = { 201 filename : string option; (** Original filename *) 202 content_type : string option; (** MIME type *) 203 size : int; (** File size in bytes *) 204 data : 'a Eio.Flow.source; (** File content stream *) 205} 206 207(** Parse file uploads from multipart form data. 208 209 @param request HTTP request with multipart content 210 @return Association list of field name to file upload *) 211val parse_file_uploads : 'a http_request -> (string * 'a file_upload) list 212 213(** Save uploaded file to filesystem. 214 215 @param fs Filesystem capability 216 @param path Destination path 217 @param upload File upload to save *) 218val save_upload : 219 fs:Eio.Fs.dir_ty Eio.Path.t -> 220 path:string -> 221 upload:'a file_upload -> 222 unit