1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
/*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Max Wipfli <mail@maxwipfli.ch>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/String.h>
#include <AK/StringView.h>
namespace AK {
// NOTE: The member variables cannot contain any percent encoded sequences.
// The URL parser automatically decodes those sequences and the the serialize() method will re-encode them as necessary.
class URL {
friend class URLParser;
public:
enum class PercentEncodeSet {
C0Control,
Fragment,
Query,
SpecialQuery,
Path,
Userinfo,
Component,
ApplicationXWWWFormUrlencoded,
EncodeURI
};
enum class ExcludeFragment {
No,
Yes
};
URL() = default;
URL(StringView const&);
URL(char const* string)
: URL(StringView(string))
{
}
URL(String const& string)
: URL(string.view())
{
}
bool const& is_valid() const { return m_valid; }
String const& scheme() const { return m_scheme; }
String const& protocol() const { return m_scheme; }
String const& username() const { return m_username; }
String const& password() const { return m_password; }
String const& host() const { return m_host; }
Vector<String> const& paths() const { return m_paths; }
String const& query() const { return m_query; }
String const& fragment() const { return m_fragment; }
u16 port() const { return m_port ? m_port : default_port_for_scheme(m_scheme); }
bool const& cannot_be_a_base_url() const { return m_cannot_be_a_base_url; }
bool includes_credentials() const { return !m_username.is_empty() || !m_password.is_empty(); }
bool is_special() const { return is_special_scheme(m_scheme); }
void set_scheme(String);
void set_protocol(String protocol) { set_scheme(move(protocol)); }
void set_username(String);
void set_password(String);
void set_host(String);
void set_port(u16);
void set_paths(Vector<String>);
void set_query(String);
void set_fragment(String);
void set_cannot_be_a_base_url(bool value) { m_cannot_be_a_base_url = value; }
void append_path(String path) { m_paths.append(path); }
String path() const;
String basename() const;
String serialize(ExcludeFragment = ExcludeFragment::No) const;
String serialize_for_display() const;
String to_string() const { return serialize(); }
bool equals(URL const& other, ExcludeFragment = ExcludeFragment::No) const;
URL complete_url(String const&) const;
bool data_payload_is_base64() const { return m_data_payload_is_base64; }
String const& data_mime_type() const { return m_data_mime_type; }
String const& data_payload() const { return m_data_payload; }
static URL create_with_url_or_path(String const&);
static URL create_with_file_scheme(String const& path, String const& fragment = {}, String const& hostname = {});
static URL create_with_file_protocol(String const& path, String const& fragment = {}) { return create_with_file_scheme(path, fragment); }
static URL create_with_data(String mime_type, String payload, bool is_base64 = false) { return URL(move(mime_type), move(payload), is_base64); };
static bool scheme_requires_port(StringView const&);
static u16 default_port_for_scheme(StringView const&);
static bool is_special_scheme(StringView const&);
static String percent_encode(StringView const& input, PercentEncodeSet set = PercentEncodeSet::Userinfo);
static String percent_decode(StringView const& input);
bool operator==(URL const& other) const { return equals(other, ExcludeFragment::No); }
private:
URL(String&& data_mime_type, String&& data_payload, bool payload_is_base64)
: m_valid(true)
, m_scheme("data")
, m_data_payload_is_base64(payload_is_base64)
, m_data_mime_type(move(data_mime_type))
, m_data_payload(move(data_payload))
{
}
bool compute_validity() const;
String serialize_data_url() const;
static void append_percent_encoded_if_necessary(StringBuilder&, u32 code_point, PercentEncodeSet set = PercentEncodeSet::Userinfo);
static void append_percent_encoded(StringBuilder&, u32 code_point);
bool m_valid { false };
String m_scheme;
String m_username;
String m_password;
String m_host;
// NOTE: If the port is the default port for the scheme, m_port should be 0.
u16 m_port { 0 };
String m_path;
Vector<String> m_paths;
String m_query;
String m_fragment;
bool m_cannot_be_a_base_url { false };
bool m_data_payload_is_base64 { false };
String m_data_mime_type;
String m_data_payload;
};
template<>
struct Formatter<URL> : Formatter<StringView> {
void format(FormatBuilder& builder, URL const& value)
{
Formatter<StringView>::format(builder, value.serialize());
}
};
template<>
struct Traits<URL> : public GenericTraits<URL> {
static unsigned hash(URL const& url) { return url.to_string().hash(); }
};
}
|