mirror of
https://github.com/ziglang/zig.git
synced 2026-02-13 12:59:04 +00:00
std.http: assert against \r\n in headers
The HTTP specification does not provide a way to escape \r\n in headers, so it's the API user's responsibility to ensure the header names and values do not contain \r\n. Also header names must not contain ':'. It's an assertion, not an error, because the calling code very likely is using hard-coded values or server-provided values that do not need to be checked, and the error would be unreachable anyway. Untrusted user input must not be put directly into into HTTP headers.
This commit is contained in:
parent
d051b13963
commit
10beb19ce7
@ -1505,12 +1505,26 @@ pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{
|
||||
///
|
||||
/// The caller is responsible for calling `deinit()` on the `Request`.
|
||||
/// This function is threadsafe.
|
||||
///
|
||||
/// Asserts that "\r\n" does not occur in any header name or value.
|
||||
pub fn open(
|
||||
client: *Client,
|
||||
method: http.Method,
|
||||
uri: Uri,
|
||||
options: RequestOptions,
|
||||
) RequestError!Request {
|
||||
if (std.debug.runtime_safety) {
|
||||
for (options.extra_headers) |header| {
|
||||
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);
|
||||
}
|
||||
for (options.privileged_headers) |header| {
|
||||
assert(std.mem.indexOfPosLinear(u8, header.name, 0, "\r\n") == null);
|
||||
assert(std.mem.indexOfPosLinear(u8, header.value, 0, "\r\n") == null);
|
||||
}
|
||||
}
|
||||
|
||||
const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme;
|
||||
|
||||
const port: u16 = uri.port orelse switch (protocol) {
|
||||
|
||||
@ -296,6 +296,7 @@ pub const Request = struct {
|
||||
///
|
||||
/// Asserts status is not `continue`.
|
||||
/// Asserts there are at most 25 extra_headers.
|
||||
/// Asserts that "\r\n" does not occur in any header name or value.
|
||||
pub fn respond(
|
||||
request: *Request,
|
||||
content: []const u8,
|
||||
@ -304,6 +305,13 @@ pub const Request = struct {
|
||||
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(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;
|
||||
@ -765,7 +773,7 @@ pub const Response = struct {
|
||||
/// Respects the value of `elide_body` to omit all data after the headers.
|
||||
/// Asserts there are at most 25 trailers.
|
||||
pub fn endChunked(r: *Response, options: EndChunkedOptions) WriteError!void {
|
||||
assert(r.content_length == null);
|
||||
assert(r.transfer_encoding == .chunked);
|
||||
try flush_chunked(r, options.trailers);
|
||||
r.* = undefined;
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user