Function respondStreaming [src]
The header is buffered but not sent until Response.flush is called.
If the request contains a body and the connection is to be reused,
discards the request body, leaving the Server in the ready state. If
this discarding fails, the connection is marked as not to be reused and
no error is surfaced.
HEAD requests are handled transparently by setting a flag on the
returned Response to omit the body. However it may be worth noticing
that flag and skipping any expensive work that would otherwise need to
be done to satisfy the request.
Asserts send_buffer is large enough to store the entire response header.
Asserts status is not continue.
Prototype
pub fn respondStreaming(request: *Request, options: RespondStreamingOptions) Response
Parameters
request: *Request
options: RespondStreamingOptions
Source
pub fn respondStreaming(request: *Request, options: RespondStreamingOptions) Response {
const o = options.respond_options;
assert(o.status != .@"continue");
const transfer_encoding_none = (o.transfer_encoding orelse .chunked) == .none;
const server_keep_alive = !transfer_encoding_none and o.keep_alive;
const keep_alive = request.discardBody(server_keep_alive);
const phrase = o.reason orelse o.status.phrase() orelse "";
var h = std.ArrayListUnmanaged(u8).initBuffer(options.send_buffer);
const elide_body = if (request.head.expect != null) eb: {
// reader() and hence discardBody() above sets expect to null if it
// is handled. So the fact that it is not null here means unhandled.
h.appendSliceAssumeCapacity("HTTP/1.1 417 Expectation Failed\r\n");
if (!keep_alive) h.appendSliceAssumeCapacity("connection: close\r\n");
h.appendSliceAssumeCapacity("content-length: 0\r\n\r\n");
break :eb true;
} else eb: {
h.fixedWriter().print("{s} {d} {s}\r\n", .{
@tagName(o.version), @intFromEnum(o.status), phrase,
}) catch unreachable;
switch (o.version) {
.@"HTTP/1.0" => if (keep_alive) h.appendSliceAssumeCapacity("connection: keep-alive\r\n"),
.@"HTTP/1.1" => if (!keep_alive) h.appendSliceAssumeCapacity("connection: close\r\n"),
}
if (o.transfer_encoding) |transfer_encoding| switch (transfer_encoding) {
.chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
.none => {},
} else if (options.content_length) |len| {
h.fixedWriter().print("content-length: {d}\r\n", .{len}) catch unreachable;
} else {
h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n");
}
for (o.extra_headers) |header| {
assert(header.name.len != 0);
h.appendSliceAssumeCapacity(header.name);
h.appendSliceAssumeCapacity(": ");
h.appendSliceAssumeCapacity(header.value);
h.appendSliceAssumeCapacity("\r\n");
}
h.appendSliceAssumeCapacity("\r\n");
break :eb request.head.method == .HEAD;
};
return .{
.stream = request.server.connection.stream,
.send_buffer = options.send_buffer,
.send_buffer_start = 0,
.send_buffer_end = h.items.len,
.transfer_encoding = if (o.transfer_encoding) |te| switch (te) {
.chunked => .chunked,
.none => .none,
} else if (options.content_length) |len| .{
.content_length = len,
} else .chunked,
.elide_body = elide_body,
.chunk_len = 0,
};
}