Response¶
Responses are representing resources requested by a user agent. They are actively streamed across the network, preferably using non-blocking asynchronous I/O.
Status¶
The response status can be set with the status property. libsoup-2.4
provides an enumeration in libsoup-2.4/Soup.Status for that purpose.
The status property will default to 200 OK.
The status code will be written in the response with write_head or
write_head_async if invoked manually. Otherwise, it is left to the
implementation to call it at a proper moment.
res.status = Soup.Status.MALFORMED;
Reason phrase¶
New in version 0.3.
The reason phrase provide a textual description for the status code. If
null, which is the default, it will be generated using
libsoup-2.4/Soup.Status.get_phrase. It is written along with the
status line if write_head or write_head_async is invoked.
res.status = Soup.Status.OK;
res.reason_phrase = "Everything Went Well"
To obtain final status line sent to the user agent, use the wrote_status_line
signal.
res.wrote_status_line.connect ((http_version, status, reason_phrase) => {
if (200 <= status < 300) {
// assuming a success
}
});
Headers¶
The response headers can be accessed as a libsoup-2.4/Soup.MessageHeaders
from the headers property.
res.headers.set_content_type ("text/plain", null);
Headers can be written in the response synchronously by invoking
write_head or asynchronously with write_head_async.
res.write_head_async.begin (Priority.DEFAULT, null, () => {
// produce the body...
});
Warning
Once written, any modification to the headers object will be ignored.
The head_written property can be tested to see if it’s already the case,
even though a well written application should assume that already.
if (!res.head_written) {
res.headers.set_content_type ("text/html", null);
}
Since headers can still be modified once written, the wrote_headers signal
can be used to obtain definitive values.
res.wrote_headers (() => {
foreach (var cookie in res.cookies) {
message (cookie.to_set_cookie_header ());
}
});
Body¶
The body of a response is accessed through the body property. It inherits
from gio-2.0/GLib.OutputStream and provides synchronous and
asynchronous streaming capabilities.
The response body is automatically closed following a RAII pattern whenever the
Response object is disposed.
Note that a reference to the body is not sufficient to maintain the inner Connection alive: a reference to either the Request or response be maintained.
You can still close the body early as it can provide multiple advantages:
- avoid further and undesired read or write operation
- indicate to the user agent that the body has been fully sent
Expand¶
New in version 0.3.
To deal with fixed-size body, expand, expand_bytes,
expand_utf8 and expand_file utilities as well as their respective
asynchronous versions are provided.
It will automatically set the Content-Length header to the size of the
provided buffer, write the response head and pipe the buffer into the body
stream and close it properly.
res.expand_utf8 ("Hello world!");
Filtering¶
One common operation related to stream is filtering. gio-2.0/GLib.FilterOutputStream and gio-2.0/GLib.ConverterOutputStream provide, by composition, many filters that can be used for:
- compression and decompression (gzip, deflate, compress, …)
- charset conversion
- buffering
- writting data
VSGI also provides its own set of Converters which cover parts of the HTTP/1.1 specifications such as chunked encoding.
var body = new ConverterOutputStream (res.body,
new CharsetConverter (res.body, "iso-8859-1", "utf-8"));
return body.write_all ("Omelette du fromâge!", null);
Additionally, some filters are applied automatically if the Transfer-Encoding
header is set. The obtained gio-2.0/GLib.OutputStream will be
wrapped appropriately so that the application can transparently produce its
output.
res.headers.append ("Transfer-Encoding", "chunked");
return res.body.write_all ("Hello world!".data, null);
Tee¶
New in version 0.3.
The response body can be splitted pretty much like how the tee UNIX utility
works. All further write operations will be performed as well on the passed
stream, making it possible to process the payload sent to the user agent.
The typical use case would be to implement a file-based cache that would tee the produced response body into a key-based storage.
var cache_key = Checksum.compute_for_string (ChecksumType.SHA256, req.uri.to_string ());
var cache_entry = File.new_for_path ("cache/%s".printf (cache_key));
if (cache_entry.query_exists ()) {
return res.body.splice (cache_entry.read ());
} else {
res.tee (cache_entry.create (FileCreateFlags.PRIVATE));
}
res.expand_utf8 ("Hello world!");
End¶
New in version 0.3.
To properly close the response, writing headers if missing, end is
provided:
res.status = Soup.Status.NO_CONTENT;
res.end ();
To produce a message before closing, favour extend utilities.