AK+LibURL: Use AK::IPv4/6 in Host

This resolves two FIXME comments.
This commit is contained in:
Arran Ireland 2025-11-28 14:18:57 +00:00 committed by Shannon Booth
parent bef8423f0f
commit bd82dfa048
11 changed files with 87 additions and 44 deletions

View file

@ -6,6 +6,7 @@
#pragma once
#include <AK/BitCast.h>
#include <AK/Endian.h>
#include <AK/Format.h>
#include <AK/IPv4Address.h>
@ -36,6 +37,15 @@ public:
m_data[i] = data[i];
}
constexpr IPv6Address(Array<u16, 8> const& data)
{
for (size_t i = 0; i < 8; i++) {
auto piece = data[i];
m_data[2 * i] = static_cast<u8>(piece >> 8);
m_data[(2 * i) + 1] = static_cast<u8>(piece & 0xff);
}
}
template<SameAs<char const*> T>
constexpr IPv6Address(T const&) = delete; // Disable implicit conversion of char const* -> ipv4 -> ipv6
@ -50,7 +60,7 @@ public:
m_data[15] = ipv4_address[3];
}
constexpr u16 operator[](int i) const { return group(i); }
constexpr u16 operator[](size_t i) const { return piece(i); }
ErrorOr<String> to_string() const
{
@ -68,13 +78,13 @@ public:
Optional<int> longest_zero_span_start;
int zero_span_length = 0;
for (int i = 0; i < 8;) {
if (group(i) != 0) {
if (piece(i) != 0) {
i++;
continue;
}
int contiguous_zeros = 1;
for (int j = i + 1; j < 8; j++) {
if (group(j) != 0)
if (piece(j) != 0)
break;
contiguous_zeros++;
}
@ -98,9 +108,9 @@ public:
}
if (i == 0)
TRY(builder.try_appendff("{:x}", group(i)));
TRY(builder.try_appendff("{:x}", piece(i)));
else
TRY(builder.try_appendff(":{:x}", group(i)));
TRY(builder.try_appendff(":{:x}", piece(i)));
i++;
}
@ -186,8 +196,8 @@ public:
}
in6_addr_t addr {};
int group = 0;
int have_groups = 0;
int piece = 0;
int have_pieces = 0;
bool found_compressed = false;
for (size_t i = 0; i < parts.size();) {
auto trimmed_part = parts[i].trim_whitespace();
@ -216,10 +226,10 @@ public:
return {};
}
int remaining_parts = parts.size() - empty_parts - have_groups;
int remaining_parts = parts.size() - empty_parts - have_pieces;
found_compressed = true;
group = 8 - remaining_parts;
VERIFY(group >= 0);
piece = 8 - remaining_parts;
VERIFY(piece >= 0);
i += empty_parts;
continue;
} else {
@ -229,13 +239,13 @@ public:
if (!part.has_value() || part.value() > 0xffff)
return {};
if (++have_groups > 8)
if (++have_pieces > 8)
return {};
VERIFY(group < 8);
addr[group * sizeof(u16)] = (u8)(part.value() >> 8);
addr[group * sizeof(u16) + 1] = (u8)part.value();
group++;
VERIFY(piece < 8);
addr[piece * sizeof(u16)] = (u8)(part.value() >> 8);
addr[piece * sizeof(u16) + 1] = (u8)part.value();
piece++;
}
return IPv6Address(addr);
@ -278,7 +288,7 @@ public:
}
private:
constexpr u16 group(unsigned i) const
constexpr u16 piece(size_t i) const
{
VERIFY(i < 8);
return ((u16)m_data[i * sizeof(u16)] << 8) | m_data[i * sizeof(u16) + 1];

View file

@ -20,7 +20,7 @@ struct ProxyData {
SOCKS5,
} type { Type::Direct };
u32 host_ipv4 { 0 };
IPv4Address host_ipv4;
int port { 0 };
bool operator==(ProxyData const& other) const = default;
@ -33,9 +33,9 @@ struct ProxyData {
proxy_data.type = ProxyData::Type::SOCKS5;
if (!url.host().has_value() || !url.host()->has<URL::IPv4Address>())
if (!url.host().has_value() || !url.host()->has<IPv4Address>())
return Error::from_string_literal("Invalid proxy host, must be an IPv4 address");
proxy_data.host_ipv4 = url.host()->get<URL::IPv4Address>();
proxy_data.host_ipv4 = url.host()->get<IPv4Address>();
auto port = url.port();
if (!port.has_value())

View file

@ -5,6 +5,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/IPv4Address.h>
#include <AK/IPv6Address.h>
#include <AK/JsonValue.h>
#include <AK/NumericLimits.h>
#include <AK/Utf16String.h>
@ -87,6 +89,20 @@ ErrorOr<UnixDateTime> decode(Decoder& decoder)
return AK::UnixDateTime::from_nanoseconds_since_epoch(nanoseconds);
}
template<>
ErrorOr<IPv4Address> decode(Decoder& decoder)
{
auto ipv4 = TRY(decoder.decode<u32>());
return IPv4Address(ipv4);
}
template<>
ErrorOr<IPv6Address> decode(Decoder& decoder)
{
auto ipv6 = TRY(decoder.decode<Array<u8, 16>>());
return IPv6Address(ipv6);
}
template<>
ErrorOr<URL::URL> decode(Decoder& decoder)
{
@ -153,7 +169,7 @@ template<>
ErrorOr<Core::ProxyData> decode(Decoder& decoder)
{
auto type = TRY(decoder.decode<Core::ProxyData::Type>());
auto host_ipv4 = TRY(decoder.decode<u32>());
auto host_ipv4 = IPv4Address(TRY(decoder.decode<u32>()));
auto port = TRY(decoder.decode<int>());
return Core::ProxyData { type, host_ipv4, port };

View file

@ -106,6 +106,12 @@ ErrorOr<AK::Duration> decode(Decoder&);
template<>
ErrorOr<UnixDateTime> decode(Decoder&);
template<>
ErrorOr<IPv4Address> decode(Decoder&);
template<>
ErrorOr<IPv6Address> decode(Decoder&);
template<>
ErrorOr<URL::URL> decode(Decoder&);

View file

@ -111,6 +111,19 @@ ErrorOr<void> encode(Encoder& encoder, UnixDateTime const& value)
return encoder.encode(value.nanoseconds_since_epoch());
}
template<>
ErrorOr<void> encode(Encoder& encoder, IPv4Address const& ipv4)
{
return encoder.encode(ipv4.to_u32());
}
template<>
ErrorOr<void> encode(Encoder& encoder, IPv6Address const& ipv6)
{
auto const& data = ipv6.to_in6_addr_t();
return encoder.encode(ReadonlySpan<u8>(data));
}
template<>
ErrorOr<void> encode(Encoder& encoder, URL::URL const& value)
{

View file

@ -9,6 +9,7 @@
#include <AK/Concepts.h>
#include <AK/HashMap.h>
#include <AK/IPv4Address.h>
#include <AK/StdLibExtras.h>
#include <AK/Variant.h>
#include <LibCore/Forward.h>
@ -108,6 +109,12 @@ ErrorOr<void> encode(Encoder&, AK::Duration const&);
template<>
ErrorOr<void> encode(Encoder&, UnixDateTime const&);
template<>
ErrorOr<void> encode(Encoder&, IPv4Address const&);
template<>
ErrorOr<void> encode(Encoder&, IPv6Address const&);
template<>
ErrorOr<void> encode(Encoder&, URL::URL const&);

View file

@ -30,7 +30,7 @@ static String serialize_ipv4_address(IPv4Address address)
Array<u8, 4> output;
// 2. Let n be the value of address.
u32 n = address;
u32 n = address.to_u32();
// 3. For each i in the range 1 to 4, inclusive:
for (size_t i = 0; i <= 3; ++i) {
@ -64,7 +64,7 @@ static Optional<size_t> find_the_ipv6_address_compressed_piece_index(IPv6Address
size_t found_size = 0;
// 5. For each pieceIndex of addresss piecess indices:
for (size_t piece_index = 0; piece_index < address.size(); ++piece_index) {
for (size_t piece_index = 0; piece_index < 8; ++piece_index) {
// 1. If addresss pieces[pieceIndex] is not 0:
if (address[piece_index] != 0) {
// 1. If foundSize is greater than longestSize, then set longestIndex to foundIndex and longestSize to foundSize.
@ -110,7 +110,7 @@ static void serialize_ipv6_address(IPv6Address const& address, StringBuilder& ou
auto ignore0 = false;
// 4. For each pieceIndex of addresss piecess indices:
for (size_t piece_index = 0; piece_index < address.size(); ++piece_index) {
for (size_t piece_index = 0; piece_index < 8; ++piece_index) {
// 1. If ignore0 is true and address[pieceIndex] is 0, then continue.
if (ignore0 && address[piece_index] == 0)
continue;

View file

@ -8,22 +8,13 @@
#pragma once
#include <AK/Array.h>
#include <AK/IPv4Address.h>
#include <AK/IPv6Address.h>
#include <AK/String.h>
#include <AK/Types.h>
namespace URL {
// https://url.spec.whatwg.org/#concept-ipv4
// An IPv4 address is a 32-bit unsigned integer that identifies a network address. [RFC791]
// FIXME: It would be nice if this were an AK::IPv4Address
using IPv4Address = u32;
// https://url.spec.whatwg.org/#concept-ipv6
// An IPv6 address is a 128-bit unsigned integer that identifies a network address. For the purposes of this standard
// it is represented as a list of eight 16-bit unsigned integers, also known as IPv6 pieces. [RFC4291]
// FIXME: It would be nice if this were an AK::IPv6Address
using IPv6Address = Array<u16, 8>;
// https://url.spec.whatwg.org/#concept-host
// A host is a domain, an IP address, an opaque host, or an empty host. Typically a host serves as a network address,
// but it is sometimes used as opaque identifier in URLs where a network address is not necessary.

View file

@ -8,6 +8,8 @@
#include <AK/ByteString.h>
#include <AK/CharacterTypes.h>
#include <AK/Debug.h>
#include <AK/IPv4Address.h>
#include <AK/IPv6Address.h>
#include <AK/IntegralMath.h>
#include <AK/Optional.h>
#include <AK/SourceLocation.h>
@ -226,7 +228,7 @@ static Optional<IPv4Address> parse_ipv4_address(StringView input)
}
// 13. Return ipv4.
return ipv4;
return IPv4Address(ipv4);
}
// https://url.spec.whatwg.org/#concept-ipv6-parser
@ -455,7 +457,7 @@ static Optional<IPv6Address> parse_ipv6_address(StringView input)
}
// 9. Return address.
return address;
return IPv6Address(address);
}
// https://url.spec.whatwg.org/#ends-in-a-number-checker

View file

@ -21,7 +21,7 @@ void upgrade_a_mixed_content_request_to_a_potentially_trustworthy_url_if_appropr
SecureContexts::is_url_potentially_trustworthy(request.url()) == SecureContexts::Trustworthiness::PotentiallyTrustworthy
// 2. requests URLs host is an IP address.
|| (request.url().host().has_value() && (request.url().host()->has<URL::IPv4Address>() || request.url().host()->has<URL::IPv6Address>()))
|| (request.url().host().has_value() && (request.url().host()->has<IPv4Address>() || request.url().host()->has<IPv6Address>()))
// 3. §4.3 Does settings prohibit mixed security contexts? returns "Does Not Restrict Mixed Security Contents" when applied to requests client.
|| does_settings_prohibit_mixed_security_contexts(request.client()) == ProhibitsMixedSecurityContexts::DoesNotRestrictMixedSecurityContexts

View file

@ -28,14 +28,12 @@ Trustworthiness is_origin_potentially_trustworthy(URL::Origin const& origin)
return Trustworthiness::PotentiallyTrustworthy;
// 4. If origins host matches one of the CIDR notations 127.0.0.0/8 or ::1/128 [RFC4632], return "Potentially Trustworthy".
// FIXME: This would be nicer if URL::IPv4Address and URL::IPv6Address were instances of AK::IPv4Address and AK::IPv6Address
if (origin.host().has<URL::IPv4Address>()) {
if ((origin.host().get<URL::IPv4Address>() & 0xff000000) != 0)
if (origin.host().has<IPv4Address>()) {
if ((origin.host().get<IPv4Address>().to_u32() & 0xff000000) != 0)
return Trustworthiness::PotentiallyTrustworthy;
} else if (origin.host().has<URL::IPv6Address>()) {
auto ipv6_address = origin.host().get<URL::IPv6Address>();
static constexpr URL::IPv6Address loopback { 0, 0, 0, 0, 0, 0, 0, 1 };
if (ipv6_address == loopback)
} else if (origin.host().has<IPv6Address>()) {
auto ipv6_address = origin.host().get<IPv6Address>();
if (ipv6_address == IPv6Address::loopback())
return Trustworthiness::PotentiallyTrustworthy;
}