pod
web
Standard weblet APIs for processing HTTP requests
mixins
Weblet |
Weblet services a web request. |
---|
classes
Cookie |
Cookie models an HTTP cookie used to pass data between the server and user agent as defined by RFC 6265. |
---|---|
FilePack |
FilePack is an in-memory cache of multiple text files to service static resources via HTTP. |
FileWeblet |
FileWeblet is used to service an HTTP request on a |
WebClient |
The |
WebMod |
WebMod defines a web modules which is plugged into a web server's URI namespace to service web requests. |
WebOutStream |
WebOutStream provides methods for generating XML and XHTML content. |
WebReq |
WebReq encapsulates a web request. |
WebRes |
WebRes encapsulates a response to a web request. |
WebSession |
WebSession provides a name/value map associated with a specific browser "connection" to the web server. |
WebSocket |
WebSocket is used for both client and server web socket messaging. |
WebUtil |
WebUtil encapsulates several useful utility web methods. |
docs
Overview
The web pod defines the standard APIs used to handle both client and server side HTTP requests.
Client side HTTP requests:
WebClient
: manages client side of the HTTP protocol
Server side web APIs are organized into the primary classes:
WebReq
: models an incoming web request such as the method, uri, request headers, and input stream.WebRes
: models the outgoing web response such as the status code, response headers, and output stream.Weblet
: an entity which processes a web request.WebMod
: a web module which may be composed with other modules to build up a web solution.
WebClient
The WebClient
class is used to manage client side HTTP requests and responses. The basic lifecycle of WebClient:
- configure request fields such as
reqUri
,reqMethod
, andreqHeaders
- send request headers via
writeReq
- optionally write request body via
reqOut
- read response status and headers via
readRes
- process response fields such as
resCode
andresHeaders
- optionally read response body via
resIn
Using the low level methods writeReq
and readRes
enables HTTP pipelining (multiple requests and responses on the same TCP socket connection). There are also a series of convenience methods which make common cases easier.
See examples for sample code.
Weblets
Pretty much anything that touches a HTTP request should be implement Weblet
. The lifecycle of a Weblet is quite simple:
- all web requests are guaranteed to be called on their own actor/thread with the actor locals "web.req" and "web.res"
req
andres
: the current actor'sWebReq
andWebRes
are available with these methods - so there no need to pass the request and response aroundonService
: theonService
method can be overridden directly to handle the request, or the default implementation will route to thedoGet
,doPost
, etc methods
WebReq
The WebReq
class models the request side of a HTTP request. Common methods you will use include:
method
: HTTP method such as "GET" or "POST"uri
: the request URI parsed into aUri
which allows you access the parsed path and query segments.mod
: web module currently responsible for requestmodBase
: URI used to route to current modulemodRel
: module relative URI used for module internal processingheaders
: a case insensitiveStr:Str
map of the request HTTP headersin
: access to the raw input stream of the requestform
: access to the parsed form datacookies
: aStr:Str
map of cookiessession
: aStr:Obj
map used to stash stuff for the browser "connection" between HTTP requestsstash
: aStr:Obj
map used to stash stuff only for the life of request
WebRes
The WebRes
class models the response side of a HTTP request. A WebRes
has the following lifecycle:
- Uncommitted: at this point nothing has been written back on the TCP socket and
statusCode
,headers
, andcookies
are still configurable - Committed: at this point the HTTP response headers have been written, and you can write the response content via the out stream. Once a response is committed, attempts to access
statusCode
,headers
,cookies
,redirect
, orsendErr
will raise an exception - Done: at this point the response is complete - for example once the
redirect
orsendErr
method is called, the response is done
Common methods you will use include:
statusCode
: sets the HTTP status code - must be set before commitheaders
: aStr:Str
map of HTTP headers - must be set before commitcookies
: used to set the cookie header - must be set before commitout
: the output stream for writing the content - first call commits the responseisCommitted
: check commit stateisDone
: check done statesendErr
: used to send an error status coderedirect
: used to send a redirect status code
WebRes is a fairly low level API which requires the commit state model to avoid buffering the content.
WebSessions
The WebSession
class models the client session which allows you to persist state between HTTP requests. WebSessions in Fantom are cookie based using the cookie name "fanws". The default session implementation stores sessions in memory for up to 24 hours, then clears them from the cache - session state is not persisted between VM restarts.
WebSession provides a Str:Obj?
map to store arbitrary name/value pairs. You can use the map
, get
, or set
methods to manage session state. You can use delete
to explicitly delete the session cookie and server side state. The values stored in a WebSession should always be serializable objects.
WebSessions are created and accessed via the WebReq.session
method. The first time a session is accessed it sets the cookie header in the response - therefore sessions should always be accessed before the response is committed. Deleting a session also requires setting the cookie header and must done before the response is committed.
Example of storing a counter in a session:
override Void doGet() { Int count := req.session.get("counter", 0) req.session["counter"] = count + 1 res.headers["Content-Type"] = "text/plain" res.statusCode = 200 res.out.printLine("session counter=$count") }
WebMods
The WebMod
class is the base class for plugging in web server modules. WebMods are immutable Weblets which may be composed together to build higher level modules or to configure the entire web server.
During processing of a given web request, there is always exactly one WebMod responsible for the request which is available via the WebReq.mod
method. The URI used to route to the module is accessed by WebReq.modBase
, and the remainder of the URI which is internal to the module via WebReq.modRel
. Using these methods you can write modules which can be freely plugged anywhere into a server's URI namespace.
WebMods receive the onStart
and onStop
callbacks when the web server is started and stopped. These callbacks can be used to perform initialization and cleanup such as managing actors.
The webmod
pod includes a library of modules which are designed to handle common tasks such publishing static files, routing, and pipelining.
Expect Continue
Using "Expect: 100-continue" allows the server to fail-fast and report an error to the client before the client sends the request body. This technique is often used before posting large files to verify preconditions.
The WebClient
API does not provide automatic support for using the Expect header. You must manually handle flow control yourself. Here is a simple example showing how to post a file using the Expect header:
c := WebClient(`http://example.com/post-file`) c.reqMethod = "POST" c.reqHeaders["Content-Type"] = file.mimeType.toStr c.reqHeaders["Content-Length"] = file.size.toStr c.reqHeaders["Expect"] = "100-continue" c.writeReq c.readRes if (c.resCode != 100) throw IOErr("Expecting 100, not $c.resCode") file.in.pipe(c.reqOut, file.size) c.reqOut.close c.readRes if (c.resCode != 200) throw IOErr("Expecting 200, not $c.resCode")
Server side processing of the Expect header is automatic. When a Weblet acquires the WebReq.in
stream for the first time, the request is checked for the "Expect: 100-continue" header and if specified, then a 100 Continue is automatically sent.