Session¶
An HTTP Session is the external API to the communication link between client and server.
Every request is executed as part of a HTTP Session. An HTTP Session lives as long as the underlying TCP connection and receives request data from it and writes response data to it.
Receiving data and parsing this data into Requests is happening on the TCPConnection actor. The Session actor is started when a new TCPConnection is accepted, and shut down, when the connection is closed.
Receiving a Request¶
As part of the Request-Response handling internal to this HTTP library, a Session is instantiated that forwards requests to a Handler, to actual application code, which in turn sends Responses back to the Session instance it was instantiated with (See HandlerFactory.
See Handler on how requests are received by application code.
Sending a Response¶
Public Behaviours¶
send_start¶
Verbose API¶
Start sending a response, submitting the Response status and headers.
Sending a response via the verbose API needs to be done in 2 or more steps:
- Session.send_start - exactly once - submit status and headers
- Session.send_chunk - 0 or more times - submit body
- Session.send_finished - exactly once - clean up resources
Parameters¶
send_chunk¶
Verbose API¶
Send a piece of body data of the request identified by request_id
.
This might be the whole body or just a piece of it.
Notify the Session that the body has been fully sent, by calling Session.send_finished
.
Parameters¶
send_finished¶
Verbose API¶
Indicate that the response for request_id
has been completed,
that is, its status, headers and body have been sent.
This will clean up resources on the session and might send pending pipelined responses in addition to this response.
If this behaviour isnt called, the server might misbehave, especially with clients doing HTTP pipelining.
Parameters¶
- request_id: USize val
send_cancel¶
Cancel sending an in-flight response.
As the Session will be invalid afterwards, as the response might not have been sent completely,
it is best to close the session afterwards using Session.dispose()
.
Parameters¶
- request_id: USize val
send_no_body¶
Simple API¶
Send a bodyless Response in one call.
This call will do all the work of sending the response and cleaning up resources.
No need to call Session.send_finished()
anymore for this request.
Parameters¶
send¶
Simple API¶
Send an Response with a body in one call.
The body must be a ByteArrays instance.
Example:
// ...
var bytes = ByteArrays
bytes = bytes + "first line" + "\n"
bytes = bytes + "second line" + "\n"
bytes = bytes + "third line"
session.send(response, bytes, request_id)
// ...
This call will do all the work of sending the response and cleaning up resources.
No need to call Session.send_finished()
anymore for this request.
Parameters¶
- response: Response val
- body: ByteArrays val
- request_id: USize val
send_raw¶
Optimized raw API¶
Send raw bytes to the Session in form of a ByteSeqIter.
These bytes may or may not include the response body.
You can use Session.send_chunk()
to send the response body piece by piece.
If the session should be closed after sending this response,
no matter the requested standard HTTP connection handling,
set close_session
to true
. To be a good HTTP citizen, include
a Connection: close
header in the raw response, to signal to the client
to also close the session.
If set to false
, then normal HTTP connection handling applies
(request Connection
header, HTTP/1.0 without Connection: keep-alive
, etc.).
To finish sending the response, it is required to call Session.send_finished()
to wrap things up, otherwise the server might misbehave.
This API uses the TCPConnection.writev method to optimize putting the given bytes out to the wire.
To make this optimized path more usable, this library provides the ResponseBuilder, which builds up a response into a ByteSeqIter, thus taylored towards being used with this API.
Example:
class MyHandler is Handler
let _session: Session
new create(session: Session) =>
_session = session
fun ref apply(request: Request val, request_id: RequestID): Any =>
let body =
match request.content_length()
| let cl: USize =>
"You've sent us " + cl.string() + " bytes! Thank you!"
| None if request.transfer_coding() is Chunked =>
"You've sent us some chunks! That's cool!"
| None =>
"Dunno how much you've sent us. Probably nothing. That's alright."
end
_session.send_raw(
Responses.builder()
.set_status(StatusOK)
.add_header("Content-Type", "text/plain; charset=UTF-8")
.add_header("Content-Length", body.size().string())
.finish_headers()
.add_chunk(body)
.build(),
request_id
)
// never forget !!!
_session.send_finished(request_id)
Parameters¶
- raw: ByteSeqIter val
- request_id: USize val
- close_session: Bool val = false
dispose¶
Close the connection from this end.
upgrade_protocol¶
Upgrade this TCP connection to another handler, serving another protocol (e.g. WebSocket).
Note that this method does not send an HTTP Response with a status of 101. This needs to be done before calling this behaviour. Also, the passed in notify
will not have its methods accepted or connected called, as the connection is already established.
After calling this behaviour, this session and the connected Handler instance will not be called again, so it is necessary to do any required clean up right after this call.
See:
Parameters¶
- notify: TCPConnectionNotify iso