parse
Function parameters
Parameters
- bytes:[]const u8
A Least-Recently-Used cache of open connections to be reused.
Types
- ConnectionPool
- A Least-Recently-Used cache of open connections to be reused.
Release all associated resources with the client.
Functions
- deinit
- Release all associated resources with the client.
- initDefaultProxies
- Populates `http_proxy` and `https_proxy` via standard proxy environment variables.
- connectTcp
- Reuses a `Connection` if one matching `host` and `port` is already open.
- connectUnix
- Connect to `path` as a unix domain socket.
- connectProxied
- Connect to `proxied_host:proxied_port` using the specified proxy with HTTP
- connect
- Connect to `host:port` using the specified protocol.
- request
- Open a connection to the host specified by `uri` and prepare to send a HTTP request.
- fetch
- Perform a one-shot HTTP request with the provided options.
Error sets in this namespace
Error Sets
= std.options.http_disable_tls
Values
- disable_tls
- = std.options.http_disable_tls
Source
Implementation
pub fn parse(bytes: []const u8) ParseError!Head {
var res: Head = .{
.bytes = bytes,
.status = undefined,
.reason = undefined,
.version = undefined,
.keep_alive = false,
};
var it = mem.splitSequence(u8, bytes, "\r\n");
const first_line = it.first();
if (first_line.len < 12) return error.HttpHeadersInvalid;
const version: http.Version = switch (int64(first_line[0..8])) {
int64("HTTP/1.0") => .@"HTTP/1.0",
int64("HTTP/1.1") => .@"HTTP/1.1",
else => return error.HttpHeadersInvalid,
};
if (first_line[8] != ' ') return error.HttpHeadersInvalid;
const status: http.Status = @enumFromInt(parseInt3(first_line[9..12]));
const reason = mem.trimLeft(u8, first_line[12..], " ");
res.version = version;
res.status = status;
res.reason = reason;
res.keep_alive = switch (version) {
.@"HTTP/1.0" => false,
.@"HTTP/1.1" => true,
};
while (it.next()) |line| {
if (line.len == 0) return res;
switch (line[0]) {
' ', '\t' => return error.HttpHeaderContinuationsUnsupported,
else => {},
}
var line_it = mem.splitScalar(u8, line, ':');
const header_name = line_it.next().?;
const header_value = mem.trim(u8, line_it.rest(), " \t");
if (header_name.len == 0) return error.HttpHeadersInvalid;
if (std.ascii.eqlIgnoreCase(header_name, "connection")) {
res.keep_alive = !std.ascii.eqlIgnoreCase(header_value, "close");
} else if (std.ascii.eqlIgnoreCase(header_name, "content-type")) {
res.content_type = header_value;
} else if (std.ascii.eqlIgnoreCase(header_name, "location")) {
res.location = header_value;
} else if (std.ascii.eqlIgnoreCase(header_name, "content-disposition")) {
res.content_disposition = header_value;
} else if (std.ascii.eqlIgnoreCase(header_name, "transfer-encoding")) {
// Transfer-Encoding: second, first
// Transfer-Encoding: deflate, chunked
var iter = mem.splitBackwardsScalar(u8, header_value, ',');
const first = iter.first();
const trimmed_first = mem.trim(u8, first, " ");
var next: ?[]const u8 = first;
if (std.meta.stringToEnum(http.TransferEncoding, trimmed_first)) |transfer| {
if (res.transfer_encoding != .none) return error.HttpHeadersInvalid; // we already have a transfer encoding
res.transfer_encoding = transfer;
next = iter.next();
}
if (next) |second| {
const trimmed_second = mem.trim(u8, second, " ");
if (http.ContentEncoding.fromString(trimmed_second)) |transfer| {
if (res.content_encoding != .identity) return error.HttpHeadersInvalid; // double compression is not supported
res.content_encoding = transfer;
} else {
return error.HttpTransferEncodingUnsupported;
}
}
if (iter.next()) |_| return error.HttpTransferEncodingUnsupported;
} else if (std.ascii.eqlIgnoreCase(header_name, "content-length")) {
const content_length = std.fmt.parseInt(u64, header_value, 10) catch return error.InvalidContentLength;
if (res.content_length != null and res.content_length != content_length) return error.HttpHeadersInvalid;
res.content_length = content_length;
} else if (std.ascii.eqlIgnoreCase(header_name, "content-encoding")) {
if (res.content_encoding != .identity) return error.HttpHeadersInvalid;
const trimmed = mem.trim(u8, header_value, " ");
if (http.ContentEncoding.fromString(trimmed)) |ce| {
res.content_encoding = ce;
} else {
return error.HttpContentEncodingUnsupported;
}
}
}
return error.HttpHeadersInvalid; // missing empty line
}