mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-02-26 09:41:29 -05:00
Add naif URL manipulation class RsUrl
Use RsUrl to convert sockaddre_storage from/to string
This commit is contained in:
parent
dedfcb2b60
commit
923c383a13
@ -550,7 +550,8 @@ HEADERS += util/folderiterator.h \
|
||||
util/rstime.h \
|
||||
util/stacktrace.h \
|
||||
util/rsdeprecate.h \
|
||||
util/cxx11retrocompat.h
|
||||
util/cxx11retrocompat.h \
|
||||
util/rsurl.h
|
||||
|
||||
SOURCES += ft/ftchunkmap.cc \
|
||||
ft/ftcontroller.cc \
|
||||
@ -695,7 +696,8 @@ SOURCES += util/folderiterator.cc \
|
||||
util/rsrandom.cc \
|
||||
util/rstickevent.cc \
|
||||
util/rsrecogn.cc \
|
||||
util/rstime.cc
|
||||
util/rstime.cc \
|
||||
util/rsurl.cc
|
||||
|
||||
|
||||
upnp_miniupnpc {
|
||||
|
@ -133,6 +133,7 @@ bool sockaddr_storage_sameip(const struct sockaddr_storage &addr, const struct s
|
||||
|
||||
// string,
|
||||
std::string sockaddr_storage_tostring(const struct sockaddr_storage &addr);
|
||||
bool sockaddr_storage_fromString(const std::string& str, sockaddr_storage &addr);
|
||||
std::string sockaddr_storage_familytostring(const struct sockaddr_storage &addr);
|
||||
std::string sockaddr_storage_iptostring(const struct sockaddr_storage &addr);
|
||||
std::string sockaddr_storage_porttostring(const struct sockaddr_storage &addr);
|
||||
|
@ -24,6 +24,8 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#include "util/rsurl.h"
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <cstdlib>
|
||||
@ -491,27 +493,32 @@ bool sockaddr_storage_sameip(const struct sockaddr_storage &addr, const struct s
|
||||
|
||||
std::string sockaddr_storage_tostring(const struct sockaddr_storage &addr)
|
||||
{
|
||||
std::string output;
|
||||
output += sockaddr_storage_familytostring(addr);
|
||||
RsUrl url;
|
||||
|
||||
switch(addr.ss_family)
|
||||
{
|
||||
case AF_INET:
|
||||
output += "=";
|
||||
output += sockaddr_storage_iptostring(addr);
|
||||
output += ":";
|
||||
output += sockaddr_storage_porttostring(addr);
|
||||
url.setScheme("ipv4");
|
||||
break;
|
||||
case AF_INET6:
|
||||
output += "=[";
|
||||
output += sockaddr_storage_iptostring(addr);
|
||||
output += "]:";
|
||||
output += sockaddr_storage_porttostring(addr);
|
||||
url.setScheme("ipv6");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
return "INVALID_IP";
|
||||
}
|
||||
return output;
|
||||
|
||||
url.setHost(sockaddr_storage_iptostring(addr))
|
||||
.setPort(sockaddr_storage_port(addr));
|
||||
|
||||
return url.toString();
|
||||
}
|
||||
|
||||
bool sockaddr_storage_fromString(const std::string& str, sockaddr_storage &addr)
|
||||
{
|
||||
RsUrl url(str);
|
||||
bool valid = sockaddr_storage_inet_pton(addr, url.host());
|
||||
if(url.hasPort()) sockaddr_storage_setport(addr, url.port());
|
||||
return valid;
|
||||
}
|
||||
|
||||
void sockaddr_storage_dump(const sockaddr_storage & addr, std::string * outputString)
|
||||
|
258
libretroshare/src/util/rsurl.cc
Normal file
258
libretroshare/src/util/rsurl.cc
Normal file
@ -0,0 +1,258 @@
|
||||
/*
|
||||
* RetroShare
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
//#include "util/rsurl.h"
|
||||
#include "rsurl.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
|
||||
using namespace std;
|
||||
|
||||
RsUrl::RsUrl() : mPort(0), mHasPort(false) {}
|
||||
|
||||
RsUrl::RsUrl(const std::string& urlStr) : mPort(0), mHasPort(false)
|
||||
{ fromString(urlStr); }
|
||||
|
||||
RsUrl& RsUrl::fromString(const std::string& urlStr)
|
||||
{
|
||||
size_t urlSize = urlStr.size();
|
||||
|
||||
size_t schemeEndI = urlStr.find(schemeSeparator);
|
||||
if(schemeEndI == string::npos)
|
||||
{
|
||||
mScheme = urlStr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
mScheme = urlStr.substr(0, schemeEndI);
|
||||
|
||||
size_t hostBeginI = schemeEndI + 3;
|
||||
if(hostBeginI >= urlSize) return *this;
|
||||
|
||||
bool hasSquareBr = (urlStr[hostBeginI] == ipv6WrapOpen[0]);
|
||||
size_t hostEndI;
|
||||
if(hasSquareBr)
|
||||
{
|
||||
if(++hostBeginI >= urlSize) return *this;
|
||||
hostEndI = urlStr.find(ipv6WrapClose, hostBeginI);
|
||||
mHost = urlStr.substr(hostBeginI, hostEndI - hostBeginI - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
hostEndI = urlStr.find(pathSeparator, hostBeginI);
|
||||
hostEndI = min(hostEndI, urlStr.find(portSeparator, hostBeginI));
|
||||
hostEndI = min(hostEndI, urlStr.find(querySeparator, hostBeginI));
|
||||
hostEndI = min(hostEndI, urlStr.find(fragmentSeparator, hostBeginI));
|
||||
|
||||
mHost = urlStr.substr(hostBeginI, hostEndI - hostBeginI);
|
||||
if(hostEndI == string::npos) return *this;
|
||||
}
|
||||
|
||||
mHasPort = (sscanf(&urlStr[hostEndI], ":%hu", &mPort) == 1);
|
||||
|
||||
size_t pathBeginI = urlStr.find(pathSeparator, hostEndI);
|
||||
size_t pathEndI = string::npos;
|
||||
if(pathBeginI != string::npos)
|
||||
{
|
||||
pathEndI = urlStr.find(querySeparator, pathBeginI);
|
||||
pathEndI = min(pathEndI, urlStr.find(fragmentSeparator, pathBeginI));
|
||||
mPath = UrlDecode(urlStr.substr(pathBeginI, pathEndI - pathBeginI));
|
||||
if(pathEndI == string::npos) return *this;
|
||||
}
|
||||
|
||||
size_t queryBeginI = urlStr.find(querySeparator, schemeEndI);
|
||||
size_t queryEndI = urlStr.find(fragmentSeparator, schemeEndI);
|
||||
if(queryBeginI != string::npos)
|
||||
{
|
||||
string qStr = urlStr.substr(queryBeginI+1, queryEndI-queryBeginI-1);
|
||||
|
||||
size_t kPos = 0;
|
||||
size_t assPos = qStr.find(queryAssign);
|
||||
do
|
||||
{
|
||||
size_t vEndPos = qStr.find(queryFieldSep, assPos);
|
||||
mQuery.insert( std::make_pair( qStr.substr(kPos, assPos-kPos),
|
||||
UrlDecode(qStr.substr(assPos+1, vEndPos-assPos-1))
|
||||
) );
|
||||
kPos = vEndPos+1;
|
||||
assPos = qStr.find(queryAssign, vEndPos);
|
||||
}
|
||||
while(assPos != string::npos);
|
||||
|
||||
if(queryEndI == string::npos) return *this;
|
||||
}
|
||||
|
||||
size_t fragmentBeginI = urlStr.find(fragmentSeparator, schemeEndI);
|
||||
if(fragmentBeginI != string::npos)
|
||||
mFragment = UrlDecode(urlStr.substr(++fragmentBeginI));
|
||||
}
|
||||
|
||||
std::string RsUrl::toString() const
|
||||
{
|
||||
std::string urlStr(mScheme);
|
||||
urlStr += schemeSeparator;
|
||||
|
||||
if(!mHost.empty())
|
||||
{
|
||||
if(mHost.find(ipv6Separator) != string::npos &&
|
||||
mHost[0] != ipv6WrapOpen[0] )
|
||||
urlStr += ipv6WrapOpen + mHost + ipv6WrapClose;
|
||||
else urlStr += mHost;
|
||||
}
|
||||
|
||||
if(mHasPort) urlStr += portSeparator + std::to_string(mPort);
|
||||
|
||||
urlStr += UrlEncode(mPath, pathSeparator);
|
||||
|
||||
bool hasQuery = !mQuery.empty();
|
||||
if(hasQuery) urlStr += querySeparator;
|
||||
for(auto&& kv : mQuery)
|
||||
{
|
||||
urlStr += kv.first;
|
||||
urlStr += queryAssign;
|
||||
urlStr += UrlEncode(kv.second);
|
||||
urlStr += queryFieldSep;
|
||||
}
|
||||
if(hasQuery) urlStr.pop_back();
|
||||
|
||||
if(!mFragment.empty()) urlStr += fragmentSeparator + UrlEncode(mFragment);
|
||||
|
||||
return urlStr;
|
||||
}
|
||||
|
||||
const std::string& RsUrl::scheme() const { return mScheme; }
|
||||
RsUrl& RsUrl::setScheme(const std::string& scheme)
|
||||
{
|
||||
mScheme = scheme;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string& RsUrl::host() const { return mHost; }
|
||||
RsUrl& RsUrl::setHost(const std::string& host)
|
||||
{
|
||||
mHost = host;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool RsUrl::hasPort() const { return mHasPort; }
|
||||
|
||||
uint16_t RsUrl::port(uint16_t def) const
|
||||
{
|
||||
if(mHasPort) return mPort;
|
||||
return def;
|
||||
}
|
||||
|
||||
RsUrl& RsUrl::setPort(uint16_t port)
|
||||
{
|
||||
mPort = port;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string& RsUrl::path() const { return mPath; }
|
||||
RsUrl& RsUrl::setPath(const std::string& path)
|
||||
{
|
||||
mPath = path;
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string>& RsUrl::query() const
|
||||
{ return mQuery; }
|
||||
RsUrl& RsUrl::setQuery(const std::map<std::string, std::string>& query)
|
||||
{
|
||||
mQuery = query;
|
||||
return *this;
|
||||
}
|
||||
RsUrl& RsUrl::setQueryKV(const std::string& key, const std::string& value)
|
||||
{
|
||||
mQuery.insert(std::make_pair(key, value));
|
||||
return *this;
|
||||
}
|
||||
RsUrl& RsUrl::delQueryK(const std::string& key)
|
||||
{
|
||||
mQuery.erase(key);
|
||||
return *this;
|
||||
}
|
||||
|
||||
const std::string& RsUrl::fragment() const { return mFragment; }
|
||||
RsUrl& RsUrl::setFragment(const std::string& fragment)
|
||||
{
|
||||
mFragment = fragment;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*static*/ std::string RsUrl::UrlEncode( const std::string& str,
|
||||
const std::string& ignore )
|
||||
{
|
||||
ostringstream escaped;
|
||||
escaped.fill('0');
|
||||
escaped << hex;
|
||||
|
||||
for (string::value_type c : str)
|
||||
{
|
||||
// Keep alphanumeric and other accepted characters intact
|
||||
if ( isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~'
|
||||
|| ignore.find(c) != string::npos )
|
||||
{
|
||||
escaped << c;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Any other characters are percent-encoded
|
||||
escaped << uppercase;
|
||||
escaped << '%' << setw(2) << int((unsigned char) c);
|
||||
escaped << nouppercase;
|
||||
}
|
||||
|
||||
return escaped.str();
|
||||
}
|
||||
|
||||
/*static*/ std::string RsUrl::UrlDecode(const std::string& str)
|
||||
{
|
||||
ostringstream decoded;
|
||||
|
||||
size_t len = str.size();
|
||||
size_t boundary = len-2; // % Encoded char must be at least 2 hex char
|
||||
for (size_t i = 0; i < len; ++i)
|
||||
{
|
||||
|
||||
if(str[i] == '%' && i < boundary)
|
||||
{
|
||||
decoded << static_cast<char>(stoi(str.substr(++i, 2), 0, 16));
|
||||
++i;
|
||||
}
|
||||
else decoded << str[i];
|
||||
}
|
||||
|
||||
return decoded.str();
|
||||
}
|
||||
|
||||
/*static*/ const std::string RsUrl::schemeSeparator("://");
|
||||
/*static*/ const std::string RsUrl::ipv6WrapOpen("[");
|
||||
/*static*/ const std::string RsUrl::ipv6Separator(":");
|
||||
/*static*/ const std::string RsUrl::ipv6WrapClose("]");
|
||||
/*static*/ const std::string RsUrl::portSeparator(":");
|
||||
/*static*/ const std::string RsUrl::pathSeparator("/");
|
||||
/*static*/ const std::string RsUrl::querySeparator("?");
|
||||
/*static*/ const std::string RsUrl::queryAssign("=");
|
||||
/*static*/ const std::string RsUrl::queryFieldSep("&");
|
||||
/*static*/ const std::string RsUrl::fragmentSeparator("#");
|
||||
|
101
libretroshare/src/util/rsurl.h
Normal file
101
libretroshare/src/util/rsurl.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
/*
|
||||
* RetroShare
|
||||
* Copyright (C) 2018 Gioacchino Mazzurco <gio@eigenlab.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
/**
|
||||
* Very simplistic and minimal URL helper class for RetroShare, after looking
|
||||
* for a small and self-contained C/C++ URL parsing and manipulation library,
|
||||
* haven't found nothing satisfactory except for implementation like QUrl that
|
||||
* rely on bigger library.
|
||||
* ATM this implementation is not standard compliant and doesn't aim to be.
|
||||
* Improvements to this are welcome.
|
||||
*
|
||||
* Anyway this should support most common URLs of the form
|
||||
* scheme://host[:port][/path][?query][#fragment]
|
||||
*/
|
||||
struct RsUrl
|
||||
{
|
||||
RsUrl();
|
||||
RsUrl(const std::string& urlStr);
|
||||
|
||||
RsUrl& fromString(const std::string& urlStr);
|
||||
std::string toString() const;
|
||||
|
||||
const std::string& scheme() const;
|
||||
RsUrl& setScheme(const std::string& scheme);
|
||||
|
||||
const std::string& host() const;
|
||||
RsUrl& setHost(const std::string& host);
|
||||
|
||||
bool hasPort() const;
|
||||
uint16_t port(uint16_t def = 0) const;
|
||||
RsUrl& setPort(uint16_t port);
|
||||
|
||||
const std::string& path() const;
|
||||
RsUrl& setPath(const std::string& path);
|
||||
|
||||
const std::map<std::string, std::string>& query() const;
|
||||
RsUrl& setQuery(const std::map<std::string, std::string>& query);
|
||||
RsUrl& setQueryKV(const std::string& key, const std::string& value);
|
||||
RsUrl& delQueryK(const std::string& key);
|
||||
|
||||
const std::string& fragment() const;
|
||||
RsUrl& setFragment(const std::string& fragment);
|
||||
|
||||
static std::string UrlEncode(const std::string& str,
|
||||
const std::string& ignoreChars = "");
|
||||
static std::string UrlDecode(const std::string& str);
|
||||
|
||||
inline bool operator<(const RsUrl& rhs)
|
||||
{ return toString() < rhs.toString(); }
|
||||
inline bool operator>(const RsUrl& rhs)
|
||||
{ return toString() > rhs.toString(); }
|
||||
inline bool operator<=(const RsUrl& rhs)
|
||||
{ return toString() <= rhs.toString(); }
|
||||
inline bool operator>=(const RsUrl& rhs)
|
||||
{ return toString() >= rhs.toString(); }
|
||||
inline bool operator==(const RsUrl& rhs)
|
||||
{ return toString() == rhs.toString(); }
|
||||
inline bool operator!=(const RsUrl& rhs)
|
||||
{ return toString() != rhs.toString(); }
|
||||
|
||||
static const std::string schemeSeparator;
|
||||
static const std::string ipv6WrapOpen;
|
||||
static const std::string ipv6Separator;
|
||||
static const std::string ipv6WrapClose;
|
||||
static const std::string portSeparator;
|
||||
static const std::string pathSeparator;
|
||||
static const std::string querySeparator;
|
||||
static const std::string queryAssign;
|
||||
static const std::string queryFieldSep;
|
||||
static const std::string fragmentSeparator;
|
||||
|
||||
private:
|
||||
|
||||
std::string mScheme;
|
||||
std::string mHost;
|
||||
uint16_t mPort;
|
||||
bool mHasPort;
|
||||
std::string mPath;
|
||||
std::map<std::string, std::string> mQuery;
|
||||
std::string mFragment;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user