···
1
+
(** Core FastCGI types and constants.
3
+
This module defines the fundamental types used throughout the
4
+
FastCGI protocol implementation.
6
+
FastCGI is an open extension to CGI that provides high performance for
7
+
all Internet applications without the penalties of Web server APIs.
8
+
Unlike traditional CGI programs that are started for each request,
9
+
FastCGI applications are long-lived processes that can handle multiple
10
+
requests over persistent connections. *)
12
+
(** {1 Core Types} *)
14
+
(** FastCGI protocol version.
16
+
The current protocol uses version 1. Future versions of the
17
+
protocol may increment this value. Applications should check the version
18
+
field in incoming records and reject unsupported versions.
20
+
Version 1 is represented by the value [1]. *)
23
+
(** FastCGI record types.
25
+
All data transmitted over a FastCGI connection is packaged in records.
26
+
Each record has a type that determines how the record's content should
27
+
be interpreted. The protocol defines both management records (for
28
+
protocol-level communication) and application records (for request
31
+
Management records contain information that is not specific to any web
32
+
server request, such as capability queries and unknown type responses.
33
+
Application records contain information about a particular request,
34
+
identified by a non-zero request ID. *)
36
+
| Begin_request (** Starts a new request. Sent by the web server to begin
37
+
processing. Contains the role and connection flags. *)
38
+
| Abort_request (** Aborts an existing request. Sent by the web server
39
+
when an HTTP client closes its connection while the
40
+
request is still being processed. *)
41
+
| End_request (** Completes a request. Sent by the application to
42
+
terminate processing, either normally or due to
43
+
an error condition. *)
44
+
| Params (** Parameter name-value pairs. Used to transmit CGI-style
45
+
environment variables from the web server to the
46
+
application. Sent as a stream. *)
47
+
| Stdin (** Standard input data. Contains the request body data
48
+
that would normally be available on stdin in CGI.
49
+
Sent as a stream. *)
50
+
| Stdout (** Standard output data. Response data from the application
51
+
to the web server. This becomes the HTTP response.
52
+
Sent as a stream. *)
53
+
| Stderr (** Standard error data. Error messages from the application.
54
+
Used for logging and debugging. Sent as a stream. *)
55
+
| Data (** Additional data stream. Used only in the Filter role
56
+
to transmit file data that needs to be filtered.
57
+
Sent as a stream. *)
58
+
| Get_values (** Management record to query application variables.
59
+
Allows the web server to discover application
60
+
capabilities like max connections and multiplexing. *)
61
+
| Get_values_result (** Management record response to Get_values. Contains
62
+
the requested variable values. *)
63
+
| Unknown_type (** Management record for unknown type handling. Sent by
64
+
the application when it receives a record type it
65
+
doesn't understand. *)
67
+
(** FastCGI application roles.
69
+
A FastCGI application can play one of several well-defined roles.
70
+
The role determines what information the application receives and
71
+
what it's expected to produce.
73
+
A FastCGI application plays one of several well-defined roles. The most
74
+
familiar is the Responder role, in which the application receives all
75
+
the information associated with an HTTP request and generates an HTTP
78
+
| Responder (** The most common role, equivalent to traditional CGI.
79
+
The application receives all information associated with
80
+
an HTTP request and generates an HTTP response. This
81
+
includes environment variables, request headers, and
82
+
request body data. *)
83
+
| Authorizer (** Performs access control decisions. The application
84
+
receives HTTP request information and generates an
85
+
authorized/unauthorized decision. In case of authorization,
86
+
it can associate additional variables with the request.
87
+
For unauthorized requests, it provides a complete HTTP
89
+
| Filter (** Processes data streams with filtering. The application
90
+
receives HTTP request information plus an additional
91
+
data stream from a file stored on the web server, and
92
+
generates a "filtered" version of the data as an HTTP
93
+
response. Both the file and the filter can be access
96
+
(** Request ID for multiplexing multiple requests over a single connection.
98
+
FastCGI supports multiplexing, allowing multiple concurrent requests
99
+
to be processed over a single transport connection. Each request is
100
+
identified by a unique request ID within the scope of that connection.
102
+
The Web server re-uses FastCGI request IDs; the application keeps track
103
+
of the current state of each request ID on a given transport connection.
104
+
Request IDs should be small integers to allow efficient tracking using
105
+
arrays rather than hash tables.
107
+
The value [0] is reserved for management records and is called the
108
+
"null request ID". *)
109
+
type request_id = int
111
+
(** Application-level status code.
113
+
When an application completes a request, it provides an application
114
+
status code similar to the exit status of a traditional CGI program.
115
+
A value of [0] indicates success, while non-zero values indicate
116
+
various error conditions.
118
+
The application sets the appStatus component to the status code that
119
+
the CGI program would have returned via the exit system call. *)
120
+
type app_status = int
122
+
(** Protocol-level status codes.
124
+
In addition to application status, each request completion includes
125
+
a protocol-level status that indicates whether the request was
126
+
processed normally or rejected for protocol-related reasons.
128
+
These status codes allow the web server to understand why a request
129
+
was not processed and take appropriate action. *)
130
+
type protocol_status =
131
+
| Request_complete (** Normal end of request. The application successfully
132
+
processed the request and the appStatus field
133
+
indicates the application-level result. *)
134
+
| Cant_mpx_conn (** Rejecting a new request because the application
135
+
cannot multiplex connections. This happens when
136
+
a web server sends concurrent requests over one
137
+
connection to an application that processes only
138
+
one request at a time per connection. *)
139
+
| Overloaded (** Rejecting a new request because the application
140
+
is overloaded. This occurs when the application
141
+
runs out of some resource, such as database
142
+
connections or memory. *)
143
+
| Unknown_role (** Rejecting a new request because the requested
144
+
role is unknown to the application. This happens
145
+
when the web server specifies a role that the
146
+
application doesn't implement. *)
148
+
(** Connection flags for controlling connection behavior.
150
+
These flags are sent in Begin_request records to control how the
151
+
connection should be managed after the request completes. *)
152
+
type connection_flags = {
153
+
keep_conn : bool; (** Keep connection open after request completion.
155
+
If false, the application closes the connection after
156
+
responding to this request. If true, the application
157
+
does not close the connection after responding to this
158
+
request; the Web server retains responsibility for the
161
+
This flag enables connection reuse for better performance,
162
+
especially important for high-traffic applications. *)
165
+
(** {1 Record Types} *)
167
+
(** FastCGI record header.
169
+
Every FastCGI record begins with an 8-byte header that identifies
170
+
the record type, request ID, and content length. This fixed-length
171
+
prefix allows efficient parsing and proper demultiplexing of records.
173
+
A FastCGI record consists of a fixed-length prefix followed by a
174
+
variable number of content and padding bytes.
176
+
The header format is platform-independent and uses network byte order
177
+
for multi-byte integers. *)
178
+
type record_header = {
179
+
version : int; (** Protocol version. Must be [1] for this specification.
180
+
Future versions may increment this value. *)
181
+
record_type : record_type; (** Type of this record, determining how to interpret
182
+
the content data. *)
183
+
request_id : request_id; (** Request ID this record belongs to. Value [0] is
184
+
reserved for management records. *)
185
+
content_length : int; (** Number of bytes in the content data. Must be
186
+
between [0] and [65535]. *)
187
+
padding_length : int; (** Number of padding bytes following content.
188
+
Must be between [0] and [255]. Used for alignment. *)
191
+
(** Begin request record body.
193
+
This record marks the start of a new request and specifies the role
194
+
the application should play and connection management flags.
196
+
The Web server sends a FCGI_BEGIN_REQUEST record to start a request.
197
+
The record body contains the role and flags that control request
199
+
type begin_request_body = {
200
+
role : role; (** The role the web server expects the application
201
+
to play for this request. *)
202
+
flags : connection_flags; (** Flags controlling connection behavior after
203
+
request completion. *)
206
+
(** End request record body.
208
+
This record marks the completion of a request and provides both
209
+
application-level and protocol-level status information.
211
+
The application sends a FCGI_END_REQUEST record to terminate a request,
212
+
either because the application has processed the request or because the
213
+
application has rejected the request. *)
214
+
type end_request_body = {
215
+
app_status : app_status; (** Application-level status code, similar to
216
+
a CGI program's exit status. *)
217
+
protocol_status : protocol_status; (** Protocol-level status indicating normal
218
+
completion or rejection reason. *)
221
+
(** Complete FastCGI record.
223
+
A complete record consists of the header, content data, and optional
224
+
padding. The content interpretation depends on the record type.
226
+
Records support padding to allow senders to keep data aligned for more
227
+
efficient processing. Experience with the X window system protocols shows
228
+
the performance benefit of such alignment. *)
230
+
header : record_header; (** Fixed 8-byte header with record metadata. *)
231
+
content : bytes; (** Variable-length content data. Length must match
232
+
header.content_length. *)
233
+
padding : bytes option; (** Optional padding data for alignment. Length must
234
+
match header.padding_length if present. *)
237
+
(** Name-value pair for parameters.
239
+
FastCGI uses a compact binary encoding for transmitting name-value pairs
240
+
such as CGI environment variables. This encoding supports both short
241
+
and long names/values efficiently.
243
+
FastCGI transmits a name-value pair as the length of the name, followed
244
+
by the length of the value, followed by the name, followed by the value.
245
+
Lengths of 127 bytes and less can be encoded in one byte, while longer
246
+
lengths are always encoded in four bytes. *)
247
+
type name_value_pair = {
248
+
name : string; (** Parameter name. For CGI compatibility, these are typically
249
+
uppercase environment variable names like "REQUEST_METHOD". *)
250
+
value : string; (** Parameter value. The value does not include a terminating
251
+
null byte in the FastCGI encoding. *)
254
+
(** {1 Request/Response Model} *)
256
+
(** Request context containing all information for a FastCGI request.
258
+
This high-level type aggregates all the information needed to process
259
+
a FastCGI request. It combines the protocol-level details (request ID,
260
+
role, flags) with the application data (parameters and input streams).
262
+
The request follows a two-level processing model: First, the protocol
263
+
multiplexes a single transport connection between several independent
264
+
FastCGI requests. Second, within each request the protocol provides
265
+
several independent data streams in each direction. *)
266
+
type 'a request = {
267
+
request_id : request_id; (** Unique identifier for this request within
268
+
the connection scope. Used for multiplexing. *)
269
+
role : role; (** The role this application should play for
270
+
this request (Responder, Authorizer, or Filter). *)
271
+
flags : connection_flags; (** Connection management flags from the web server. *)
272
+
params : (string * string) list; (** CGI-style environment variables transmitted
273
+
via FCGI_PARAMS records. These provide request
274
+
context like HTTP headers, server info, etc. *)
275
+
stdin : 'a Eio.Flow.source; (** Standard input stream, containing request body
276
+
data (equivalent to CGI stdin). For HTTP POST
277
+
requests, this contains the form data or payload. *)
278
+
data : 'a Eio.Flow.source option; (** Additional data stream, used only in Filter
279
+
role. Contains file data that needs to be
280
+
filtered. [None] for Responder and Authorizer. *)
283
+
(** Response builder for constructing FastCGI responses.
285
+
This type provides the output streams for sending response data back
286
+
to the web server. Following CGI conventions, it separates normal
287
+
output from error output.
289
+
Both stdout and stderr data pass over a single transport connection from
290
+
the application to the Web server, rather than requiring separate pipes
291
+
as with CGI/1.1. *)
292
+
type 'a response = {
293
+
stdout : 'a Eio.Flow.sink; (** Standard output stream for response data.
294
+
In Responder role, this contains the HTTP
295
+
response including headers and body. *)
296
+
stderr : 'a Eio.Flow.sink; (** Standard error stream for logging and debugging.
297
+
All role protocols use the FCGI_STDERR stream
298
+
just the way stderr is used in conventional
299
+
applications programming: to report application-level
300
+
errors in an intelligible way. *)
303
+
(** Complete response with status.
305
+
When an application finishes processing a request, it must provide
306
+
both application-level and protocol-level status information. This
307
+
allows the web server to understand the outcome and take appropriate
310
+
This corresponds to the FCGI_END_REQUEST record sent by the application. *)
311
+
type response_result = {
312
+
app_status : app_status; (** Application exit status, equivalent to what
313
+
a CGI program would return via exit(). *)
314
+
protocol_status : protocol_status; (** Protocol-level completion status, indicating
315
+
normal completion or various rejection reasons. *)
318
+
(** {1 Protocol Constants} *)
320
+
(** Protocol version constant.
322
+
This constant represents FCGI_VERSION_1. This value should be used in
323
+
the version field of all record headers. *)
324
+
val version_1 : int
326
+
(** Standard file descriptor for FastCGI listening socket.
328
+
The Web server leaves a single file descriptor, FCGI_LISTENSOCK_FILENO,
329
+
open when the application begins execution. This descriptor refers to a
330
+
listening socket created by the Web server.
332
+
The value equals STDIN_FILENO (0). Applications can distinguish between
333
+
CGI and FastCGI invocation by calling getpeername() on this descriptor. *)
334
+
val listensock_fileno : int
336
+
(** {2 Record Type Constants}
338
+
These integer constants correspond to the record_type variants and are
339
+
used in the binary protocol encoding. These are the values transmitted
340
+
in the type field of record headers. *)
342
+
(** Value [1]. Starts a new request. *)
343
+
val fcgi_begin_request : int
345
+
(** Value [2]. Aborts an existing request. *)
346
+
val fcgi_abort_request : int
348
+
(** Value [3]. Completes a request. *)
349
+
val fcgi_end_request : int
351
+
(** Value [4]. Parameter name-value pairs. *)
352
+
val fcgi_params : int
354
+
(** Value [5]. Standard input data. *)
355
+
val fcgi_stdin : int
357
+
(** Value [6]. Standard output data. *)
358
+
val fcgi_stdout : int
360
+
(** Value [7]. Standard error data. *)
361
+
val fcgi_stderr : int
363
+
(** Value [8]. Additional data stream (Filter). *)
364
+
val fcgi_data : int
366
+
(** Value [9]. Query application variables. *)
367
+
val fcgi_get_values : int
369
+
(** Value [10]. Response to Get_values. *)
370
+
val fcgi_get_values_result : int
372
+
(** Value [11]. Unknown record type response. *)
373
+
val fcgi_unknown_type : int
375
+
(** {2 Role Constants}
377
+
These integer constants correspond to the role variants and are used
378
+
in Begin_request record bodies. These identify the role the web server
379
+
expects the application to play. *)
381
+
(** Value [1]. Handle HTTP requests and generate responses. *)
382
+
val fcgi_responder : int
384
+
(** Value [2]. Perform authorization decisions. *)
385
+
val fcgi_authorizer : int
387
+
(** Value [3]. Process data streams with filtering. *)
388
+
val fcgi_filter : int
390
+
(** {2 Flag Constants}
392
+
These constants are used in the flags field of Begin_request records
393
+
to control connection behavior. *)
395
+
(** Value [1]. Keep connection open after request.
396
+
If zero, the application closes the connection after
397
+
responding to this request. If not zero, the application
398
+
does not close the connection after responding to this
400
+
val fcgi_keep_conn : int
402
+
(** {2 Protocol Limits}
404
+
These constants define the maximum sizes for various protocol elements,
405
+
ensuring compatibility and preventing buffer overflows. *)
407
+
(** Value [65535]. Maximum bytes in record content.
408
+
Between 0 and 65535 bytes of data, interpreted
409
+
according to the record type. *)
410
+
val max_content_length : int
412
+
(** Value [255]. Maximum bytes in record padding.
413
+
Between 0 and 255 bytes of data, which are ignored. *)
414
+
val max_padding_length : int
416
+
(** Value [8]. Fixed size of record headers.
417
+
Number of bytes in a FCGI_Header. Future versions
418
+
of the protocol will not reduce this number. *)
419
+
val header_length : int
421
+
(** {2 Management Record Variables}
423
+
These string constants identify the standard management variables that
424
+
can be queried using FCGI_GET_VALUES records. They allow the web server
425
+
to discover application capabilities.
427
+
The initial set provides information to help the server perform application
428
+
and connection management. *)
430
+
(** Variable name "FCGI_MAX_CONNS". The maximum number
431
+
of concurrent transport connections this application
432
+
will accept, e.g. "1" or "10". *)
433
+
val fcgi_max_conns : string
435
+
(** Variable name "FCGI_MAX_REQS". The maximum number
436
+
of concurrent requests this application will accept,
437
+
e.g. "1" or "50". *)
438
+
val fcgi_max_reqs : string
440
+
(** Variable name "FCGI_MPXS_CONNS". "0" if this
441
+
application does not multiplex connections (i.e.
442
+
handle concurrent requests over each connection),
444
+
val fcgi_mpxs_conns : string