Authors
- Richard Frith-Macdonald (
rfm@gnu.org
)
-
Date: Generated at 2025-04-12 16:42:20 -0600
Copyright: (C) 2004-2010 Free Software Foundation, Inc.
The WebServer class provides the framework for a GNUstep
program to act as an HTTP or HTTPS server for simple
applications.
It does not attempt to be
a general-purpose web server, but is rather intended to
permit a program to easily handle requests from
automated systems which are intended to control,
monitor, or use the services provided by the program
in which the class is embedded.
The emphasis is on
making it robust/reliable/simple, so you can rapidly
develop software using it.
By default, it is a
single-threaded, single-process system using
asynchronous I/O, so you can easily run it under
debug in gdb to fix any bugs in your delegate object.
For performance, it can also operate as a
massively multi-threaded process, with separate I/O
threads handling groups of hundreds or thousands of
simultaneous connections, and a pool of
processing threads handling parsing of incoming
requests.
The class is controlled by a few straightforward settings
and basically operates by handing over requests to its
delegate. The delegate must at least implement the
[<WebServerDelegate>-processRequest:response:for:]
method.
Built-in facilities include -
-
Parsing of parameter string in request URL
-
Parsing of url encoded form data in a POST request
-
Parsing of form encoded data in a POST request
-
Substitution into template pages on output
-
SSL support
-
HTTP Basic authentication
-
Limit access by IP address
-
Limit total number of simultaneous connections
-
Limit number of simultaneous connections from one
address
-
Limit idle time permitted on a connection
-
Limit size of request headers permitted
-
Limit size of request body permitted
The WebServer class essentially works using asynchronous
I/O in a single thread. The asynchronous I/O mechanism is
capably of reading a request of up to the operating
systems network buffer size in a single operation and
similarly writing out a response of up to the
operating system's network buffer size.
As
long as requests and responses are
within those limits, it can be assumed that slow
processing of a request in the
[<WebServerDelegate>-processRequest:response:for:]
method will have little impact on efficiency as the WebServer read request and write responses as rapidly as the delegates processing can handle them.
If however the I/O sizes are larger than the buffers, then writing a response will need to be multiple operations and each buffer full of data may need to wait for the next call to the processing method before it can be sent.
So, for large request/response sizes, or other cases where processing a single request at a time is a problem, the WebServer class provides a simple mechanism for supporting multithreaded use.
To use multiple threads, all you need to do is have the
delegate implementation of
[<WebServerDelegate>-processRequest:response:for:]
pass processing to another thread and return NO
. When processing is complete, the delegate calls -completedWithResponse:
to pass the response back to the WebServer instance for delivery to the client.
NB. the -completedWithResponse:
method is safe to call from any thread but all other methods of the class should be called only from the master thread. If a delegate needs to call methods of the WebServer instance in order to handle a request, it should do so in the [<WebServerDelegate>-processRequest:response:for:]
method before handing control to another thread.
If the simple threading outlined above is not sufficient
for your appplication, a more agressive threading scheme
is available.
You may call the
-setIOThreads:andPool:
method to ask the WebServer instance to use threading
internally itself. In this case the low-level I/O
operations will be shared across the specified
number of I/O threads instead of occurring in the
master thread (makes sense if you need to handle a
very large number of simultaneous connections). In
addition, the parsing of the incoming HTTP request
and the generation of the raw data of the outgoing
response are performed using threads from the thread
pool, so that the I/O threads can concentrate on the
low level communications.
With the use of a thread pool, you muse be aware that
the
-preProcessRequest:response:for:
method will be executed by a thread from the pool
rather than by the master thread.
This may be
useful if you wish to split the processing into part
which is thread-safe, and part which uses complex
interacting data structures which are hard to
make safe (done in the main processing method).
- Declared in:
- WebServer.h
You create an instance of the WebServer class in order
to handle incoming HTTP or HTTPS requests on a single
port.
Before use, it must be configured using the
-setAddress:port:secure:
method to specify the address and port and if/how
SSL is to be used.
You must also set a delegate to handle incoming
requests, and may specify a maximum number of
simultaneous connections which may be in
progress etc.
In addition to the options which may be set directly in
the class, you can provide some configuration via the
standard NSDefaults class. This information is set
at initialisation of an instance and the class
recognises the following defaults keys -
- WebServerFrameOptions
-
A string defining the frame options setting for
responses produced by the server (application
code can always override this).
If this is
not defined, the value DENY
is used to
prevent responses from being presented inside
frames.
If this is defined as an empty
string, no X-Frame-Options header is set (unless
application code explicitly sets the header
in the response).
Unless you use this option
(or your application code explicitly sets/removes the
header), all responses will have the frame
option DENY, which will at least tend to keep
security auditors who are afraid of
click-jacking attacks happy, even if it
serves no other purpose.
- WebServerHosts
-
An array of host IP addresses to list the hosts
permitted to send requests to the server. If
defined, requests from other hosts will be
rejected (with an HTTP 403 response). It may be
better to use firewalling to control this sort of
thing.
- WebServerQuiet
-
An array of host IP addresses to refrain from logging
... this is useful if (for instance) you have a
monitoring process which sends requests to the
server to be sure it's alive, and don't want to
log all the connections from this monitor.
Not
only do we refrain from logging anything but
exceptional events about these hosts,
connections and requests by these hosts are
not counted in statistics we generate.
- ReverseHostLookup
-
A boolean (default
NO
) which specifies
whether the server should lookup the host name
for each incoming connection, and refuse connections
where no host can be found. The downside of
enabling this is that host lookups can be slow
and cause performance problems.
To shut down the WebServer, you must call
-setAddress:port:secure:
with nil
arguments. This will stop the
server listening for incoming connections and wait
for any existing connections to be closed (or to time
out).
NB. Once a WebServer instance has been
started listening on a port, it is not OK to simply
release it without shutting it down... doing that
will cause a leak of memory and resources as the
instance will continue to operate.
+ (NSURL*)
baseURLForRequest: (
WebServerRequest*)request;
Returns the base URL used by the remote client to
send the request.
+ (NSUInteger)
decodeURLEncodedForm: (NSData*)data
into: (NSMutableDictionary*)dict;
Same as the instance method of the same name.
+ (NSUInteger)
encodeURLEncodedForm: (NSDictionary*)dict
charset: (NSString*)charset
into: (NSMutableData*)data;
Same as the instance method of the same name.
+ (NSUInteger)
encodeURLEncodedForm: (NSDictionary*)dict
into: (NSMutableData*)data;
+ (NSString*)
escapeHTML: (NSString*)str;
Same as the instance method of the same name.
+ (NSURL*)
linkPath: (NSString*)newPath
relative: (NSURL*)oldURL
query: (NSDictionary*)fields
,...;
Returns a new URL formed by putting the
newPath in the oldURL and
appending a query string containing the
fields specified in the fields
argument (optionally extended/overridden by any
other fields defined as key/value pairs in
the nil
terminated list of additional
arguments.
If the oldURL is
nil
, then the new URL will be a
relative URL containing just the path and query
string.
If newPath is an absolute
path, it replaces the path from oldURL,
otherwise it replaces the last path component
from uldURL.
+ (BOOL)
matchIP: (NSString*)address
to: (NSString*)pattern;
Convenience function to check to see if a
particular IP address matches
anything in a comma separated list of IP addresses
or masks.
This currently handles simple IPv4
addresses, and masks in the format
nnn.nnn.nnn.nnn/bb where bb is the
number of bits of the mask to match against the
address (eg. 192.168.11.0/24).
+ (NSData*)
parameter: (NSString*)name
at: (NSUInteger)index
from: (NSDictionary*)params;
Same as the instance method of the same
name.
+ (NSString*)
parameterString: (NSString*)name
at: (NSUInteger)index
from: (NSDictionary*)params
charset: (NSString*)charset;
Same as the instance method of the same
name.
+ (BOOL)
redirectRequest: (
WebServerRequest*)request
response: (
WebServerResponse*)response
to: (id)destination;
Convenience method to set up a temporary
redirect to the specified URL using the supplied
response data. The method returns
YES
so that it is reasonable to pass
its return value back directly as the return value for
a call to the
[<WebServerDelegate>-processRequest:response:for:]
method.
If
destination is an NSURL, the redirection is done to the specified location, otherwise arguments description is taken as a local path to be used with the base URL of the
request.
- (BOOL)
accessRequest: (
WebServerRequest*)request
response: (
WebServerResponse*)response;
This method is called for each incoming
request, and checks that the requested
resource is accessible (basic user/password access
control).
The method returns
YES
if access is granted, or returns
NO
and sets the appropriate
response values if access is refused.
If access is refused by this method, the
delegate is not informed of the
request
at all... so this forms an initial access control
mechanism, but if it is passed, the delegate is
still free to implement its own additional access
control within the
[<WebServerDelegate>-processRequest:response:for:]
method.
The access control is managed by the
WebServerAccess
user default, which is a dictionary whose keys are paths, and whose values are dictionaries specifying the access control for those paths. Access control is done on the basis of the longest matching path.
Each access control dictionary contains an authentication realm string (keyed on
Realm) and a dictionary containing username/password pairs (keyed on
Users).
eg.
WebServerAccess = {
"" = {
Realm = "general";
Users = {
Fred = 1942;
};
};
};
- (NSString*)
address;
Return the address the receiver listens for
connections on, or nil
if it is
not listening.
- (NSTimeInterval)
blockOnAuthenticationFailure;
If greater than zero, the returned value is the number
of seconds for which the server should block subsequent
requests from the offending address, otherwise
(returned value is zero) bocking is not performed
when an authentication attem,pt fails.
Blocked
requests will get a 429 response.
- (void)
closeConnectionAfter: (
WebServerResponse*)response;
Instructs the server that the connection handlind
the current request should be closed once the
response has been sent back to the client.
- (void)
completedWithResponse: (
WebServerResponse*)response;
This may only be called in the case where a call to
the delegate's
[<WebServerDelegate>-processRequest:response:for:]
method to process a request returned NO
, indicating that the delegate would handle the request asynchronously and complete it later.
In such a case, the thread handling the request in the
delegate must call this method upon
completion (passing in the same request
parameter that was passed to the delegate) to
inform the WebServer instance that processing of
the request has been completed and that it should now
take over the job of sending the response
to the client process.
If the
-streamData:withResponse:
method has been called with the supplied
response object, calling this method
terminated the streamed response to
the client.
- (NSArray*)
connections;
Returns an array containing an object representing
each connection currently active for this server
instance.
- (NSUInteger)
decodeURLEncodedForm: (NSData*)data
into: (NSMutableDictionary*)dict;
Decode an application/x-www-form-urlencoded form and
store its contents into the supplied dictionary.
The resulting dictionary keys are strings.
The resulting dictionary values are arrays of
NSData objects.
You probably don't need to
call this method yourself... more likely you will use
the
-parameters:
method instead.
NB. For forms POST-ed using
multipart/form-data
you don't need to
perform any explicit decoding as this will already
have been done for you and the decoded form will be
presented as the request GSMimeDocument subclass.
The fields of the form will be the component parts of
the content of the request and can be accessed using
the standard GSMimeDocument methods.
This method
returns the number of fields actually decoded.
- (id)
delegate;
Return this web server's delegate.
- (NSUInteger)
encodeURLEncodedForm: (NSDictionary*)dict
charset: (NSString*)charset
into: (NSMutableData*)data;
Encode an application/x-www-form-urlencoded form and
store its representation in the supplied
data object.
The dictionary
contains the form, with keys as data
objects or strings, and values as arrays of values
to be placed in the data. Each value in the
array may be a data object or a string.
As a special case, a value may be a
data object or a string rather than an
array... this is treated like an array of one value.
All non data keys and values are
converted to data using the specified
charset (or utf-8 if charset is
nil/unrecognized or where the key/value
cannot be represented using the specified
charset).
This method returns the
number of values actually encoded.
- (NSUInteger)
encodeURLEncodedForm: (NSDictionary*)dict
into: (NSMutableData*)data;
- (NSString*)
escapeHTML: (NSString*)str;
Escapes special characters in str for
use in an HTML page.
This converts & to
& for instance, and replaces non-ascii
characters with the appropriate numeric entity
references.
- (NSData*)
incrementalDataForRequest: (
WebServerRequest*)request;
Returns a data object containing any data read for
the body of a partially read request since
the last call for the same request.
- (id)
init;
Initialises the receiver to run on the
processes main thread (as returned by
[NSThread +mainThread]
.
- (id)
initForThread: (NSThread*)aThread;
This is a designated initialiser for the class.
Initialises the WebServer instance to operate
using the specified thread as the 'master' thread. If
aThread is nil
,
[NSThread +mainThread]
is used as the master thread for the newly initialised
instance.
If the current thread is not the
same as the specified master thread, this method will
not return until the master thread's run loop had run
to handle the initialisation.
- (BOOL)
isCompletedRequest: (
WebServerRequest*)request;
Returns YES
if the request
has been completely read, NO
if it still
needs more data to be read from the client and parsed
before it is complete (ie incremental parsing is in
progress).
- (BOOL)
isSecure;
Returns YES
if the server is for HTTPS
(encrypted connections), NO
otherwise.
- (BOOL)
isTrusted;
Returns YES
if the server is running
behind a secure proxy inside a demilitarised zone
(DMZ).
- (NSData*)
parameter: (NSString*)name
at: (NSUInteger)index
from: (NSDictionary*)params;
Returns the index'th data parameter for the
specified name.
Matching of
names is case-insensitive
If there are no data
items for the name, or if the
index is too large for the number of items
which exist, this returns nil
.
- (NSData*)
parameter: (NSString*)name
from: (NSDictionary*)params;
- (NSString*)
parameterString: (NSString*)name
at: (NSUInteger)index
from: (NSDictionary*)params;
- (NSString*)
parameterString: (NSString*)name
at: (NSUInteger)index
from: (NSDictionary*)params
charset: (NSString*)charset;
Calls
-parameter:at:from:
and, if the result is non-nil converts the data to a
string using the specified mime characterset, (if
charset is
nil
, UTF-8 is
used).
- (NSString*)
parameterString: (NSString*)name
from: (NSDictionary*)params;
- (NSString*)
parameterString: (NSString*)name
from: (NSDictionary*)params
charset: (NSString*)charset;
- (NSMutableDictionary*)
parameters: (
WebServerRequest*)request;
Extracts request parameters from the
HTTP query string and from the request body
(if it was application/x-www-form-urlencoded or
multipart/form-data) and return the
extracted parameters as a mutable dictionary
whose keys are the parameter names and whose values
are arrays containing the data for each parameter.
You should call this no more than once per
request, storing the result and using it
as an argument to the methods used to extract particular
parameters.
Parameters from the
request data are added to any
found in the query string.
Values provided as
multipart/form-data
are also available
in a more flexible format (see
GSMimeDocument
) as the content of the request.
- (NSString*)
port;
Return the port the receiver listens for connections
on, or nil
if it is not listening.
- (BOOL)
produceResponse: (
WebServerResponse*)aResponse
fromStaticPage: (NSString*)aPath
using: (NSDictionary*)map;
Loads a template file from disk and places it in
aResponse as content whose mime type is
determined from the file extension using the
provided mapping (or a simple built-in default
mapping if map is nil
).
Text responses use utf-8 enmcoding.
If
you have a dedicated web server for handling static
pages (eg images) it is better to use that rather
than vending static pages using this method. It's
unlikely that this method can be as efficient as a
dedicated server. However this mechanism is
adequate for moderate throughputs.
- (BOOL)
produceResponse: (
WebServerResponse*)aResponse
fromTemplate: (NSString*)aPath
using: (NSDictionary*)map;
Loads a template file from disk and places it in
aResponse as content of type 'text/html'
with a charset of 'utf-8'.
The argument
aPath is a path relative to the root path
set using the
-setRoot:
method.
Substitutes values into the template
from
map using the
-substituteFrom:using:into:depth:
method.
Returns
NO
if the
template could not be read or if any substitution
failed. In this case no value is set in the
response.
If the response is actually text
of another type, or you want another characterset used,
you can change the content type header in the request
after you call this method.
Note that,
although the
map is nominally an
NSDictionary instance, it can in fact be any
object which responds to the
[NSDictionary -objectForKey:]
message by returning a string or
nil
.
- (BOOL)
setAddress: (NSString*)anAddress
port: (NSString*)aPort
secure: (NSDictionary*)secure;
Sets the listenng address, port and security
information for the receiver... without this
the receiver will not listen for incoming requests.
If anAddress is nil
or empty, the receiver will listen on all available
network interfaces.
If secure is
nil
then the receiver listens on
aPort for HTTP requests.
If
secure is a dictionary, it must either
contain Proxy
with the value set to
YES
(to configure the receiver to
accept HTTP connections but treat them as coming via
a secure proxy), or it must contain
CertificateFile
, KeyFile
and Password
to configure the server to
use the specified certificate and key files (which it
will access using the password) to support HTTPS
rather than HTTP. Alternatively both may be
specified (if the connections are coming from a
secure proxy and the connection between
the proxy and the server is also secure.
If the dictionary also contains
HSTS
then this must be a non-negative
integer value specifying the number of seconds to
set in the Strict-Transport-Security header (defaults
to 1 year).
The secure
dictionary may also contain other dictionaries
keyed on IP addresses, and if the address that an
incoming connection arrived on matches the key of
a dictionary, that dictionary is used to provide the
certificate information, with the top-level
values being used as a fallback.
This method
returns YES
on success,
NO
on failure... if it returns
NO
then the receiver will not
be capable of handling incoming web requests!
Typically a failure will be due to an invalid
address or port being specified... a port may not
already be in use and may not be in the range up to
1024 (unless running as the super-user).
Call
this with a nil/empty port argument to shut the server
down as soon as all current connections are closed
(and refuse new incoming connections).
NB.
Changing of this configuration must only occur in
the master thread so this method, if called from
another thread, will need to perform some internal
operations in the master thread before it
returns.
- (void)
setBlockOnAuthenticationFailure: (NSTimeInterval)ti;
Sets the time for which requests from the same host
should be blocked if a request from the host
attempts to authenticate and fails.
The
default is 1 second but setting a value of zero or
less turns this feature off (sets the blocking
interval to zero).
The -[WebServerResponse
block:] method may be used to set a different
timeout in response to a particular request.
- (void)
setConnectionTimeout: (NSTimeInterval)aDelay;
Sets the time after which an idle connection should be
shut down.
Default is 30.0
- (void)
setDelegate: (id)anObject;
Sets the delegate object which processes requests for
the receiver.
- (void)
setDurationLogging: (BOOL)aFlag;
Sets a flag to determine whether logging of request
and connection durations is to be performed.
If
this is YES
then the duration of requests
and connections will be logged using the
[<WebServerDelegate>-webLog:for:]
method.
The request duration is calculated from the point where the first byte of data in the request is read to the point where the response has been completely written.
This is useful for debugging and where a full audit trail is required.
- (void)
setFoldHeaders: (BOOL)aFlag;
Sets a flag to determine whether the header lines in
responses are folded if they are over 78
characters (off by default).
Some buggy
clients don't support folding, but do accept
long header lines, and this
compatibility setting may be used to allow
such clients to handle the server's responses (though
this may of course break things for other clients).
This setting applies to any connection
established after the setting is changed.
Because use of this setting could result in a
faulty response (one with a
long
header) being sent to a client which correctly
handles folded headers, it's also controllable
individually for each response, so the same
process can respond both to clients which expect
folded headers and clients which expect
long headers (see
[WebServerResponse -setFoldHeaders:]
).
- (void)
setIOThreads: (NSUInteger)threads
andPool: (NSInteger)poolSize;
Sets the number of threads used to process
basic I/O and the size of the thread pool used by the
receiver for handling parsing of incoming
requests, generation of outgoing responses, and
pre/post processing of requests by the delegate.
This defaults to no use of threads
.
NB. Since each thread typically uses two file
descriptors to handle any inter-thread message
dispatch, enabling threading will use at least
two extra file descriptors per thread... this may
easily cause you to go beyound the per-process limit
imposed by the operating system and you may wish to
configure a smaller connection limit or tune the
O/S to allow more descriptors.
- (void)
setLogRawIO: (BOOL)aFlag;
Sets a flag to determine whether I/O logging is to be
performed.
If this is YES
then all incoming requests and their responses will be
logged using the
[<WebServerDelegate>-webLog:for:]
method.
- (void)
setMaxBodySize: (NSUInteger)max;
Sets the maximum size of an uploaded request body.
The default is 4M bytes.
The HTTP
failure response for too large a body is 413.
- (void)
setMaxConnectionDuration: (NSTimeInterval)max;
Sets the maximum total duration of the incoming
requests handled on an individual connection.
After this many requests are handled, the connection
is closed (so another client may get a chance to
connect).
The default is 10.0 seconds.
- (void)
setMaxConnectionRequests: (NSUInteger)max;
Sets the maximum size number of incoming requests to
be handled on an individual connection. After this many
requests are handled, the connection is closed (so
another client may get a chance to connect).
The default is 100 requests.
- (void)
setMaxConnections: (NSUInteger)max;
Sets the maximum number of simultaneous connections
with clients.
The default is 128.
A
value of zero permits unlimited connections.
If this limit is reached, the behavior of the software
depends upon the value set by the
-setMaxConnectionsReject:
method.
- (void)
setMaxConnectionsPerHost: (NSUInteger)max;
Sets the maximum number of simultaneous connections
with a particular remote host.
The default is
32.
A value of zero permits unlimited
connections.
If this value is greater
than that of
-setMaxConnections:
then it will have no effect as the maximum number of
connections from one host cannot be reached.
The HTTP failure response for too many
connections from a host is 503.
- (void)
setMaxConnectionsReject: (BOOL)reject;
This setting (default value NO
)
determines the behavior of the software when
the number of simultaneous incoming connections
exceeds the value set by the
-setMaxConnections:
method.
If reject is NO
, the software
will simply not accept the incoming connections
until some earlier connection is terminated, so the
incoming connections will be queued by the
operating system and may time-out if no
connections become free quickly enough for
them to be handled. In the case of a huge number of
incoming connections the 'listen' queue of the
operating system may fill up and connections
may be lost altogether.
If reject is yes, then the service will set
aside a slot for one extra connection and, when the
number of permitted connections is exceeded, the
server will accept the first additional
connection, send back an HTTP 503 response,
and drop the additional connection again. This means
that clients should receive a 503 response rather
than finding that their connection attempts block
and possible time out.
- (void)
setMaxKeepalives: (NSUInteger)max;
Sets the maximum number of connections in each I/O
thread which are to be kept in a 'keepalive' state
waiting for a new request once a request completes.
The permitted range is currently from 0 to
1000, with settings being limited to that range. The
default value is 0, which means that the number of
idle connections per thread is unlimited (though the
total number of connections and number per host is
still constrained).
- (void)
setMaxRequestSize: (NSUInteger)max;
Sets the maximum size of an incoming request
(including all headers, but not the body).
The default is 8K bytes.
The HTTP
failure response for too large a request is 413.
- (void)
setPermittedMethods: (NSSet*)s;
Sets the HTTP methods which may be used by the server.
Any incoming request using a method not
listed in the permitted set is rejected with an HTTP
405 response and an Allow header saying which methods
ARE allowed.
The default set contains only the
GET and POST methods.
- (BOOL)
setPort: (NSString*)aPort
secure: (NSDictionary*)secure;
- (void)
setRoot: (NSString*)aPath;
Set root path for loading template files from.
Templates may only be loaded from within this
directory.
- (void)
setSecureProxy: (BOOL)aFlag;
Configures a flag to say whether the receiver is
running behind a secure proxy (in a DMZ) and all
connections are to be considered as having come
in via https.
If this is not set, requests are
not trusted and some headers may be deleted from them.
- (void)
setStrictTransportSecurity: (NSUInteger)seconds;
Specifies the number of seconds HSTS
is to be turned on for when responding to a request on a
secure connection (including via a secure proxy).
The Strict-Transport-Security header is
automatically set in the response to any
incoming request (but code handling the request
may alter that).
The default setting is 1 year
(31536000 seconds), while a setting of
zero turns off HSTS.
- (void)
setSubstitutionLimit: (NSUInteger)depth;
Sets the maximum recursion depth allowed
for substitutions into templates. This defaults to 4.
- (void)
setUserInfo: (NSObject*)info
forRequest: (
WebServerRequest*)request;
Stores additional user information with a
request.
This information may be
retrieved later using the
-userInfoForRequest:
method.
- (void)
setVerbose: (BOOL)aFlag;
Sets a flag to determine whether verbose logging is to
be performed.
If this is
YES
then
all incoming requests and their responses will be
logged using the
[<WebServerDelegate>-webLog:for:]
method.
Setting this to
YES
automatically sets duration logging to
YES
as well, though you can then call
-setDurationLogging:
to set it back to
NO
.
This is useful for debugging and where a full audit trail is required.
- (BOOL)
streamData: (NSData*)data
withResponse: (
WebServerResponse*)response;
This may only be called in the case where a call to
the delegate's
[<WebServerDelegate>-processRequest:response:for:]
method to process a request returned NO
, indicating that the delegate would handle the request asynchronously and complete it later.
In this case the response content should be
empty, and instead of sending the
response in one go the server will send
the response header followed by the
supplied data. Subsequent calls to
this method using the same response
object will send more data to the
client.
The code which calls this method
must terminate the sequence of calls with a
call to the
-completedWithResponse:
method.
The method returns YES
is the
data is scheduled for sending to the
client, NO
if the client has already
dropped the connection and there is no point
attempting to stream more data.
- (NSUInteger)
strictTransportSecurity;
Returns the number of seconds set for HSTS for this
server.
This will be zero if the server is
not using a secure connection or if HSTS has been
disabled by the
-setStrictTransportSecurity:
method.
- (BOOL)
substituteFrom: (NSString*)aTemplate
using: (NSDictionary*)map
into: (NSMutableString*)result
depth: (NSUInteger)depth;
Perform substitutions replacing the markup in
aTemplate with the values supplied by
map and appending the results to the
result.
Substitutions are
recursive, and the
depth argument is
used to specify the current recursion
depth
(you should normally call this method with a
depth of zero at the start of processing a
template).
Any value inside SGML comment
delimiters ('<!--' and '-->') is treated
as a possible key in
map and the entire
comment is replaced by the corresponding
map value (unless it is
nil
).
Recursive substitution is done unless the mapped
value
starts with an SGML comment.
While the
map is nominally a dictionary,
in fact it may be any object which responds to the
objectForKey: method by returning an NSString
or
nil
, you can therefore use it to
dynamically replace tokens within a template
page in an intelligent manner.
The method
returns
YES
on success,
NO
on failure (
depth too
great).
You don't normally need to use this
method directly... call the
-produceResponse:fromTemplate:using:
method instead.
- (GSThreadPool*)
threadPool;
Returns the thread pool used by this instance.
- Declared in:
- WebServer.h
Do not attempt to subclass the WebServerRequest class to
add instance variables... the public interface is
intended to keep your compiler happy, but does not
guarantee that the instance variable layout is
actually what it seems.
- (NSString*)
address;
Convenience method returning the address of the
client.
This is taken from the
x-forwarded-for header if possible, but
from the x-remote-address header if the request was
not forwarded through a proxy.
- Declared in:
- WebServer.h
Do not attempt to subclass the WebServerResponse class to
add instance variables... the public interface is
intended to keep your compiler happy, but does not
guarantee that the instance variable layout is
actually what it seems.
- (void)
block: (NSTimeInterval)ti;
Blocks (for the time interval specified) further
incoming requests from the same source as the one
we are responding to.
A ti value more
than zero establishes a new blocking.
A
ti value of zero cancels any existing
blocking.
A ti value of less
than zero is ignored and the value returned by the
-[WebServer blockOnAuthenticationFailure]
method is used instead.
Subsequent requests
from the blocked source will be responded to with a
429 status code until the blocking expires.
- (void)
setFoldHeaders: (BOOL)aFlag;
- (void)
setUserInfo: (NSObject*)info;
Sets additional information attached to the response
which may then be retrieved with the
-userInfo
method.
- (NSObject*)
userInfo;
Returns the obect previously set with the
-setUserInfo:
method or
nil
if nothing has been set.
- Declared in:
- WebServer.h
This is an informal protocol documenting optional
methods which will be used if implemented by the
delegate.
- (void)
completedResponse: (
WebServerResponse*)response
duration: (NSTimeInterval)timeInterval;
Informs the handler (if any) associated with the
response that the server has written the
response to the network. The
timeInterval is measured between the point
when the server started reading the request and the
point at which it finished writing the
response.
- (uint32_t)
incrementalRequest: (
WebServerRequest*)request
for: (
WebServer*)http;
If your delegate implements this method, it will be
called before the first call to handle a
request (ie before
-preProcessRequest:response:for:
or -processRequest:response:for:) to provide the
delegate with the
request header
information and allow it to decide whether the
request body should be processed
incrementally (return value is non-zero) or
not (return value is zero). The returned value is
treated as a guide to how much
request
data should be buffered at a time.
This method
is called
before any HTTP basic authentication
is done, and may (if threading is turned on) be called
from a thread other than the master one.
If
your delegate turns on incremental parsing for a
request, then any time that more incoming
data is read, the web server class will look at how
much data it has and decide (based on the return value
from this method) to call your
-processRequest:response:for:
method (preceded by
-preProcessRequest:response:for:
if it is implemented) so that you can handle the new
request data.
Your code can check
to see if the
request is complete by using
the
-isCompletedRequest:
method, and can check for the latest data added to
the
request body using the *
-incrementalDataForRequest:
method.
- (void)
postProcessRequest: (
WebServerRequest*)request
response: (
WebServerResponse*)response
for: (
WebServer*)http;
If your delegate implements this method, it will be
called by the
-completedWithResponse:
method before the
response data is
actually written to the client.
This method
may re-write the
response, changing the
result of the earlier methods.
You may use
the
[WebServer -userInfoForRequest:]
method to obtain any information passed from an earlier stage of processing.
NB. if threading is turned on this method may be called from a thread other than the master one.
- (void)
webAlert: (NSString*)message
for: (
WebServer*)http;
Log an error or warning... if the delegate does not
implement this method, the message is
logged to stderr using the NSLog function.
- (void)
webAudit: (NSString*)message
for: (
WebServer*)http;
Log an audit record... if the delegate does not
implement this method, the
message is
logged to stderr.
The logged record is
similar to the Apache common log format, though it
differs after the timestamp:
- ip address
-
the address of the client host making the request
- ident
-
not currently implemented... '-' as placeholder
- user
-
the remote user name from the authorization header,
or '-'
- timestamp
-
the date/time enclosed in square brackets
- command
-
The command sent in the request... as a quoted
string
- agent
-
The user-agent header from the request... as a
quoted string
- result
-
The initial response line... as a quoted string
- (void)
webLog: (NSString*)message
for: (
WebServer*)http;
Log a debug... if the delegate does not implement this
method, no logging is done.
- Declared in:
- WebServer.h
This protocol is implemented by a delegate of a
WebServer instance in order to allow the delegate
to process requests which arrive at the server.
- (BOOL)
processRequest: (
WebServerRequest*)request
response: (
WebServerResponse*)response
for: (
WebServer*)http;
Process the HTTP
request whose headers
and data are provided in a GSMimeDocument subclass.
Extra headers are created as follows -
- x-http-method
-
The method from the HTTP request (eg.
GET or POST)
- x-http-path
-
The path from the HTTP request, or an
empty string if there was no path.
- x-http-query
-
The query string from the HTTP request
or an empty string if there was no query.
- x-http-scheme
-
Returns the URL scheme used (http or
https) to access the server. This is https if
the request arrived on an encrypted
connection or if the server is configured as
being behind a secure proxy.
- x-http-version
-
The version from the HTTP request.
- x-local-address
-
The IP address of the local host receiving the
request.
- x-local-port
-
The port of the local host receiving the
request.
- x-remote-address
-
The IP address of the host that the
request came from.
- x-remote-port
-
The port of the host that the request
came from.
- x-http-username
-
The username from the 'authorization' header if the
request supplied HTTP basic
authentication.
- x-http-password
-
The password from the 'authorization' header if the
request supplied HTTP basic
authentication.
- x-cert-issuer
-
The certificate issuer (RFC4514) if the
request connection was authenticated
with a TLS/SSL certificate or if a secure proxy is
in use and the proxy set this header. NB the header
from a secure proxy takes precedence.
- x-cert-owner
-
The certificate subject/owner (RFC4514) if the
request connection was authenticated
with a TLS/SSL certificate or if a secure proxy is
in use and the proxy set this header. NB the header
from a secure proxy takes precedence.
- x-cert-owner-proxy
-
Used if the proxy provides a certificate to
identify itself.
- x-cert-issuer-proxy
-
Used if the proxy provides a certificate to
identify itself.
- x-count-requests
-
The number of requests being processed at the point
when this request started (includes
this request).
- x-count-connections
-
The number of connections established to the
WebServer at the point when this
request started (including the
connection this request arrived
on).
- x-count-connected-hosts
-
The number of connected hosts (IP addresses) at the
point when this request started
(including the host which sent this
request).
- x-count-host-connections
-
The number of connections to the web server from
the host which sent this request at the
point when this request started
(includes the connection that this
request arrived on).
On completion, the method must modify
response (an instance of a subclass of
GSMimeDocument) to contain the data and
headers to be sent out.
The 'content-length'
header need not be set in the
response as
it will be overridden anyway.
The special 'HTTP'
header will be used as the response/status line. If
not supplied, 'HTTP/1.1 200 Success' or 'HTTP/1.1 204
No Content' will be used as the
response
line, depending on whether the data is empty or not.
If an exception is raised by this method, the
response produced will be set to 'HTTP/1.0
500 Internal Server Error' and the connection will be
closed.
If the method returns
YES
, the WebServer instance sends the
response to the client process which made
the
request.
If the method returns
NO
, the WebServer instance assumes that
the delegate is processing the
request
asynchronously, either in another thread or
with completion being triggered by an asynchronous I/O
event. The server takes no action respond to the
request until the delegate calls
[WebServer -completedWithResponse:]
to let it know that processing is complete and the
response should at last be sent out.
This method is always called in the master thread of your WebServer instance (usually the main thread of your application).