Files
bx/src/url.cpp
Бранимир Караџић 13c40f9a6e Happy New Year!
2025-01-13 15:45:25 -08:00

158 lines
3.2 KiB
C++

/*
* Copyright 2011-2025 Branimir Karadzic. All rights reserved.
* License: https://github.com/bkaradzic/bnet#license-bsd-2-clause
*/
#include <bx/url.h>
namespace bx
{
UrlView::UrlView()
{
}
void UrlView::clear()
{
for (uint32_t ii = 0; ii < Count; ++ii)
{
m_tokens[ii].clear();
}
}
bool UrlView::parse(const StringView& _url)
{
clear();
const char* term = _url.getTerm();
StringView schemeEnd = strFind(_url, "://");
const char* hostStart = !schemeEnd.isEmpty() ? schemeEnd.getTerm() : _url.getPtr();
StringView path = strFind(StringView(hostStart, term), '/');
if (schemeEnd.isEmpty()
&& path.isEmpty() )
{
return false;
}
if (!schemeEnd.isEmpty()
&& (path.isEmpty() || path.getPtr() > schemeEnd.getPtr() ) )
{
const StringView scheme(_url.getPtr(), schemeEnd.getPtr() );
if (!isAlpha(scheme) )
{
return false;
}
m_tokens[Scheme].set(scheme);
}
if (!path.isEmpty() )
{
path.set(path.getPtr(), term);
const StringView query = strFind(path, '?');
const StringView fragment = strFind(path, '#');
if (!fragment.isEmpty()
&& fragment.getPtr() < query.getPtr() )
{
return false;
}
m_tokens[Path].set(path.getPtr()
, !query.isEmpty() ? query.getPtr()
: !fragment.isEmpty() ? fragment.getPtr()
: term
);
if (!query.isEmpty() )
{
m_tokens[Query].set(query.getPtr()+1
, !fragment.isEmpty() ? fragment.getPtr()
: term
);
}
if (!fragment.isEmpty() )
{
m_tokens[Fragment].set(fragment.getPtr()+1, term);
}
term = path.getPtr();
}
const StringView userPassEnd = strFind(StringView(hostStart, term), '@');
const char* userPassStart = !userPassEnd.isEmpty() ? hostStart : NULL;
hostStart = !userPassEnd.isEmpty() ? userPassEnd.getPtr()+1 : hostStart;
const StringView portStart = strFind(StringView(hostStart, term), ':');
m_tokens[Host].set(hostStart, !portStart.isEmpty() ? portStart.getPtr() : term);
if (!portStart.isEmpty())
{
m_tokens[Port].set(portStart.getPtr()+1, term);
}
if (NULL != userPassStart)
{
StringView passStart = strFind(StringView(userPassStart, userPassEnd.getPtr() ), ':');
m_tokens[UserName].set(userPassStart
, !passStart.isEmpty() ? passStart.getPtr()
: userPassEnd.getPtr()
);
if (!passStart.isEmpty() )
{
m_tokens[Password].set(passStart.getPtr()+1, userPassEnd.getPtr() );
}
}
return true;
}
const StringView& UrlView::get(Enum _token) const
{
return m_tokens[_token];
}
static char toHex(char _nible)
{
return "0123456789ABCDEF"[_nible&0xf];
}
// https://secure.wikimedia.org/wikipedia/en/wiki/URL_encoding
void urlEncode(char* _out, uint32_t _max, const StringView& _str)
{
_max--; // need space for zero terminator
const char* str = _str.getPtr();
const char* term = _str.getTerm();
uint32_t ii = 0;
for (char ch = *str++
; str <= term && ii < _max
; ch = *str++
)
{
if (isAlphaNum(ch)
|| ch == '-'
|| ch == '_'
|| ch == '.'
|| ch == '~')
{
_out[ii++] = ch;
}
else if (ii+3 < _max)
{
_out[ii++] = '%';
_out[ii++] = toHex(ch>>4);
_out[ii++] = toHex(ch);
}
}
_out[ii] = '\0';
}
} // namespace bx