From 389eb1b693d592e05d54af8b37858f8cf37eeffa Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 26 Apr 2020 22:48:54 +0200 Subject: [PATCH] AK: Teach URL how to parse data: URLs :^) --- AK/URL.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++--- AK/URL.h | 7 +++++++ 2 files changed, 58 insertions(+), 3 deletions(-) diff --git a/AK/URL.cpp b/AK/URL.cpp index 8c77031b88..7e690ff68b 100644 --- a/AK/URL.cpp +++ b/AK/URL.cpp @@ -54,6 +54,8 @@ bool URL::parse(const StringView& string) InPath, InQuery, InFragment, + InDataMimeType, + InDataPayload, }; Vector buffer; @@ -75,30 +77,39 @@ bool URL::parse(const StringView& string) while (index < string.length()) { switch (state) { - case State::InProtocol: + case State::InProtocol: { if (is_valid_protocol_character(peek())) { buffer.append(consume()); continue; } if (consume() != ':') return false; + + m_protocol = String::copy(buffer); + + if (m_protocol == "data") { + buffer.clear(); + state = State::InDataMimeType; + continue; + } + if (consume() != '/') return false; if (consume() != '/') return false; if (buffer.is_empty()) return false; - m_protocol = String::copy(buffer); if (m_protocol == "http") m_port = 80; else if (m_protocol == "https") m_port = 443; - buffer.clear(); if (m_protocol == "file") state = State::InPath; else state = State::InHostname; + buffer.clear(); continue; + } case State::InHostname: if (is_valid_hostname_character(peek())) { buffer.append(consume()); @@ -160,6 +171,41 @@ bool URL::parse(const StringView& string) case State::InFragment: buffer.append(consume()); continue; + case State::InDataMimeType: { + if (peek() != ';' && peek() != ',') { + buffer.append(consume()); + continue; + } + + m_data_mime_type = String::copy(buffer); + buffer.clear(); + + if (peek() == ';') { + consume(); + if (consume() != 'b') + return false; + if (consume() != 'a') + return false; + if (consume() != 's') + return false; + if (consume() != 'e') + return false; + if (consume() != '6') + return false; + if (consume() != '4') + return false; + m_data_payload_is_base64 = true; + } + + if (consume() != ',') + return false; + + state = State::InDataPayload; + break; + } + case State::InDataPayload: + buffer.append(consume()); + break; } } if (state == State::InHostname) { @@ -177,6 +223,8 @@ bool URL::parse(const StringView& string) m_query = String::copy(buffer); if (state == State::InFragment) m_fragment = String::copy(buffer); + if (state == State::InDataPayload) + m_data_payload = String::copy(buffer); if (m_query.is_null()) m_query = ""; if (m_fragment.is_null()) diff --git a/AK/URL.h b/AK/URL.h index be8bc05c93..4c47f0368e 100644 --- a/AK/URL.h +++ b/AK/URL.h @@ -65,6 +65,10 @@ public: URL complete_url(const String&) const; + bool data_payload_is_base64() const { return m_data_payload_is_base64; } + const String& data_mime_type() const { return m_data_mime_type; } + const String& data_payload() const { return m_data_payload; } + static URL create_with_url_or_path(const String& url_or_path); static URL create_with_file_protocol(const String& path); @@ -74,11 +78,14 @@ private: bool m_valid { false }; u16 m_port { 80 }; + bool m_data_payload_is_base64 { false }; String m_protocol; String m_host; String m_path; String m_query; String m_fragment; + String m_data_mime_type; + String m_data_payload; }; }