31 #ifndef PARSING_URI_HPP_ 32 #define PARSING_URI_HPP_ 34 #include "../Helper/Strings.hpp" 35 #include "../Main/Exception.hpp" 36 #include "../Wrapper/URI.hpp" 37 #include "../Wrapper/URIQueryList.hpp" 39 #include <uriparser/Uri.h> 42 #error "uriparser version 0.9.0 or higher required!" 49 #include <string_view> 81 [[nodiscard]] std::string
getSubUri()
const;
82 [[nodiscard]] std::string
getSubUri(
const std::vector<std::string>& args,
bool whiteList)
const;
95 bool parseLink(std::string_view uriToParse);
101 static std::string
escape(std::string_view
string,
bool plusSpace);
102 static std::string
unescape(std::string_view
string,
bool plusSpace);
103 static std::string
escapeUri(std::string_view uriToEscape);
104 static void makeAbsolute(std::string_view uriBase, std::vector<std::string>& uris);
140 bool crossDomain{
false};
147 static std::string textRangeToString(
const UriTextRangeA& range);
165 if(this->crossDomain) {
169 if(!(this->uri.
valid())) {
171 "Parsing::URI::isSameDomain():" 172 " No URI has been parsed" 176 return URI::textRangeToString(this->uri.
getc()->hostText) == this->domain;
197 return this->
getSubUri(std::vector<std::string>(),
false);
225 inline std::string
URI::getSubUri(
const std::vector<std::string>& args,
bool whiteList)
const {
226 if(this->domain.empty()) {
228 "Parsing::URI::getSubUri():" 229 " No domain has been specified or parsed" 233 if(!(this->uri.
valid())) {
235 "Parsing::URI::getSubUri():" 236 " No URI has been parsed" 241 const UriQueryListA * queryNext{
nullptr};
246 if(this->uri.
getc()->query.first != this->uri.
getc()->query.afterLast) {
248 uriDissectQueryMallocA(
251 this->uri.
getc()->query.first,
252 this->uri.
getc()->query.afterLast
256 queryNext = queryList.
getc();
258 while(queryNext !=
nullptr) {
276 queries += queryNext->key;
278 if(queryNext->value !=
nullptr) {
279 queries +=
"=" + std::string(queryNext->value);
285 queryNext = queryNext->next;
290 if(!queries.empty()) {
295 UriPathSegmentStructA * nextSegment = this->uri.
getc()->pathHead;
299 if(this->crossDomain) {
300 result = URI::textRangeToString(this->uri.
getc()->hostText);
307 while(nextSegment !=
nullptr) {
308 result +=
"/" +
URI::unescape(URI::textRangeToString(nextSegment->text),
false);
310 nextSegment = nextSegment->next;
314 if(!queries.empty()) {
315 result +=
"?" + queries;
329 if(currentDomain.empty()) {
330 this->domain.clear();
332 this->crossDomain =
true;
361 std::string parsedSubUri;
364 if(this->crossDomain) {
365 const auto domainEnd{baseUri.find(
'/')};
367 if(domainEnd == std::string::npos) {
375 parsedSubUri = baseUri.substr(domainEnd);
379 parsedSubUri = baseUri;
383 if(this->domain.empty()) {
385 "Parsing::URI::setCurrentOrigin():" 386 " No domain has been specified or parsed" 390 if(parsedSubUri.empty()) {
392 "Parsing::URI::setCurrentOrigin():" 393 " Parsed sub-URI is empty" 397 if(parsedSubUri.at(0) !=
'/') {
399 "Parsing::URI::setCurrentOrigin():" 400 " Parsed sub-URI does not start with slash ('/')" 408 this->current =
"https://" + this->domain + this->subUri;
414 const char * errorPos{
nullptr};
415 const auto errorCode{
418 this->current.c_str(),
423 if(errorCode != URI_SUCCESS) {
424 const std::string end(
426 baseUri.size() - (errorPos - baseUri.data())
429 std::string errorString{
430 "Parsing::URI::setCurrentOrigin():" 431 " URI Parser error #" 434 errorString += std::to_string(errorCode);
435 errorString +=
": '";
437 if(end.size() < this->current.size()) {
438 errorString += this->current.substr(0, this->current.size() - end.size());
439 errorString +=
"[!!!]";
443 errorString += this->current +
"[!!!]";
484 if(this->domain.empty()) {
486 "Parsing::URI::parseLink():" 487 " No domain has been specified or parsed" 491 if(this->subUri.empty()) {
493 "Parsing::URI::parseLink():" 494 " No sub-URI has been parsed" 499 std::string linkCopy(uriToParse);
502 const auto end{linkCopy.find(
'#')};
504 if(end != std::string::npos && linkCopy.size() > end) {
506 linkCopy = linkCopy.substr(0, end);
519 if(linkCopy.empty()) {
533 this->link.swap(linkCopy);
536 const char * errorPos{
nullptr};
537 const auto errorCode{
539 relativeSource.
get(),
545 if(errorCode != URI_SUCCESS) {
546 const std::string rest(errorPos);
548 std::string errorString{
549 "Parsing::URI::parseLink():" 550 " URI Parser error #" 553 errorString += std::to_string(errorCode);
554 errorString +=
": '";
556 if(rest.size() < this->link.size()) {
557 errorString += this->link.substr(0, this->link.size() - rest.size());
558 errorString +=
"[!!!]";
562 errorString += this->link;
563 errorString +=
"[!!!]";
575 relativeSource.
getc(),
577 URI_RESOLVE_IDENTICAL_SCHEME_COMPAT
581 "Parsing::URI::parseLink():" 582 " Reference resolving failed for '" 583 + URI::toString(relativeSource)
589 const auto dirtyParts{
590 uriNormalizeSyntaxMaskRequiredA(
596 dirtyParts != URI_NORMALIZED
597 && uriNormalizeSyntaxExA(
603 "Parsing::URI::parseLink():" 604 " Normalizing failed for '" 605 + URI::toString(this->uri)
622 inline std::string
URI::escape(std::string_view
string,
bool plusSpace) {
625 std::make_unique<char[]>(
632 string.data() +
string.size(),
634 static_cast<UriBool
>(plusSpace),
638 return std::string(cString.get());
653 return std::string();
658 std::make_unique<char[]>(
663 for(std::size_t n{}; n <
string.size(); ++n) {
664 cString[n] =
string.at(n);
667 cString[
string.size()] =
'\0';
669 uriUnescapeInPlaceExA(
671 static_cast<UriBool
>(plusSpace),
675 return std::string(cString.get());
693 while(pos < uriToEscape.size()) {
694 auto end{uriToEscape.find_first_of(
";/?:@=&#%", pos)};
696 if(end == std::string::npos) {
697 end = uriToEscape.size();
701 const std::string part(uriToEscape, pos, end - pos);
706 if(end < uriToEscape.size()) {
707 result += uriToEscape.at(end);
741 const char * errorPos{
nullptr};
742 const auto errorCode{
743 uriParseSingleUriExA(
746 uriBase.data() + uriBase.size(),
751 if(errorCode != URI_SUCCESS) {
752 const std::string end(
754 uriBase.size() - (errorPos - uriBase.data())
757 std::string errorString{
758 "Parsing::URI::makeAbsolute():" 759 " URI Parser error #" 762 errorString += std::to_string(errorCode);
763 errorString +=
": '";
765 if(end.size() < uriBase.size()) {
766 errorString += uriBase.substr(0, uriBase.size() - end.size());
767 errorString +=
"[!!!]";
771 errorString += uriBase;
772 errorString +=
"[!!!]";
781 std::vector<std::string> result;
783 for(
const auto& relUri : uris) {
800 if(uriParseSingleUriA(
801 relativeSource.
get(),
812 relativeSource.
getc(),
814 URI_RESOLVE_IDENTICAL_SCHEME_COMPAT
821 const auto dirtyParts{
822 uriNormalizeSyntaxMaskRequiredA(
828 dirtyParts != URI_NORMALIZED
829 && uriNormalizeSyntaxExA(
839 result.emplace_back(URI::toString(absoluteDest));
847 inline std::string URI::textRangeToString(
const UriTextRangeA& range) {
849 range.first ==
nullptr 850 || *(range.first) == 0
851 || range.afterLast ==
nullptr 852 || range.afterLast <= range.first
854 return std::string();
857 return std::string(range.first, range.afterLast - range.first);
861 inline std::string URI::toString(
const Wrapper::URI& src) {
863 return std::string();
869 uriToStringCharsRequiredA(
875 "Parsing::URI::toString():" 876 " Could not convert URI to string," 877 " because uriToStringCharsRequiredA(...)" 884 std::make_unique<char[]>(
898 "Parsing::URI::toString():" 899 " Could not convert URI to string," 900 " because uriToStringA(...) failed" 904 return std::string(uriCString.get());
void create()
Creates a new and empty URI.
Definition: URI.hpp:160
static void makeAbsolute(std::string_view uriBase, std::vector< std::string > &uris)
Public static helper function making a set of (possibly) relative URIs absolute.
Definition: URI.hpp:734
const UriUriA * getc() const noexcept
Gets a const pointer to the underlying URI structure.
Definition: URI.hpp:139
static std::string unescape(std::string_view string, bool plusSpace)
Public static helper function URI-unescaping a string.
Definition: URI.hpp:651
#define MAIN_EXCEPTION_CLASS()
Macro used to easily define classes for general exceptions.
Definition: Exception.hpp:50
void encodePercentage(std::string &stringToEncode)
Encodes percentage signs that are not followed by a two-digit hexadecimal number with %25...
Definition: Strings.hpp:977
void trim(std::string &stringToTrim)
Removes whitespaces around a string.
Definition: Strings.hpp:360
void setCurrentDomain(std::string_view currentDomain)
Sets the current domain.
Definition: URI.hpp:328
UriQueryListA ** getPtr() noexcept
Gets a pointer to the pointer containing the address of the underlying query list.
Definition: URIQueryList.hpp:147
const UriQueryListA * getc() const noexcept
Gets a const pointer to the underlying query list.
Definition: URIQueryList.hpp:136
Class for URI exceptions.
Definition: URI.hpp:130
void setCurrentOrigin(std::string_view baseUri)
Sets the current origin.
Definition: URI.hpp:360
bool isSameDomain() const
Checks whether the parsed URI links to the current domain.
Definition: URI.hpp:164
static std::string escape(std::string_view string, bool plusSpace)
Public static helper function URI-escaping a string.
Definition: URI.hpp:622
bool valid() const noexcept
Checks whether the URI is valid.
Definition: URI.hpp:148
Namespace for classes parsing HTML, URIs, and XML.
Definition: HTML.hpp:42
static std::string escapeUri(std::string_view uriToEscape)
Public static helper function escaping a URI, but leacing reserved characters intact.
Definition: URI.hpp:689
bool parseLink(std::string_view uriToParse)
Parses a link, either abolute or into a sub-URI.
Definition: URI.hpp:479
std::string getSubUri() const
Gets the sub-URI for the current URI.
Definition: URI.hpp:196
RAII wrapper for the RFC 3986 URI structure used by uriparser.
Definition: URI.hpp:57
UriUriA * get() noexcept
Gets a pointer to the underlying URI structure.
Definition: URI.hpp:131
Parser for RFC 3986 URIs that can also analyze their relationships with each other.
Definition: URI.hpp:75
void clear()
Frees the current URI.
Definition: URI.hpp:172
constexpr auto maxEscapedCharLength
Maximum length of a URL-escaped character.
Definition: URI.hpp:62
RAII wrapper for the URI query list used by uriparser.
Definition: URIQueryList.hpp:56