Added URL type.
This commit is contained in:
parent
8002e1f1f8
commit
99f5987f4b
169
source/mijin/net/url.hpp
Normal file
169
source/mijin/net/url.hpp
Normal file
@ -0,0 +1,169 @@
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(MIJIN_NET_URL_HPP_INCLUDED)
|
||||
#define MIJIN_NET_URL_HPP_INCLUDED 1
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include "../util/string.hpp"
|
||||
|
||||
namespace mijin
|
||||
{
|
||||
template<typename TChar, typename TTraits = std::char_traits<TChar>, typename TAllocator = std::allocator<TChar>>
|
||||
class URLBase
|
||||
{
|
||||
public:
|
||||
using string_t = std::basic_string<TChar, TTraits, TAllocator>;
|
||||
using string_view_t = std::basic_string_view<TChar, TTraits>;
|
||||
private:
|
||||
string_t base_;
|
||||
string_view_t scheme_;
|
||||
string_view_t userinfo_;
|
||||
string_view_t host_;
|
||||
string_view_t path_;
|
||||
string_view_t query_;
|
||||
string_view_t fragment_;
|
||||
string_view_t pathQueryFragment_;
|
||||
std::uint16_t port_ = 0;
|
||||
public:
|
||||
constexpr URLBase() noexcept = default;
|
||||
constexpr URLBase(const URLBase&) = default;
|
||||
constexpr URLBase(URLBase&&) noexcept = default;
|
||||
constexpr URLBase(string_t base) noexcept : base_(std::move(base)) { parse(); }
|
||||
constexpr URLBase(string_view_t base) : URLBase(string_t(base.begin(), base.end())) {}
|
||||
constexpr URLBase(const TChar* base) : URLBase(string_t(base)) {}
|
||||
|
||||
constexpr URLBase& operator=(const URLBase&) = default;
|
||||
constexpr URLBase& operator=(URLBase&&) noexcept = default;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept { return !base_.empty(); }
|
||||
[[nodiscard]] constexpr string_view_t getScheme() const noexcept { return scheme_; }
|
||||
[[nodiscard]] constexpr string_view_t getUserInfo() const noexcept { return userinfo_; }
|
||||
[[nodiscard]] constexpr string_view_t getHost() const noexcept { return host_; }
|
||||
[[nodiscard]] constexpr string_view_t getPath() const noexcept { return path_; }
|
||||
[[nodiscard]] constexpr string_view_t getQuery() const noexcept { return query_; }
|
||||
[[nodiscard]] constexpr string_view_t getFragment() const noexcept { return fragment_; }
|
||||
[[nodiscard]] constexpr string_view_t getPathQueryFragment() const noexcept { return pathQueryFragment_; }
|
||||
[[nodiscard]] constexpr std::uint16_t getPort() const noexcept { return port_; }
|
||||
|
||||
|
||||
constexpr void clear() noexcept;
|
||||
private:
|
||||
constexpr void parse() noexcept;
|
||||
constexpr bool parseAuthority(string_view_t authority) noexcept;
|
||||
};
|
||||
|
||||
using URL = URLBase<char>;
|
||||
|
||||
template<typename TChar, typename TTraits, typename TAllocator>
|
||||
constexpr void URLBase<TChar, TTraits, TAllocator>::clear() noexcept
|
||||
{
|
||||
base_.clear();
|
||||
scheme_ = {};
|
||||
userinfo_ = {};
|
||||
host_ = {};
|
||||
path_ = {};
|
||||
query_ = {};
|
||||
fragment_ = {};
|
||||
port_ = 0;
|
||||
}
|
||||
|
||||
template<typename TChar, typename TTraits, typename TAllocator>
|
||||
constexpr void URLBase<TChar, TTraits, TAllocator>::parse() noexcept
|
||||
{
|
||||
if (base_.empty())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
string_view_t toParse = base_;
|
||||
typename string_view_t::size_type pos = toParse.find(':');
|
||||
if (pos == string_t::npos)
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
scheme_ = toParse.substr(0, pos);
|
||||
toParse = toParse.substr(pos + 1);
|
||||
|
||||
if (!toParse.starts_with("//"))
|
||||
{
|
||||
userinfo_ = host_ = {};
|
||||
port_ = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
toParse = toParse.substr(2); // skip the slashes
|
||||
pos = toParse.find('/');
|
||||
if (!parseAuthority(toParse.substr(0, pos)))
|
||||
{
|
||||
clear();
|
||||
return;
|
||||
}
|
||||
if (pos == string_view_t::npos)
|
||||
{
|
||||
path_ = query_ = fragment_ = pathQueryFragment_ = {};
|
||||
return;
|
||||
}
|
||||
toParse = toParse.substr(pos);
|
||||
}
|
||||
pathQueryFragment_ = toParse;
|
||||
pos = toParse.find('#');
|
||||
if (pos == string_view_t::npos)
|
||||
{
|
||||
fragment_ = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
fragment_ = toParse.substr(pos + 1);
|
||||
toParse = toParse.substr(0, pos);
|
||||
}
|
||||
pos = toParse.find('?');
|
||||
if (pos == string_view_t::npos)
|
||||
{
|
||||
query_ = {};
|
||||
path_ = toParse;
|
||||
}
|
||||
else
|
||||
{
|
||||
query_ = toParse.substr(pos + 1);
|
||||
path_ = toParse.substr(0, pos);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename TChar, typename TTraits, typename TAllocator>
|
||||
constexpr bool URLBase<TChar, TTraits, TAllocator>::parseAuthority(string_view_t authority) noexcept
|
||||
{
|
||||
string_view_t toParse = authority;
|
||||
typename string_view_t::size_type pos = toParse.find('@');
|
||||
if (pos == string_view_t::npos)
|
||||
{
|
||||
userinfo_ = {};
|
||||
}
|
||||
else
|
||||
{
|
||||
userinfo_ = toParse.substr(0, pos);
|
||||
toParse = toParse.substr(pos + 1);
|
||||
}
|
||||
pos = toParse.find(':'); // TODO: IPv6
|
||||
if (pos == string_view_t::npos)
|
||||
{
|
||||
port_ = 0;
|
||||
host_ = toParse;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!toNumber(toParse.substr(pos + 1), port_))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
host_ = toParse.substr(0, pos);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif // !defined(MIJIN_NET_URL_HPP_INCLUDED)
|
Loading…
x
Reference in New Issue
Block a user