mirror of
https://github.com/lightpanda-io/browser.git
synced 2025-12-16 08:18:59 +00:00
upgrade to zig 0.12.1
This commit is contained in:
@@ -133,7 +133,7 @@ pub const ConnectionPool = struct {
|
|||||||
pool.mutex.lock();
|
pool.mutex.lock();
|
||||||
defer pool.mutex.unlock();
|
defer pool.mutex.unlock();
|
||||||
|
|
||||||
const node = @fieldParentPtr(Node, "data", connection);
|
const node: *Node = @fieldParentPtr("data", connection);
|
||||||
|
|
||||||
pool.used.remove(node);
|
pool.used.remove(node);
|
||||||
|
|
||||||
@@ -796,17 +796,41 @@ pub const Request = struct {
|
|||||||
req.client.connection_pool.release(req.client.allocator, req.connection.?);
|
req.client.connection_pool.release(req.client.allocator, req.connection.?);
|
||||||
req.connection = null;
|
req.connection = null;
|
||||||
|
|
||||||
const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme;
|
var server_header = std.heap.FixedBufferAllocator.init(req.response.parser.header_bytes_buffer);
|
||||||
|
defer req.response.parser.header_bytes_buffer = server_header.buffer[server_header.end_index..];
|
||||||
|
const protocol, const valid_uri = try validateUri(uri, server_header.allocator());
|
||||||
|
|
||||||
const port: u16 = uri.port orelse switch (protocol) {
|
const new_host = valid_uri.host.?.raw;
|
||||||
.plain => 80,
|
const prev_host = req.uri.host.?.raw;
|
||||||
.tls => 443,
|
const keep_privileged_headers =
|
||||||
};
|
std.ascii.eqlIgnoreCase(valid_uri.scheme, req.uri.scheme) and
|
||||||
|
std.ascii.endsWithIgnoreCase(new_host, prev_host) and
|
||||||
|
(new_host.len == prev_host.len or new_host[new_host.len - prev_host.len - 1] == '.');
|
||||||
|
if (!keep_privileged_headers) {
|
||||||
|
// When redirecting to a different domain, strip privileged headers.
|
||||||
|
req.privileged_headers = &.{};
|
||||||
|
}
|
||||||
|
|
||||||
const host = uri.host orelse return error.UriMissingHost;
|
if (switch (req.response.status) {
|
||||||
|
.see_other => true,
|
||||||
|
.moved_permanently, .found => req.method == .POST,
|
||||||
|
else => false,
|
||||||
|
}) {
|
||||||
|
// A redirect to a GET must change the method and remove the body.
|
||||||
|
req.method = .GET;
|
||||||
|
req.transfer_encoding = .none;
|
||||||
|
req.headers.content_type = .omit;
|
||||||
|
}
|
||||||
|
|
||||||
req.uri = uri;
|
if (req.transfer_encoding != .none) {
|
||||||
req.connection = try req.client.connect(host, port, protocol);
|
// The request body has already been sent. The request is
|
||||||
|
// still in a valid state, but the redirect must be handled
|
||||||
|
// manually.
|
||||||
|
return error.RedirectRequiresResend;
|
||||||
|
}
|
||||||
|
|
||||||
|
req.uri = valid_uri;
|
||||||
|
req.connection = try req.client.connect(new_host, uriPort(valid_uri, protocol), protocol);
|
||||||
req.redirect_behavior.subtractOne();
|
req.redirect_behavior.subtractOne();
|
||||||
req.response.parser.reset();
|
req.response.parser.reset();
|
||||||
|
|
||||||
@@ -821,13 +845,8 @@ pub const Request = struct {
|
|||||||
|
|
||||||
pub const SendError = Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
|
pub const SendError = Connection.WriteError || error{ InvalidContentLength, UnsupportedTransferEncoding };
|
||||||
|
|
||||||
pub const SendOptions = struct {
|
|
||||||
/// Specifies that the uri is already escaped.
|
|
||||||
raw_uri: bool = false,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Send the HTTP request headers to the server.
|
/// Send the HTTP request headers to the server.
|
||||||
pub fn send(req: *Request, options: SendOptions) SendError!void {
|
pub fn send(req: *Request) SendError!void {
|
||||||
if (!req.method.requestHasBody() and req.transfer_encoding != .none)
|
if (!req.method.requestHasBody() and req.transfer_encoding != .none)
|
||||||
return error.UnsupportedTransferEncoding;
|
return error.UnsupportedTransferEncoding;
|
||||||
|
|
||||||
@@ -846,7 +865,6 @@ pub const Request = struct {
|
|||||||
.authority = connection.proxied,
|
.authority = connection.proxied,
|
||||||
.path = true,
|
.path = true,
|
||||||
.query = true,
|
.query = true,
|
||||||
.raw = options.raw_uri,
|
|
||||||
}, w);
|
}, w);
|
||||||
}
|
}
|
||||||
try w.writeByte(' ');
|
try w.writeByte(' ');
|
||||||
@@ -1063,55 +1081,19 @@ pub const Request = struct {
|
|||||||
const location = req.response.location orelse
|
const location = req.response.location orelse
|
||||||
return error.HttpRedirectLocationMissing;
|
return error.HttpRedirectLocationMissing;
|
||||||
|
|
||||||
// This mutates the beginning of header_buffer and uses that
|
// This mutates the beginning of header_bytes_buffer and uses that
|
||||||
// for the backing memory of the returned new_uri.
|
// for the backing memory of the returned Uri.
|
||||||
const header_buffer = req.response.parser.header_bytes_buffer;
|
try req.redirect(req.uri.resolve_inplace(
|
||||||
const new_uri = req.uri.resolve_inplace(location, header_buffer) catch
|
location,
|
||||||
return error.HttpRedirectLocationInvalid;
|
&req.response.parser.header_bytes_buffer,
|
||||||
|
) catch |err| switch (err) {
|
||||||
// The new URI references the beginning of header_bytes_buffer memory.
|
error.UnexpectedCharacter,
|
||||||
// That memory will be kept, but everything after it will be
|
error.InvalidFormat,
|
||||||
// reused by the subsequent request. In other words,
|
error.InvalidPort,
|
||||||
// header_bytes_buffer must be large enough to store all
|
=> return error.HttpRedirectLocationInvalid,
|
||||||
// redirect locations as well as the final request header.
|
error.NoSpaceLeft => return error.HttpHeadersOversize,
|
||||||
const path_end = new_uri.path.ptr + new_uri.path.len;
|
});
|
||||||
// https://github.com/ziglang/zig/issues/1738
|
try req.send();
|
||||||
const path_offset = @intFromPtr(path_end) - @intFromPtr(header_buffer.ptr);
|
|
||||||
const end_offset = @max(path_offset, location.len);
|
|
||||||
req.response.parser.header_bytes_buffer = header_buffer[end_offset..];
|
|
||||||
|
|
||||||
const is_same_domain_or_subdomain =
|
|
||||||
std.ascii.endsWithIgnoreCase(new_uri.host.?, req.uri.host.?) and
|
|
||||||
(new_uri.host.?.len == req.uri.host.?.len or
|
|
||||||
new_uri.host.?[new_uri.host.?.len - req.uri.host.?.len - 1] == '.');
|
|
||||||
|
|
||||||
if (new_uri.host == null or !is_same_domain_or_subdomain or
|
|
||||||
!std.ascii.eqlIgnoreCase(new_uri.scheme, req.uri.scheme))
|
|
||||||
{
|
|
||||||
// When redirecting to a different domain, strip privileged headers.
|
|
||||||
req.privileged_headers = &.{};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (switch (req.response.status) {
|
|
||||||
.see_other => true,
|
|
||||||
.moved_permanently, .found => req.method == .POST,
|
|
||||||
else => false,
|
|
||||||
}) {
|
|
||||||
// A redirect to a GET must change the method and remove the body.
|
|
||||||
req.method = .GET;
|
|
||||||
req.transfer_encoding = .none;
|
|
||||||
req.headers.content_type = .omit;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (req.transfer_encoding != .none) {
|
|
||||||
// The request body has already been sent. The request is
|
|
||||||
// still in a valid state, but the redirect must be handled
|
|
||||||
// manually.
|
|
||||||
return error.RedirectRequiresResend;
|
|
||||||
}
|
|
||||||
|
|
||||||
try req.redirect(new_uri);
|
|
||||||
try req.send(.{});
|
|
||||||
} else {
|
} else {
|
||||||
req.response.skip = false;
|
req.response.skip = false;
|
||||||
if (!req.response.parser.done) {
|
if (!req.response.parser.done) {
|
||||||
@@ -1289,30 +1271,25 @@ fn createProxyFromEnvVar(arena: Allocator, env_var_names: []const []const u8) !?
|
|||||||
};
|
};
|
||||||
} else return null;
|
} else return null;
|
||||||
|
|
||||||
const uri = Uri.parse(content) catch try Uri.parseWithoutScheme(content);
|
const uri = Uri.parse(content) catch try Uri.parseAfterScheme("http", content);
|
||||||
|
const protocol, const valid_uri = validateUri(uri, arena) catch |err| switch (err) {
|
||||||
|
error.UnsupportedUriScheme => return null,
|
||||||
|
error.UriMissingHost => return error.HttpProxyMissingHost,
|
||||||
|
error.OutOfMemory => |e| return e,
|
||||||
|
};
|
||||||
|
|
||||||
const protocol = if (uri.scheme.len == 0)
|
const authorization: ?[]const u8 = if (valid_uri.user != null or valid_uri.password != null) a: {
|
||||||
.plain // No scheme, assume http://
|
const authorization = try arena.alloc(u8, basic_authorization.valueLengthFromUri(valid_uri));
|
||||||
else
|
assert(basic_authorization.value(valid_uri, authorization).len == authorization.len);
|
||||||
protocol_map.get(uri.scheme) orelse return null; // Unknown scheme, ignore
|
|
||||||
|
|
||||||
const host = uri.host orelse return error.HttpProxyMissingHost;
|
|
||||||
|
|
||||||
const authorization: ?[]const u8 = if (uri.user != null or uri.password != null) a: {
|
|
||||||
const authorization = try arena.alloc(u8, basic_authorization.valueLengthFromUri(uri));
|
|
||||||
assert(basic_authorization.value(uri, authorization).len == authorization.len);
|
|
||||||
break :a authorization;
|
break :a authorization;
|
||||||
} else null;
|
} else null;
|
||||||
|
|
||||||
const proxy = try arena.create(Proxy);
|
const proxy = try arena.create(Proxy);
|
||||||
proxy.* = .{
|
proxy.* = .{
|
||||||
.protocol = protocol,
|
.protocol = protocol,
|
||||||
.host = host,
|
.host = valid_uri.host.?.raw,
|
||||||
.authorization = authorization,
|
.authorization = authorization,
|
||||||
.port = uri.port orelse switch (protocol) {
|
.port = uriPort(valid_uri, protocol),
|
||||||
.plain => 80,
|
|
||||||
.tls => 443,
|
|
||||||
},
|
|
||||||
.supports_connect = true,
|
.supports_connect = true,
|
||||||
};
|
};
|
||||||
return proxy;
|
return proxy;
|
||||||
@@ -1330,24 +1307,26 @@ pub const basic_authorization = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn valueLengthFromUri(uri: Uri) usize {
|
pub fn valueLengthFromUri(uri: Uri) usize {
|
||||||
return valueLength(
|
var stream = std.io.countingWriter(std.io.null_writer);
|
||||||
if (uri.user) |user| user.len else 0,
|
try stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty});
|
||||||
if (uri.password) |password| password.len else 0,
|
const user_len = stream.bytes_written;
|
||||||
);
|
stream.bytes_written = 0;
|
||||||
|
try stream.writer().print("{password}", .{uri.password orelse Uri.Component.empty});
|
||||||
|
const password_len = stream.bytes_written;
|
||||||
|
return valueLength(@intCast(user_len), @intCast(password_len));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn value(uri: Uri, out: []u8) []u8 {
|
pub fn value(uri: Uri, out: []u8) []u8 {
|
||||||
assert(uri.user == null or uri.user.?.len <= max_user_len);
|
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
|
||||||
assert(uri.password == null or uri.password.?.len <= max_password_len);
|
var stream = std.io.fixedBufferStream(&buf);
|
||||||
|
stream.writer().print("{user}", .{uri.user orelse Uri.Component.empty}) catch
|
||||||
|
unreachable;
|
||||||
|
assert(stream.pos <= max_user_len);
|
||||||
|
stream.writer().print(":{password}", .{uri.password orelse Uri.Component.empty}) catch
|
||||||
|
unreachable;
|
||||||
|
|
||||||
@memcpy(out[0..prefix.len], prefix);
|
@memcpy(out[0..prefix.len], prefix);
|
||||||
|
const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], stream.getWritten());
|
||||||
var buf: [max_user_len + ":".len + max_password_len]u8 = undefined;
|
|
||||||
const unencoded = std.fmt.bufPrint(&buf, "{s}:{s}", .{
|
|
||||||
uri.user orelse "", uri.password orelse "",
|
|
||||||
}) catch unreachable;
|
|
||||||
const base64 = std.base64.standard.Encoder.encode(out[prefix.len..], unencoded);
|
|
||||||
|
|
||||||
return out[0 .. prefix.len + base64.len];
|
return out[0 .. prefix.len + base64.len];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -1362,8 +1341,7 @@ pub fn connectTcp(client: *Client, host: []const u8, port: u16, protocol: Connec
|
|||||||
.host = host,
|
.host = host,
|
||||||
.port = port,
|
.port = port,
|
||||||
.protocol = protocol,
|
.protocol = protocol,
|
||||||
})) |node|
|
})) |node| return node;
|
||||||
return node;
|
|
||||||
|
|
||||||
if (disable_tls and protocol == .tls)
|
if (disable_tls and protocol == .tls)
|
||||||
return error.TlsInitializationFailed;
|
return error.TlsInitializationFailed;
|
||||||
@@ -1439,19 +1417,12 @@ pub fn connectTunnel(
|
|||||||
client.connection_pool.release(client.allocator, conn);
|
client.connection_pool.release(client.allocator, conn);
|
||||||
}
|
}
|
||||||
|
|
||||||
const uri: Uri = .{
|
|
||||||
.scheme = "http",
|
|
||||||
.user = null,
|
|
||||||
.password = null,
|
|
||||||
.host = tunnel_host,
|
|
||||||
.port = tunnel_port,
|
|
||||||
.path = "",
|
|
||||||
.query = null,
|
|
||||||
.fragment = null,
|
|
||||||
};
|
|
||||||
|
|
||||||
var buffer: [8096]u8 = undefined;
|
var buffer: [8096]u8 = undefined;
|
||||||
var req = client.open(.CONNECT, uri, .{
|
var req = client.open(.CONNECT, .{
|
||||||
|
.scheme = "http",
|
||||||
|
.host = .{ .raw = tunnel_host },
|
||||||
|
.port = tunnel_port,
|
||||||
|
}, .{
|
||||||
.redirect_behavior = .unhandled,
|
.redirect_behavior = .unhandled,
|
||||||
.connection = conn,
|
.connection = conn,
|
||||||
.server_header_buffer = &buffer,
|
.server_header_buffer = &buffer,
|
||||||
@@ -1461,7 +1432,7 @@ pub fn connectTunnel(
|
|||||||
};
|
};
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
req.send(.{ .raw_uri = true }) catch |err| break :tunnel err;
|
req.send() catch |err| break :tunnel err;
|
||||||
req.wait() catch |err| break :tunnel err;
|
req.wait() catch |err| break :tunnel err;
|
||||||
|
|
||||||
if (req.response.status.class() == .server_error) {
|
if (req.response.status.class() == .server_error) {
|
||||||
@@ -1490,7 +1461,7 @@ pub fn connectTunnel(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prevents a dependency loop in open()
|
// Prevents a dependency loop in open()
|
||||||
const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUrlScheme, ConnectionRefused };
|
const ConnectErrorPartial = ConnectTcpError || error{ UnsupportedUriScheme, ConnectionRefused };
|
||||||
pub const ConnectError = ConnectErrorPartial || RequestError;
|
pub const ConnectError = ConnectErrorPartial || RequestError;
|
||||||
|
|
||||||
/// Connect to `host:port` using the specified protocol. This will reuse a
|
/// Connect to `host:port` using the specified protocol. This will reuse a
|
||||||
@@ -1538,7 +1509,7 @@ pub fn connect(
|
|||||||
pub const RequestError = ConnectTcpError || ConnectErrorPartial || Request.SendError ||
|
pub const RequestError = ConnectTcpError || ConnectErrorPartial || Request.SendError ||
|
||||||
std.fmt.ParseIntError || Connection.WriteError ||
|
std.fmt.ParseIntError || Connection.WriteError ||
|
||||||
error{ // TODO: file a zig fmt issue for this bad indentation
|
error{ // TODO: file a zig fmt issue for this bad indentation
|
||||||
UnsupportedUrlScheme,
|
UnsupportedUriScheme,
|
||||||
UriMissingHost,
|
UriMissingHost,
|
||||||
|
|
||||||
CertificateBundleLoadFailure,
|
CertificateBundleLoadFailure,
|
||||||
@@ -1588,12 +1559,28 @@ pub const RequestOptions = struct {
|
|||||||
privileged_headers: []const http.Header = &.{},
|
privileged_headers: []const http.Header = &.{},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{
|
fn validateUri(uri: Uri, arena: Allocator) !struct { Connection.Protocol, Uri } {
|
||||||
.{ "http", .plain },
|
const protocol_map = std.ComptimeStringMap(Connection.Protocol, .{
|
||||||
.{ "ws", .plain },
|
.{ "http", .plain },
|
||||||
.{ "https", .tls },
|
.{ "ws", .plain },
|
||||||
.{ "wss", .tls },
|
.{ "https", .tls },
|
||||||
});
|
.{ "wss", .tls },
|
||||||
|
});
|
||||||
|
const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUriScheme;
|
||||||
|
var valid_uri = uri;
|
||||||
|
// The host is always going to be needed as a raw string for hostname resolution anyway.
|
||||||
|
valid_uri.host = .{
|
||||||
|
.raw = try (uri.host orelse return error.UriMissingHost).toRawMaybeAlloc(arena),
|
||||||
|
};
|
||||||
|
return .{ protocol, valid_uri };
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uriPort(uri: Uri, protocol: Connection.Protocol) u16 {
|
||||||
|
return uri.port orelse switch (protocol) {
|
||||||
|
.plain => 80,
|
||||||
|
.tls => 443,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
/// Open a connection to the host specified by `uri` and prepare to send a HTTP request.
|
/// Open a connection to the host specified by `uri` and prepare to send a HTTP request.
|
||||||
///
|
///
|
||||||
@@ -1623,14 +1610,8 @@ pub fn open(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const protocol = protocol_map.get(uri.scheme) orelse return error.UnsupportedUrlScheme;
|
var server_header = std.heap.FixedBufferAllocator.init(options.server_header_buffer);
|
||||||
|
const protocol, const valid_uri = try validateUri(uri, server_header.allocator());
|
||||||
const port: u16 = uri.port orelse switch (protocol) {
|
|
||||||
.plain => 80,
|
|
||||||
.tls => 443,
|
|
||||||
};
|
|
||||||
|
|
||||||
const host = uri.host orelse return error.UriMissingHost;
|
|
||||||
|
|
||||||
if (protocol == .tls and @atomicLoad(bool, &client.next_https_rescan_certs, .acquire)) {
|
if (protocol == .tls and @atomicLoad(bool, &client.next_https_rescan_certs, .acquire)) {
|
||||||
if (disable_tls) unreachable;
|
if (disable_tls) unreachable;
|
||||||
@@ -1639,15 +1620,17 @@ pub fn open(
|
|||||||
defer client.ca_bundle_mutex.unlock();
|
defer client.ca_bundle_mutex.unlock();
|
||||||
|
|
||||||
if (client.next_https_rescan_certs) {
|
if (client.next_https_rescan_certs) {
|
||||||
client.ca_bundle.rescan(client.allocator) catch return error.CertificateBundleLoadFailure;
|
client.ca_bundle.rescan(client.allocator) catch
|
||||||
|
return error.CertificateBundleLoadFailure;
|
||||||
@atomicStore(bool, &client.next_https_rescan_certs, false, .release);
|
@atomicStore(bool, &client.next_https_rescan_certs, false, .release);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const conn = options.connection orelse try client.connect(host, port, protocol);
|
const conn = options.connection orelse
|
||||||
|
try client.connect(valid_uri.host.?.raw, uriPort(valid_uri, protocol), protocol);
|
||||||
|
|
||||||
var req: Request = .{
|
var req: Request = .{
|
||||||
.uri = uri,
|
.uri = valid_uri,
|
||||||
.client = client,
|
.client = client,
|
||||||
.connection = conn,
|
.connection = conn,
|
||||||
.keep_alive = options.keep_alive,
|
.keep_alive = options.keep_alive,
|
||||||
@@ -1661,7 +1644,7 @@ pub fn open(
|
|||||||
.status = undefined,
|
.status = undefined,
|
||||||
.reason = undefined,
|
.reason = undefined,
|
||||||
.keep_alive = undefined,
|
.keep_alive = undefined,
|
||||||
.parser = proto.HeadersParser.init(options.server_header_buffer),
|
.parser = proto.HeadersParser.init(server_header.buffer[server_header.end_index..]),
|
||||||
},
|
},
|
||||||
.headers = options.headers,
|
.headers = options.headers,
|
||||||
.extra_headers = options.extra_headers,
|
.extra_headers = options.extra_headers,
|
||||||
@@ -1741,7 +1724,7 @@ pub fn fetch(client: *Client, options: FetchOptions) !FetchResult {
|
|||||||
|
|
||||||
if (options.payload) |payload| req.transfer_encoding = .{ .content_length = payload.len };
|
if (options.payload) |payload| req.transfer_encoding = .{ .content_length = payload.len };
|
||||||
|
|
||||||
try req.send(.{ .raw_uri = options.raw_uri });
|
try req.send();
|
||||||
|
|
||||||
if (options.payload) |payload| try req.writeAll(payload);
|
if (options.payload) |payload| try req.writeAll(payload);
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ test "blocking mode open/send/wait API" {
|
|||||||
});
|
});
|
||||||
defer req.deinit();
|
defer req.deinit();
|
||||||
|
|
||||||
try req.send(.{});
|
try req.send();
|
||||||
try req.finish();
|
try req.finish();
|
||||||
try req.wait();
|
try req.wait();
|
||||||
|
|
||||||
@@ -120,7 +120,7 @@ const AsyncClient = struct {
|
|||||||
},
|
},
|
||||||
.open => {
|
.open => {
|
||||||
self.state = .send;
|
self.state = .send;
|
||||||
self.req.?.send(.{}) catch |e| return self.onerr(e);
|
self.req.?.send() catch |e| return self.onerr(e);
|
||||||
},
|
},
|
||||||
.send => {
|
.send => {
|
||||||
self.state = .finish;
|
self.state = .finish;
|
||||||
|
|||||||
@@ -224,7 +224,7 @@ pub const Page = struct {
|
|||||||
// own the url
|
// own the url
|
||||||
if (self.rawuri) |prev| alloc.free(prev);
|
if (self.rawuri) |prev| alloc.free(prev);
|
||||||
self.rawuri = try alloc.dupe(u8, uri);
|
self.rawuri = try alloc.dupe(u8, uri);
|
||||||
self.uri = std.Uri.parse(self.rawuri.?) catch try std.Uri.parseWithoutScheme(self.rawuri.?);
|
self.uri = std.Uri.parse(self.rawuri.?) catch try std.Uri.parseAfterScheme("", self.rawuri.?);
|
||||||
|
|
||||||
// prepare origin value.
|
// prepare origin value.
|
||||||
var buf = std.ArrayList(u8).init(alloc);
|
var buf = std.ArrayList(u8).init(alloc);
|
||||||
@@ -511,7 +511,8 @@ pub const Page = struct {
|
|||||||
log.debug("starting fetch script {s}", .{src});
|
log.debug("starting fetch script {s}", .{src});
|
||||||
|
|
||||||
var buffer: [1024]u8 = undefined;
|
var buffer: [1024]u8 = undefined;
|
||||||
const u = try std.Uri.resolve_inplace(self.uri, src, &buffer);
|
var b: []u8 = buffer[0..];
|
||||||
|
const u = try std.Uri.resolve_inplace(self.uri, src, &b);
|
||||||
|
|
||||||
var fetchres = try self.session.loader.get(alloc, u);
|
var fetchres = try self.session.loader.get(alloc, u);
|
||||||
defer fetchres.deinit();
|
defer fetchres.deinit();
|
||||||
@@ -529,7 +530,7 @@ pub const Page = struct {
|
|||||||
// check no body
|
// check no body
|
||||||
if (body.len == 0) return FetchError.NoBody;
|
if (body.len == 0) return FetchError.NoBody;
|
||||||
|
|
||||||
var res = try self.session.env.execTryCatch(alloc, fetchres.body.?, src);
|
var res = try self.session.env.execTryCatch(alloc, body, src);
|
||||||
defer res.deinit(alloc);
|
defer res.deinit(alloc);
|
||||||
|
|
||||||
if (res.success) {
|
if (res.success) {
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ pub const Loader = struct {
|
|||||||
});
|
});
|
||||||
errdefer resp.req.deinit();
|
errdefer resp.req.deinit();
|
||||||
|
|
||||||
try resp.req.send(.{});
|
try resp.req.send();
|
||||||
try resp.req.finish();
|
try resp.req.finish();
|
||||||
try resp.req.wait();
|
try resp.req.wait();
|
||||||
|
|
||||||
|
|||||||
@@ -246,10 +246,10 @@ pub const HTMLAnchorElement = struct {
|
|||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
if (p) |pp| {
|
if (p) |pp| {
|
||||||
u.uri.host = h;
|
u.uri.host = .{ .raw = h };
|
||||||
u.uri.port = pp;
|
u.uri.port = pp;
|
||||||
} else {
|
} else {
|
||||||
u.uri.host = v;
|
u.uri.host = .{ .raw = v };
|
||||||
u.uri.port = null;
|
u.uri.port = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -271,7 +271,7 @@ pub const HTMLAnchorElement = struct {
|
|||||||
var u = try url(self, alloc);
|
var u = try url(self, alloc);
|
||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
u.uri.host = v;
|
u.uri.host = .{ .raw = v };
|
||||||
const href = try u.format(alloc);
|
const href = try u.format(alloc);
|
||||||
try parser.anchorSetHref(self, href);
|
try parser.anchorSetHref(self, href);
|
||||||
}
|
}
|
||||||
@@ -312,7 +312,11 @@ pub const HTMLAnchorElement = struct {
|
|||||||
var u = try url(self, alloc);
|
var u = try url(self, alloc);
|
||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
u.uri.user = v;
|
if (v) |vv| {
|
||||||
|
u.uri.user = .{ .raw = vv };
|
||||||
|
} else {
|
||||||
|
u.uri.user = null;
|
||||||
|
}
|
||||||
const href = try u.format(alloc);
|
const href = try u.format(alloc);
|
||||||
defer alloc.free(href);
|
defer alloc.free(href);
|
||||||
|
|
||||||
@@ -331,7 +335,11 @@ pub const HTMLAnchorElement = struct {
|
|||||||
var u = try url(self, alloc);
|
var u = try url(self, alloc);
|
||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
u.uri.password = v;
|
if (v) |vv| {
|
||||||
|
u.uri.password = .{ .raw = vv };
|
||||||
|
} else {
|
||||||
|
u.uri.password = null;
|
||||||
|
}
|
||||||
const href = try u.format(alloc);
|
const href = try u.format(alloc);
|
||||||
defer alloc.free(href);
|
defer alloc.free(href);
|
||||||
|
|
||||||
@@ -350,7 +358,7 @@ pub const HTMLAnchorElement = struct {
|
|||||||
var u = try url(self, alloc);
|
var u = try url(self, alloc);
|
||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
u.uri.path = v;
|
u.uri.path = .{ .raw = v };
|
||||||
const href = try u.format(alloc);
|
const href = try u.format(alloc);
|
||||||
defer alloc.free(href);
|
defer alloc.free(href);
|
||||||
|
|
||||||
@@ -369,7 +377,11 @@ pub const HTMLAnchorElement = struct {
|
|||||||
var u = try url(self, alloc);
|
var u = try url(self, alloc);
|
||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
u.uri.query = v;
|
if (v) |vv| {
|
||||||
|
u.uri.query = .{ .raw = vv };
|
||||||
|
} else {
|
||||||
|
u.uri.query = null;
|
||||||
|
}
|
||||||
const href = try u.format(alloc);
|
const href = try u.format(alloc);
|
||||||
defer alloc.free(href);
|
defer alloc.free(href);
|
||||||
|
|
||||||
@@ -388,7 +400,11 @@ pub const HTMLAnchorElement = struct {
|
|||||||
var u = try url(self, alloc);
|
var u = try url(self, alloc);
|
||||||
defer u.deinit(alloc);
|
defer u.deinit(alloc);
|
||||||
|
|
||||||
u.uri.fragment = v;
|
if (v) |vv| {
|
||||||
|
u.uri.fragment = .{ .raw = vv };
|
||||||
|
} else {
|
||||||
|
u.uri.fragment = null;
|
||||||
|
}
|
||||||
const href = try u.format(alloc);
|
const href = try u.format(alloc);
|
||||||
defer alloc.free(href);
|
defer alloc.free(href);
|
||||||
|
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ pub fn main() !void {
|
|||||||
while (args.next()) |arg| {
|
while (args.next()) |arg| {
|
||||||
if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) {
|
if (std.mem.eql(u8, "-h", arg) or std.mem.eql(u8, "--help", arg)) {
|
||||||
try std.io.getStdErr().writer().print(usage, .{});
|
try std.io.getStdErr().writer().print(usage, .{});
|
||||||
std.os.exit(0);
|
std.posix.exit(0);
|
||||||
}
|
}
|
||||||
if (std.mem.eql(u8, "--json", arg)) {
|
if (std.mem.eql(u8, "--json", arg)) {
|
||||||
out = .json;
|
out = .json;
|
||||||
|
|||||||
@@ -62,7 +62,10 @@ pub const URL = struct {
|
|||||||
return .{
|
return .{
|
||||||
.rawuri = raw,
|
.rawuri = raw,
|
||||||
.uri = uri,
|
.uri = uri,
|
||||||
.search_params = try URLSearchParams.constructor(alloc, uri.query),
|
.search_params = try URLSearchParams.constructor(
|
||||||
|
alloc,
|
||||||
|
uriComponentNullStr(uri.query),
|
||||||
|
),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +105,7 @@ pub const URL = struct {
|
|||||||
var q = std.ArrayList(u8).init(alloc);
|
var q = std.ArrayList(u8).init(alloc);
|
||||||
defer q.deinit();
|
defer q.deinit();
|
||||||
try self.search_params.values.encode(q.writer());
|
try self.search_params.values.encode(q.writer());
|
||||||
self.uri.query = q.items;
|
self.uri.query = .{ .raw = q.items };
|
||||||
|
|
||||||
return try self.format(alloc);
|
return try self.format(alloc);
|
||||||
}
|
}
|
||||||
@@ -116,9 +119,9 @@ pub const URL = struct {
|
|||||||
.scheme = true,
|
.scheme = true,
|
||||||
.authentication = true,
|
.authentication = true,
|
||||||
.authority = true,
|
.authority = true,
|
||||||
.path = self.uri.path.len > 0,
|
.path = uriComponentNullStr(self.uri.path).len > 0,
|
||||||
.query = self.uri.query != null and self.uri.query.?.len > 0,
|
.query = uriComponentNullStr(self.uri.query).len > 0,
|
||||||
.fragment = self.uri.fragment != null and self.uri.fragment.?.len > 0,
|
.fragment = uriComponentNullStr(self.uri.fragment).len > 0,
|
||||||
}, buf.writer());
|
}, buf.writer());
|
||||||
return try buf.toOwnedSlice();
|
return try buf.toOwnedSlice();
|
||||||
}
|
}
|
||||||
@@ -131,11 +134,11 @@ pub const URL = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_username(self: *URL) []const u8 {
|
pub fn get_username(self: *URL) []const u8 {
|
||||||
return self.uri.user orelse "";
|
return uriComponentNullStr(self.uri.user);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_password(self: *URL) []const u8 {
|
pub fn get_password(self: *URL) []const u8 {
|
||||||
return self.uri.password orelse "";
|
return uriComponentNullStr(self.uri.password);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the caller must free the returned string.
|
// the caller must free the returned string.
|
||||||
@@ -157,7 +160,7 @@ pub const URL = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_hostname(self: *URL) []const u8 {
|
pub fn get_hostname(self: *URL) []const u8 {
|
||||||
return self.uri.host orelse "";
|
return uriComponentNullStr(self.uri.host);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the caller must free the returned string.
|
// the caller must free the returned string.
|
||||||
@@ -174,8 +177,8 @@ pub const URL = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_pathname(self: *URL) []const u8 {
|
pub fn get_pathname(self: *URL) []const u8 {
|
||||||
if (self.uri.path.len == 0) return "/";
|
if (uriComponentStr(self.uri.path).len == 0) return "/";
|
||||||
return self.uri.path;
|
return uriComponentStr(self.uri.path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the caller must free the returned string.
|
// the caller must free the returned string.
|
||||||
@@ -198,7 +201,7 @@ pub const URL = struct {
|
|||||||
pub fn get_hash(self: *URL, alloc: std.mem.Allocator) ![]const u8 {
|
pub fn get_hash(self: *URL, alloc: std.mem.Allocator) ![]const u8 {
|
||||||
if (self.uri.fragment == null) return try alloc.dupe(u8, "");
|
if (self.uri.fragment == null) return try alloc.dupe(u8, "");
|
||||||
|
|
||||||
return try std.mem.concat(alloc, u8, &[_][]const u8{ "#", self.uri.fragment.? });
|
return try std.mem.concat(alloc, u8, &[_][]const u8{ "#", uriComponentNullStr(self.uri.fragment) });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_searchParams(self: *URL) *URLSearchParams {
|
pub fn get_searchParams(self: *URL) *URLSearchParams {
|
||||||
@@ -210,6 +213,21 @@ pub const URL = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// uriComponentNullStr converts an optional std.Uri.Component to string value.
|
||||||
|
// The string value can be undecoded.
|
||||||
|
fn uriComponentNullStr(c: ?std.Uri.Component) []const u8 {
|
||||||
|
if (c == null) return "";
|
||||||
|
|
||||||
|
return uriComponentStr(c.?);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uriComponentStr(c: std.Uri.Component) []const u8 {
|
||||||
|
return switch (c) {
|
||||||
|
.raw => |v| v,
|
||||||
|
.percent_encoded => |v| v,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// https://url.spec.whatwg.org/#interface-urlsearchparams
|
// https://url.spec.whatwg.org/#interface-urlsearchparams
|
||||||
// TODO array like
|
// TODO array like
|
||||||
pub const URLSearchParams = struct {
|
pub const URLSearchParams = struct {
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ pub const XMLHttpRequestBodyInit = union(XMLHttpRequestBodyInitTag) {
|
|||||||
pub const XMLHttpRequest = struct {
|
pub const XMLHttpRequest = struct {
|
||||||
proto: XMLHttpRequestEventTarget = XMLHttpRequestEventTarget{},
|
proto: XMLHttpRequestEventTarget = XMLHttpRequestEventTarget{},
|
||||||
alloc: std.mem.Allocator,
|
alloc: std.mem.Allocator,
|
||||||
cli: Client,
|
cli: *Client,
|
||||||
impl: YieldImpl,
|
impl: YieldImpl,
|
||||||
|
|
||||||
priv_state: PrivState = .new,
|
priv_state: PrivState = .new,
|
||||||
@@ -509,7 +509,7 @@ pub const XMLHttpRequest = struct {
|
|||||||
if (self.payload) |v| self.req.?.transfer_encoding = .{ .content_length = v.len };
|
if (self.payload) |v| self.req.?.transfer_encoding = .{ .content_length = v.len };
|
||||||
|
|
||||||
self.priv_state = .send;
|
self.priv_state = .send;
|
||||||
self.req.?.send(.{}) catch |e| return self.onErr(e);
|
self.req.?.send() catch |e| return self.onErr(e);
|
||||||
},
|
},
|
||||||
.send => {
|
.send => {
|
||||||
if (self.payload) |payload| {
|
if (self.payload) |payload| {
|
||||||
|
|||||||
Reference in New Issue
Block a user