Function respond [src]
Prototype
pub fn respond( request: *Request, content: []const u8, options: RespondOptions, ) Response.WriteError!void
Parameters
request: *Request
content: []const u8
options: RespondOptions
Possible Errors
File descriptor does not hold the required rights to write to it.
Connection reset by peer.
The process cannot access the file because another process has locked a portion of the file. Windows-only.
The socket type requires that message be sent atomically, and the size of the message to be sent made this impossible. The message is not transmitted.
This error occurs when a device gets disconnected before or mid-flush while it's being written to - errno(6): No such device or address.
This error occurs in Linux if the process being written to no longer exists.
The Operating System returned an undocumented error code.
This error is in theory not possible, but it would be better to handle this error than to invoke undefined behavior.
When this error code is observed, it usually means the Zig Standard Library needs a small patch to add the error code to the error set for the respective function.
This error occurs when no global event loop is configured, and reading from the file descriptor would block.
Source
pub fn respond(
request: *Request,
content: []const u8,
options: RespondOptions,
) Response.WriteError!void {
const max_extra_headers = 25;
assert(options.status != .@"continue");
assert(options.extra_headers.len <= max_extra_headers);
if (std.debug.runtime_safety) {
for (options.extra_headers) |header| {
assert(header.name.len != 0);
assert(std.mem.indexOfScalar(u8, header.name, ':') == null);
assert(std.mem.indexOfPosLinear(u8, header.name, 0, "\r\n") == null);
assert(std.mem.indexOfPosLinear(u8, header.value, 0, "\r\n") == null);
}
}
const transfer_encoding_none = (options.transfer_encoding orelse .chunked) == .none;
const server_keep_alive = !transfer_encoding_none and options.keep_alive;
const keep_alive = request.discardBody(server_keep_alive);
const phrase = options.reason orelse options.status.phrase() orelse "";
var first_buffer: [500]u8 = undefined;
var h = std.ArrayListUnmanaged(u8).initBuffer(&first_buffer);
if (request.head.expect != null) {
// 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");
try request.server.connection.stream.writeAll(h.items);
return;
}
h.fixedWriter().print("{s} {d} {s}\r\n", .{
@tagName(options.version), @intFromEnum(options.status), phrase,
}) catch unreachable;
switch (options.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 (options.transfer_encoding) |transfer_encoding| switch (transfer_encoding) {
.none => {},
.chunked => h.appendSliceAssumeCapacity("transfer-encoding: chunked\r\n"),
} else {
h.fixedWriter().print("content-length: {d}\r\n", .{content.len}) catch unreachable;
}
var chunk_header_buffer: [18]u8 = undefined;
var iovecs: [max_extra_headers * 4 + 3]std.posix.iovec_const = undefined;
var iovecs_len: usize = 0;
iovecs[iovecs_len] = .{
.base = h.items.ptr,
.len = h.items.len,
};
iovecs_len += 1;
for (options.extra_headers) |header| {
iovecs[iovecs_len] = .{
.base = header.name.ptr,
.len = header.name.len,
};
iovecs_len += 1;
iovecs[iovecs_len] = .{
.base = ": ",
.len = 2,
};
iovecs_len += 1;
if (header.value.len != 0) {
iovecs[iovecs_len] = .{
.base = header.value.ptr,
.len = header.value.len,
};
iovecs_len += 1;
}
iovecs[iovecs_len] = .{
.base = "\r\n",
.len = 2,
};
iovecs_len += 1;
}
iovecs[iovecs_len] = .{
.base = "\r\n",
.len = 2,
};
iovecs_len += 1;
if (request.head.method != .HEAD) {
const is_chunked = (options.transfer_encoding orelse .none) == .chunked;
if (is_chunked) {
if (content.len > 0) {
const chunk_header = std.fmt.bufPrint(
&chunk_header_buffer,
"{x}\r\n",
.{content.len},
) catch unreachable;
iovecs[iovecs_len] = .{
.base = chunk_header.ptr,
.len = chunk_header.len,
};
iovecs_len += 1;
iovecs[iovecs_len] = .{
.base = content.ptr,
.len = content.len,
};
iovecs_len += 1;
iovecs[iovecs_len] = .{
.base = "\r\n",
.len = 2,
};
iovecs_len += 1;
}
iovecs[iovecs_len] = .{
.base = "0\r\n\r\n",
.len = 5,
};
iovecs_len += 1;
} else if (content.len > 0) {
iovecs[iovecs_len] = .{
.base = content.ptr,
.len = content.len,
};
iovecs_len += 1;
}
}
try request.server.connection.stream.writevAll(iovecs[0..iovecs_len]);
}