DoxigAlpha

respondStreaming

The header is not guaranteed to be sent until BodyWriter.flush or BodyWriter.end 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 the BodyWriter.elide flag on the returned BodyWriter, causing the response stream 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 status is not continue.

Function parameters

Parameters

#
request:*Request
buffer:[]u8

Type definitions in this namespace

Types

#
WebSocket
See https://tools.ietf.org/html/rfc6455

Initialize an HTTP server that can respond to multiple requests on the same

Functions

#
init
Initialize an HTTP server that can respond to multiple requests on the same

Error sets in this namespace

Error Sets

#

Source

Implementation

#
pub fn respondStreaming(
    request: *Request,
    buffer: []u8,
    options: RespondStreamingOptions,
) ExpectContinueError!http.BodyWriter {
    try writeExpectContinue(request);
    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 "";
    const out = request.server.out;

    try out.print("{s} {d} {s}\r\n", .{
        @tagName(o.version), @intFromEnum(o.status), phrase,
    });

    switch (o.version) {
        .@"HTTP/1.0" => if (keep_alive) try out.writeAll("connection: keep-alive\r\n"),
        .@"HTTP/1.1" => if (!keep_alive) try out.writeAll("connection: close\r\n"),
    }

    if (o.transfer_encoding) |transfer_encoding| switch (transfer_encoding) {
        .chunked => try out.writeAll("transfer-encoding: chunked\r\n"),
        .none => {},
    } else if (options.content_length) |len| {
        try out.print("content-length: {d}\r\n", .{len});
    } else {
        try out.writeAll("transfer-encoding: chunked\r\n");
    }

    for (o.extra_headers) |header| {
        assert(header.name.len != 0);
        var bufs: [4][]const u8 = .{ header.name, ": ", header.value, "\r\n" };
        try out.writeVecAll(&bufs);
    }

    try out.writeAll("\r\n");
    const elide_body = request.head.method == .HEAD;
    const state: http.BodyWriter.State = if (o.transfer_encoding) |te| switch (te) {
        .chunked => .init_chunked,
        .none => .none,
    } else if (options.content_length) |len| .{
        .content_length = len,
    } else .init_chunked;

    return if (elide_body) .{
        .http_protocol_output = request.server.out,
        .state = state,
        .writer = .{
            .buffer = buffer,
            .vtable = &.{
                .drain = http.BodyWriter.elidingDrain,
                .sendFile = http.BodyWriter.elidingSendFile,
            },
        },
    } else .{
        .http_protocol_output = request.server.out,
        .state = state,
        .writer = .{
            .buffer = buffer,
            .vtable = switch (state) {
                .none => &.{
                    .drain = http.BodyWriter.noneDrain,
                    .sendFile = http.BodyWriter.noneSendFile,
                },
                .content_length => &.{
                    .drain = http.BodyWriter.contentLengthDrain,
                    .sendFile = http.BodyWriter.contentLengthSendFile,
                },
                .chunk_len => &.{
                    .drain = http.BodyWriter.chunkedDrain,
                    .sendFile = http.BodyWriter.chunkedSendFile,
                },
                .end => unreachable,
            },
        },
    };
}