merged upstream/master

This commit is contained in:
csoler 2018-07-08 21:17:48 +02:00
commit 6848a586f3
No known key found for this signature in database
GPG key ID: 7BCA522266C0804C
94 changed files with 1618 additions and 758 deletions

View file

@ -138,6 +138,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);

View file

@ -21,6 +21,8 @@
* *
*******************************************************************************/
#include "util/rsurl.h"
#include <sstream>
#include <iomanip>
#include <cstdlib>
@ -187,8 +189,7 @@ bool sockaddr_storage_copyip(struct sockaddr_storage &dst, const struct sockaddr
uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr)
{
#ifdef SS_DEBUG
std::cerr << "sockaddr_storage_port()";
std::cerr << std::endl;
std::cerr << "sockaddr_storage_port()" << std::endl;
#endif
switch(addr.ss_family)
{
@ -198,8 +199,10 @@ uint16_t sockaddr_storage_port(const struct sockaddr_storage &addr)
return sockaddr_storage_ipv6_port(addr);
default:
std::cerr << "sockaddr_storage_port() invalid addr.ss_family" << std::endl;
#ifdef SS_DEBUG
sockaddr_storage_dump(addr);
print_stacktrace();
#endif
break;
}
return 0;
@ -488,27 +491,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 "AF_INVALID";
}
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)
@ -603,9 +611,11 @@ std::string sockaddr_storage_iptostring(const struct sockaddr_storage &addr)
break;
default:
output = "INVALID_IP";
std::cerr << __PRETTY_FUNCTION__ << " Got invalid IP:" << std::endl;
std::cerr << __PRETTY_FUNCTION__ << " Got invalid IP!" << std::endl;
#ifdef SS_DEBUG
sockaddr_storage_dump(addr);
print_stacktrace();
#endif
break;
}
return output;

View file

@ -0,0 +1,267 @@
/*
* 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 endI = urlStr.size()-1;
size_t schemeEndI = urlStr.find(schemeSeparator);
if(schemeEndI >= endI)
{
mScheme = urlStr;
return *this;
}
mScheme = urlStr.substr(0, schemeEndI);
size_t hostBeginI = schemeEndI + 3;
if(hostBeginI >= endI) return *this;
bool hasSquareBr = (urlStr[hostBeginI] == ipv6WrapOpen[0]);
size_t hostEndI;
if(hasSquareBr)
{
if(++hostBeginI >= endI) return *this;
hostEndI = urlStr.find(ipv6WrapClose, hostBeginI);
mHost = urlStr.substr(hostBeginI, hostEndI - hostBeginI - 1);
++hostEndI;
}
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 >= endI ) return *this;
mHasPort = (sscanf(&urlStr[hostEndI], ":%hu", &mPort) == 1);
size_t pathBeginI = urlStr.find(pathSeparator, hostBeginI);
size_t pathEndI = string::npos;
if(pathBeginI < endI)
{
pathEndI = urlStr.find(querySeparator, pathBeginI);
pathEndI = min(pathEndI, urlStr.find(fragmentSeparator, pathBeginI));
mPath = UrlDecode(urlStr.substr(pathBeginI, pathEndI - pathBeginI));
if(pathEndI >= endI) return *this;
}
size_t queryBeginI = urlStr.find(querySeparator, hostBeginI);
size_t queryEndI = urlStr.find(fragmentSeparator, hostBeginI);
if(queryBeginI < endI)
{
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 < endI);
if(queryEndI >= endI) return *this;
}
size_t fragmentBeginI = urlStr.find(fragmentSeparator, hostBeginI);
if(fragmentBeginI < endI)
mFragment = UrlDecode(urlStr.substr(++fragmentBeginI));
return *this;
}
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;
mHasPort = true;
return *this;
}
RsUrl& RsUrl::unsetPort()
{
mPort = 0;
mHasPort = false;
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("#");

View file

@ -0,0 +1,102 @@
#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);
RsUrl& unsetPort();
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) const
{ return toString() < rhs.toString(); }
inline bool operator>(const RsUrl& rhs) const
{ return toString() > rhs.toString(); }
inline bool operator<=(const RsUrl& rhs) const
{ return toString() <= rhs.toString(); }
inline bool operator>=(const RsUrl& rhs) const
{ return toString() >= rhs.toString(); }
inline bool operator==(const RsUrl& rhs) const
{ return toString() == rhs.toString(); }
inline bool operator!=(const RsUrl& rhs) const
{ 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;
};