1
(* $Id: nethttpd_engine.mli 1063 2006-12-17 20:54:34Z gerd $
6
* Copyright 2005 Baretta s.r.l. and Gerd Stolpmann
8
* This file is part of Nethttpd.
10
* Nethttpd is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 2 of the License, or
13
* (at your option) any later version.
15
* Nethttpd is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with WDialog; if not, write to the Free Software
22
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25
(** {1 The event-based encapsulation of the HTTP daemon}
27
* This is a user-friendlier encapsulation of the HTTP daemon. It uses
28
* the engine module defined in [Uq_engines].
31
(* Integration into event-based server design *)
35
type engine_req_state =
42
class type http_engine_config =
44
inherit Nethttpd_reactor.http_processor_config
46
method config_input_flow_control : bool
47
(** If [true], the engine stops reading input tokens from the HTTP kernel when
48
* there is data in the input channel of the engine not yet read. If [false],
49
* all available input tokens are fetched from the kernel and buffered up
50
* in the input channel.
52
* In general, this {b should} be set to [true]. However, this is only possible
53
* when the user of the engine is prepared for flow control. In particular,
54
* all data contained in the input channel must be immediately read, or else
55
* the engine blocks. By calling [input_ch_async # request_notification], the
56
* user can be notified when there is data to read.
58
* When set to [false], the engine never blocks, but the price is that the
59
* input channel may become as large as needed to store the whole request.
61
* The option [config_limit_pipeline_size] does not have any effect for engines.
64
method config_output_flow_control : bool
65
(** If [true], the engine signals the user when there is already enough data
66
* to output, and no more output should be generated. The user can query
67
* this state by calling [output_ch_async # can_output], and react
68
* accordingly. The user can also ignore this signal, and the output channel
71
* If [false], the mentioned method [can_output] returns always [true]. This
72
* turns off flow control in the case it is implemented by the user of the
73
* engine, but actually not wanted.
75
* The internal processing of data is not affected by this configuration option.
76
* In doubt, set it to [true].
82
class type extended_async_environment =
84
inherit extended_environment
86
(** Environment also providing asynchronous views to I/O *)
88
method input_ch_async : Uq_engines.async_in_channel
89
(** This is the [input_ch] channel taken as asynchonous channel. This type of
90
* channel indicates when data is available to read, and also sends notifications.
91
* Note that this is only an alternate interface of the [input_ch] object.
93
* The method [can_input] returns true when there is at least one byte of
94
* the body to read, or the EOF has been seen. The channel buffers any arriving
95
* data (which can be limited in amount by [config_pipeline_size]).
97
* The behaviour of this channel is influenced by the configuration option
98
* [config_input_flow_control].
101
method output_ch_async : Uq_engines.async_out_channel
102
(** This is the [output_ch] channel taken as asynchronous channel. This type of
103
* channel indicates when space is available for further output, and also sends
105
* Note that this is only an alternate interface of the [output_ch] object.
107
* The method [can_output] returns [true] only when the internal buffer is empty,
108
* i.e. all data have been transmitted to the client. Independent of this, the
109
* channel buffers all data written to it.
111
* The behaviour of this channel is influenced by the configuration option
112
* [config_output_flow_control].
117
class type http_request_header_notification =
119
(** Notification that a new request header has arrived
121
* This object notifies the user that a new request header has arrived.
122
* The header is accessible by the [environment] object. The channels
123
* also contained in this object are locked at this moment. The user must
124
* now either call [schedule_accept_body] or [schedule_reject_body]. The
125
* user will get a second notification (a [http_request_notification], below)
126
* when the request body has completely arrived (in case of acceptance), or
127
* immediately (in case of rejection). One can also call [schedule_finish]
128
* at any time to drop the current request.
131
method req_state : engine_req_state
132
(** Returns the request processing state which is [`Received_header] at the
133
* moment when this notification is delivered.
136
method environment : extended_async_environment
137
(** The request environment. Depending on the request processing state, parts
138
* of the environment are already set up or still unaccessible ("locked").
139
* In the state [`Received_header] only the request header and the
140
* derived fields are accessible, and the input and output channels are
141
* locked. In the state [`Receiving_body] the input channel is unlocked,
142
* but it is not yet filled (reading from it may cause the exception
143
* [Buffer_underrun]). The output channel remains locked.
144
* In the state [`Received_request], the input channel is unlocked and filled
145
* with data, and the output channel is unlocked, too.
147
* This environment is not fully CGI-compatible. In particular, the following
149
* - There is no [cgi_path_info] and no [cgi_path_translated].
150
* - The user is always unauthenticated.
151
* - The [Status] response header works as in CGI. The [Location] header, however,
152
* must be a full URL when set (only browser redirects)
153
* - When the request body is transmitted by chunked encoding, the header
154
* [Content-Length] is not set. In CGI this is interpreted as missing body.
155
* It is unlikely that clients send requests with chunked encoding, as this
156
* may cause interoperability problems anyway.
160
method schedule_accept_body : on_request:(http_request_notification -> unit) ->
161
?on_error:(unit -> unit) ->
163
(** Schedules that the request body is accepted. In terms of HTTP, this sends the
164
* "100 Continue" response when necessary. One can reply with a positive or
167
* This method returns immediately, and sets callbacks for certain events.
168
* When the body has completely arrived (or is empty), the function
169
* [on_request] is called back. The argument is the full request notification
172
* When the request is dropped for some reason, [on_error] is called back instead.
173
* This can be used to free resources, for example.
175
* Neither of the callbacks must raise exceptions.
178
method schedule_reject_body : on_request:(http_request_notification -> unit) ->
179
?on_error:(unit -> unit) ->
181
(** Schedules that the request body is rejected. In terms of HTTP, this prevents
182
* sending the "100 Continue" response. Any arriving request body is silently
183
* discarded. One should immediately reply with an error mesage.
186
* This method returns immediately, and sets callbacks for certain events.
187
* When the body has completely arrived (or is empty), the function
188
* [on_request] is called back. The argument is the full request notification
191
* When the request is dropped for some reason, [on_error] is called back instead.
192
* This can be used to free resources, for example.
194
* Neither of the callbacks must raise exceptions.
197
method schedule_finish : unit -> unit
198
(** Schedules that the request is finished. This method should be called after
199
* the regular processing of the request to ensure that the HTTP protocol
200
* is fulfilled. If the request body has not been
201
* fully read, this is now done, and its data are dropped. If the response
202
* is incomplete, it is completed. If the error is not recoverable, a "Server
203
* Error" is generated.
209
and http_request_notification =
211
(** Notification that the whole request has arrived
213
* This object notifies the user that the request has fully arrived (including
214
* the body if accepted), and can now be responded. The [environment] is the
215
* same as in the request header notification, but the channels are now
219
method req_state : engine_req_state
220
(** Returns the request processing state which is [`Received_request] at the
221
* moment when this notification is delivered.
224
method environment : extended_async_environment
225
(** The request environment. See above. *)
227
method schedule_finish : unit -> unit
228
(** Schedules that the request is finished. See above. *)
233
class http_engine : on_request_header:(http_request_header_notification -> unit) ->
235
#http_engine_config -> Unix.file_descr ->
236
Unixqueue.unix_event_system ->
237
[unit] Uq_engines.engine
238
(** This engine processes the requests arriving on the file descriptor using
239
* the Unix event system. Whenever a new request header arrives, the function
240
* [on_request_header] is called back, and must handle the request.
242
* Unless aborted using the [abort] method, this engine is always successful.
243
* Errors are logged, but not returned as result.
245
* The file descriptor is closed after processing all HTTP requests and
246
* responses. It is also closed on error and when the engine is aborted.
248
* An aborted engine does not try to clean up resources external to the
249
* engine, e.g. by calling the [on_error] functions. This is up to the user.
253
class type http_engine_processing_config =
255
method config_synch_input :
256
(Netchannels.in_obj_channel -> unit) ->
257
Uq_engines.async_in_channel ->
259
(** The "input synchronizer": It is called as [obj # config_synch_input f ch]
260
* to create a synchronous input channel from an asynchronous one, [ch].
261
* The function [f] must be called back by the synchronizer when synchronisation
262
* is established, and with the synchronous channel [ch'] as argument.
263
* In particular, the task of the synchronizer is to turn blocking reads of
264
* [ch'] into non-blocking reads of [ch]. In general there are two ways of
266
* - Buffer all input from [ch] until the end of the channel is reached,
267
* then call [f] with a wrapper channel [ch'] that just reads from the
269
* - Run [f] in a different thread that blocks whenever there is nothing to
272
* Both implementations are allowed, i.e. {b it is allowed that [f] runs in
273
* a different thread}.
275
* CHECK: How to handle exceptions raised from [f]? Idea: [f] is obliged to
276
* close [ch'] in this case, even if [ch] is not yet at the end. The rest of
277
* exception handling is up to the user. - The complementary must also be true:
278
* When there is an error in the engine, [ch] must be closed to signal the
279
* other thread that we have a problem.
282
method config_synch_output :
283
(Netchannels.out_obj_channel -> unit) ->
284
Uq_engines.async_out_channel ->
286
(** The "output synchronizer": It is called as [obj # config_synch_output f ch]
287
* to create a synchronous output channel from an asynchronous one, [ch].
288
* The function [f] must be called back by the synchronizer when synchronisation
289
* is established, and with the synchronous channel [ch'] as argument.
290
* In particular, the task of the synchronizer is to turn blocking writes to
291
* [ch'] into non-blocking writes to [ch]. In general there are two ways of
293
* - Call [f], then buffer all output to [ch'] until the end of the channel is
294
* reached, and finally output the contents of the buffer in an asynchronous
296
* - Run [f] in a different thread that blocks whenever there is no space to
299
* Both implementations are allowed, i.e. {b it is allowed that [f] runs in
300
* a different thread}.
306
class buffering_engine_processing_config : http_engine_processing_config
307
(** Implements the synchronisation by buffering *)
309
class type http_engine_processing_context =
312
method engine : unit Uq_engines.engine
313
(** The engine doing HTTP *)
317
val process_connection :
318
#Nethttpd_reactor.http_processor_config ->
319
#http_engine_processing_config ->
321
Unixqueue.unix_event_system ->
323
http_engine_processing_context
324
(** Sets up an engine that processes all requests using the service description.
325
* This function returns immediately, one needs to [Unixqueue.run] the event
326
* system to start the engine.
328
* The passed [http_engine_processing_config] is crucial for good performance.