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.