fixed issue with parsing the password in a amqp:// string

This commit is contained in:
Emiel Bruijntjes 2017-05-01 21:59:45 +02:00
parent 2bb1300bc0
commit 2a249ae7ea
2 changed files with 80 additions and 22 deletions

View File

@ -50,65 +50,82 @@ private:
public: public:
/** /**
* Constructor to parse an address string * Constructor to parse an address string
* The address should be in "amqp:// * The address should start with "amqp://
* @param address * @param data
* @param size
* @throws std::runtime_error * @throws std::runtime_error
*/ */
Address(const char *address) : _vhost("/") Address(const char *data, size_t size) : _vhost("/")
{ {
// position of the last byte
const char *last = data + size;
// must start with amqp:// // must start with amqp://
if (strncmp(address, "amqp://", 7) != 0) throw std::runtime_error("AMQP address should start with \"amqp://\""); if (size < 7 || strncmp(data, "amqp://", 7) != 0) throw std::runtime_error("AMQP address should start with \"amqp://\"");
// begin of the string being parsed // begin of the string was parsed
const char *begin = address + 7; data += 7;
// do we have a '@' to split user-data and hostname? // do we have a '@' to split user-data and hostname?
const char *at = strchr(begin, '@'); const char *at = (const char *)memchr(data, '@', last - data);
// do we have one? // do we have one?
if (at != nullptr) if (at != nullptr)
{ {
// size of the user:password
size_t loginsize = at - data;
// colon could split username and password // colon could split username and password
const char *colon = (const char *)memchr(begin, ':', at - begin); const char *colon = (const char *)memchr(data, ':', loginsize);
// assign the login // assign the login
_login = Login( _login = Login(
std::string(begin, colon ? colon - begin : at - begin), std::string(data, colon ? colon - data : loginsize),
std::string(colon ? colon + 1 : "", colon ? at - colon - 1 : 0) std::string(colon ? colon + 1 : "", colon ? at - colon - 1 : 0)
); );
// set begin to the start of the hostname // set data to the start of the hostname
begin = at + 1; data = at + 1;
} }
// find out where the vhost is set (starts with a slash) // find out where the vhost is set (starts with a slash)
const char *slash = strchr(begin, '/'); const char *slash = (const char *)memchr(data, '/', last - data);
// was a vhost set? // was a vhost set?
if (slash != nullptr && slash[1]) _vhost = slash + 1; if (slash != nullptr && last - data > 1) _vhost.assign(slash + 1, last - data - 1);
// the hostname is everything until the slash, check is portnumber was set // the hostname is everything until the slash, check is portnumber was set
const char *colon = strchr(begin, ':'); const char *colon = (const char *)memchr(data, ':', last - data);
// was a portnumber specified (colon must appear before the slash of the vhost) // was a portnumber specified (colon must appear before the slash of the vhost)
if (colon && (!slash || colon < slash)) if (colon && (!slash || colon < slash))
{ {
// a portnumber was set to // a portnumber was set to
_hostname.assign(begin, colon - begin); _hostname.assign(data, colon - data);
_port = atoi(colon + 1);
// calculate the port
_port = atoi(std::string(colon + 1, slash ? slash - colon - 1 : last - colon - 1).data());
} }
else else
{ {
// no portnumber was set // no portnumber was set
_hostname.assign(begin, slash ? slash - begin : strlen(begin)); _hostname.assign(data, slash ? slash - data : last - data);
} }
} }
/**
* Constructor to parse an address string
* The address should start with "amqp://
* @param data
* @throws std::runtime_error
*/
Address(const char *data) : Address(data, strlen(data)) {}
/** /**
* Constructor based on std::string * Constructor based on std::string
* @param address * @param address
*/ */
Address(const std::string &address) : Address(address.data()) {} Address(const std::string &address) : Address(address.data(), address.size()) {}
/** /**
* Constructor based on already known properties * Constructor based on already known properties
@ -117,14 +134,16 @@ public:
* @param login * @param login
* @param vhost * @param vhost
*/ */
Address(std::string host, uint16_t port, Login login, std::string vhost) : _login(std::move(login)), Address(std::string host, uint16_t port, Login login, std::string vhost) :
_hostname(std::move(host)), _login(std::move(login)),
_port(port), _vhost(std::move(vhost)) {} _hostname(std::move(host)),
_port(port),
_vhost(std::move(vhost)) {}
/** /**
* Destructor * Destructor
*/ */
virtual ~Address() {} virtual ~Address() = default;
/** /**
* Expose the login data * Expose the login data

39
tests/address.cpp Normal file
View File

@ -0,0 +1,39 @@
/**
* Address.cpp
*
* Test program to parse address strings
*
* @author Emiel Bruijntjes <emiel.bruijntjes@copernica.com>
* @copyright 2017 Copernica BV
*/
/**
* Dependencies
*/
#include <amqpcpp.h>
/**
* Main procedure
* @param argc
* @param argv
* @return int
*/
int main(int argc, const char *argv[])
{
// iterate over the arguments
for (int i = 1; i < argc; ++i)
{
// parse address
AMQP::Address address(argv[i]);
// output all properties
std::cout << "user: " << address.login().user() << std::endl;
std::cout << "password: " << address.login().password() << std::endl;
std::cout << "hostname: " << address.hostname() << std::endl;
std::cout << "port: " << address.port() << std::endl;
std::cout << "vhost: " << address.vhost() << std::endl;
}
// done
return 0;
}