diff --git a/lib/std/Io/net/HostName.zig b/lib/std/Io/net/HostName.zig index 262a86386b60f9b3b4585e7749089c02eca47efc..6249e47dfcda57c603d42042094abbde235a62b1 100644 --- a/lib/std/Io/net/HostName.zig +++ b/lib/std/Io/net/HostName.zig @@ -19,6 +19,18 @@ bytes: []const u8, pub const max_len = 255; +pub const FromUriError = error{UriMissingHost} || ValidateError; + +/// Returned `HostName.bytes` may point into `buffer` or `uri.host`. +pub fn fromUri(uri: std.Uri, buffer: *[HostName.max_len]u8) FromUriError!HostName { + const component = uri.host orelse return error.UriMissingHost; + const bytes = component.toRaw(buffer) catch |err| switch (err) { + error.NoSpaceLeft => return error.NameTooLong, + }; + try validate(bytes); + return .{ .bytes = bytes }; +} + pub const ValidateError = error{ NameTooLong, InvalidHostName, diff --git a/lib/std/Uri.zig b/lib/std/Uri.zig index 352af5aed73d4bd11ed7302b44669d52229d9f9d..dccda6e89a3fab38b2bb096da54aae24dcccb018 100644 --- a/lib/std/Uri.zig +++ b/lib/std/Uri.zig @@ -7,43 +7,18 @@ const testing = std.testing; const Uri = @This(); const Allocator = std.mem.Allocator; const Writer = std.Io.Writer; -const HostName = std.Io.net.HostName; scheme: []const u8, user: ?Component = null, password: ?Component = null, -/// If non-null, already validated. host: ?Component = null, port: ?u16 = null, path: Component = Component.empty, query: ?Component = null, fragment: ?Component = null, -pub const GetHostError = error{UriMissingHost}; - -/// Returned value may point into `buffer` or be the original string. -/// -/// See also: -/// * `getHostAlloc` -pub fn getHost(uri: Uri, buffer: *[HostName.max_len]u8) GetHostError!HostName { - const component = uri.host orelse return error.UriMissingHost; - const bytes = component.toRaw(buffer) catch |err| switch (err) { - error.NoSpaceLeft => unreachable, // `host` already validated. - }; - return .{ .bytes = bytes }; -} - -pub const GetHostAllocError = GetHostError || error{OutOfMemory}; - -/// Returned value may point into `buffer` or be the original string. -/// -/// See also: -/// * `getHost` -pub fn getHostAlloc(uri: Uri, arena: Allocator) GetHostAllocError!HostName { - const component = uri.host orelse return error.UriMissingHost; - const bytes = try component.toRawMaybeAlloc(arena); - return .{ .bytes = bytes }; -} +pub const getHost = @compileError("This function has been moved to std.Io.net.HostName.fromUri"); +pub const getHostAlloc = @compileError("This function has been deleted. See std.Io.net.HostName.fromUri instead"); pub const Component = union(enum) { /// Invalid characters in this component must be percent encoded @@ -403,7 +378,7 @@ pub fn resolveInPlace(base: Uri, new_len: usize, aux_buf: *[]u8) ResolveInPlaceE .scheme = new_parsed.scheme, .user = new_parsed.user, .password = new_parsed.password, - .host = try validateHostComponent(new_parsed.host), + .host = new_parsed.host, .port = new_parsed.port, .path = remove_dot_segments(new_path), .query = new_parsed.query, @@ -414,7 +389,7 @@ pub fn resolveInPlace(base: Uri, new_len: usize, aux_buf: *[]u8) ResolveInPlaceE .scheme = base.scheme, .user = new_parsed.user, .password = new_parsed.password, - .host = try validateHostComponent(host), + .host = host, .port = new_parsed.port, .path = remove_dot_segments(new_path), .query = new_parsed.query, @@ -436,7 +411,7 @@ pub fn resolveInPlace(base: Uri, new_len: usize, aux_buf: *[]u8) ResolveInPlaceE .scheme = base.scheme, .user = base.user, .password = base.password, - .host = try validateHostComponent(base.host), + .host = base.host, .port = base.port, .path = path, .query = query, @@ -444,18 +419,6 @@ pub fn resolveInPlace(base: Uri, new_len: usize, aux_buf: *[]u8) ResolveInPlaceE }; } -fn validateHostComponent(optional_component: ?Component) error{InvalidHostName}!?Component { - const component = optional_component orelse return null; - switch (component) { - .raw => |raw| HostName.validate(raw) catch return error.InvalidHostName, - .percent_encoded => |encoded| { - // TODO validate decoded name instead - HostName.validate(encoded) catch return error.InvalidHostName; - }, - } - return component; -} - /// In-place implementation of RFC 3986, Section 5.2.4. fn remove_dot_segments(path: []u8) Component { var in_i: usize = 0; diff --git a/lib/std/http/Client.zig b/lib/std/http/Client.zig index 1dd8bb657944484ae0608002395166cea3a0decf..5eca8d78a8f582c773589d9f01f4ff85027e7500 100644 --- a/lib/std/http/Client.zig +++ b/lib/std/http/Client.zig @@ -1229,7 +1229,11 @@ pub const Request = struct { const old_connection = r.connection.?; const old_host = old_connection.host(); var new_host_name_buffer: [HostName.max_len]u8 = undefined; - const new_host = try new_uri.getHost(&new_host_name_buffer); + const new_host = HostName.fromUri(new_uri, &new_host_name_buffer) catch |err| switch (err) { + error.UriMissingHost => return error.HttpRedirectLocationInvalid, + error.InvalidHostName => return error.HttpRedirectLocationInvalid, + error.NameTooLong => return error.HttpRedirectLocationOversize, + }; const keep_privileged_headers = std.ascii.eqlIgnoreCase(r.uri.scheme, new_uri.scheme) and old_host.sameParentDomain(new_host); @@ -1349,7 +1353,8 @@ fn createProxyFromEnvVar( const uri = Uri.parse(content) catch try Uri.parseAfterScheme("http", content); const protocol = Protocol.fromUri(uri) orelse return null; - const raw_host = try uri.getHostAlloc(arena); + var host_buf: [HostName.max_len]u8 = undefined; + const raw_host = try HostName.fromUri(uri, &host_buf); const authorization: ?[]const u8 = if (uri.user != null or uri.password != null) a: { const authorization = try arena.alloc(u8, basic_authorization.valueLengthFromUri(uri)); @@ -1360,7 +1365,7 @@ fn createProxyFromEnvVar( const proxy = try arena.create(Proxy); proxy.* = .{ .protocol = protocol, - .host = raw_host, + .host = .{ .bytes = try arena.dupe(u8, raw_host.bytes) }, .authorization = authorization, .port = uriPort(uri, protocol), .supports_connect = true, @@ -1624,6 +1629,7 @@ pub fn connect( pub const RequestError = ConnectTcpError || error{ UnsupportedUriScheme, UriMissingHost, + InvalidHostName, CertificateBundleLoadFailure, }; @@ -1721,7 +1727,10 @@ pub fn request( const connection = options.connection orelse c: { var host_name_buffer: [HostName.max_len]u8 = undefined; - const host_name = try uri.getHost(&host_name_buffer); + const host_name = HostName.fromUri(uri, &host_name_buffer) catch |err| switch (err) { + error.UriMissingHost => |e| return e, + error.NameTooLong, error.InvalidHostName => return error.InvalidHostName, + }; break :c try client.connect(host_name, uriPort(uri, protocol), protocol); };