backport fix upnp xml_parse

This commit is contained in:
Andrei Kurushin 2016-12-18 15:31:02 +03:00 committed by Arvid Norberg
parent db65eaaa00
commit d62b980278
3 changed files with 107 additions and 48 deletions

View File

@ -130,9 +130,30 @@ struct parse_state
}
};
struct error_code_parse_state
{
error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {}
bool in_error_code;
bool exit;
int error_code;
};
struct ip_address_parse_state: error_code_parse_state
{
ip_address_parse_state(): in_ip_address(false) {}
bool in_ip_address;
std::string ip_address;
};
TORRENT_EXTRA_EXPORT void find_control_url(int type, char const* string
, int str_len, parse_state& state);
TORRENT_EXTRA_EXPORT void find_error_code(int type, char const* string
, int str_len, error_code_parse_state& state);
TORRENT_EXTRA_EXPORT void find_ip_address(int type, char const* string
, int str_len, ip_address_parse_state& state);
// TODO: support using the windows API for UPnP operations as well
class TORRENT_EXTRA_EXPORT upnp : public boost::enable_shared_from_this<upnp>
{

View File

@ -1063,53 +1063,39 @@ void upnp::disable(error_code const& ec, mutex::scoped_lock& l)
m_socket.close();
}
void find_error_code(int type, char const* string, int str_len, error_code_parse_state& state)
{
if (state.exit) return;
if (type == xml_start_tag && !std::strncmp("errorCode", string, size_t(str_len)))
{
state.in_error_code = true;
}
else if (type == xml_string && state.in_error_code)
{
std::string error_code_str(string, str_len);
state.error_code = std::atoi(error_code_str.c_str());
state.exit = true;
}
}
void find_ip_address(int type, char const* string, int str_len, ip_address_parse_state& state)
{
find_error_code(type, string, str_len, state);
if (state.exit) return;
if (type == xml_start_tag && !std::strncmp("NewExternalIPAddress", string, size_t(str_len)))
{
state.in_ip_address = true;
}
else if (type == xml_string && state.in_ip_address)
{
state.ip_address.assign(string, str_len);
state.exit = true;
}
}
namespace
{
struct error_code_parse_state
{
error_code_parse_state(): in_error_code(false), exit(false), error_code(-1) {}
bool in_error_code;
bool exit;
int error_code;
};
void find_error_code(int type, char const* string, error_code_parse_state& state)
{
if (state.exit) return;
if (type == xml_start_tag && !std::strcmp("errorCode", string))
{
state.in_error_code = true;
}
else if (type == xml_string && state.in_error_code)
{
state.error_code = std::atoi(string);
state.exit = true;
}
}
struct ip_address_parse_state: public error_code_parse_state
{
ip_address_parse_state(): in_ip_address(false) {}
bool in_ip_address;
std::string ip_address;
};
void find_ip_address(int type, char const* string, ip_address_parse_state& state)
{
find_error_code(type, string, state);
if (state.exit) return;
if (type == xml_start_tag && !std::strcmp("NewExternalIPAddress", string))
{
state.in_ip_address = true;
}
else if (type == xml_string && state.in_ip_address)
{
state.ip_address = string;
state.exit = true;
}
}
struct error_code_t
{
int code;
@ -1239,7 +1225,7 @@ void upnp::on_upnp_get_ip_address_response(error_code const& e
ip_address_parse_state s;
xml_parse(const_cast<char*>(p.get_body().begin), const_cast<char*>(p.get_body().end)
, boost::bind(&find_ip_address, _1, _2, boost::ref(s)));
, boost::bind(&find_ip_address, _1, _2, _3, boost::ref(s)));
if (s.error_code != -1)
{
char msg[500];
@ -1333,7 +1319,7 @@ void upnp::on_upnp_map_response(error_code const& e
error_code_parse_state s;
xml_parse(const_cast<char*>(p.get_body().begin)
, const_cast<char*>(p.get_body().end)
, boost::bind(&find_error_code, _1, _2, boost::ref(s)));
, boost::bind(&find_error_code, _1, _2, _3, boost::ref(s)));
if (s.error_code != -1)
{
@ -1476,7 +1462,7 @@ void upnp::on_upnp_unmap_response(error_code const& e
{
xml_parse(const_cast<char*>(p.get_body().begin)
, const_cast<char*>(p.get_body().end)
, boost::bind(&find_error_code, _1, _2, boost::ref(s)));
, boost::bind(&find_error_code, _1, _2, _3, boost::ref(s)));
}
int const proto = m_mappings[mapping].protocol;

View File

@ -233,6 +233,36 @@ char upnp_xml2[] =
"</device>"
"</root>";
char upnp_xml3[] =
"<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""
" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body>"
"<s:Fault>"
"<faultcode>s:Client</faultcode>"
"<faultstring>UPnPError</faultstring>"
"<detail>"
"<UPnPErrorxmlns=\"urn:schemas-upnp-org:control-1-0\">"
"<errorCode>402</errorCode>"
"<errorDescription>Invalid Args</errorDescription>"
"</UPnPError>"
"</detail>"
"</s:Fault>"
"</s:Body>"
"</s:Envelope>";
char upnp_xml4[] =
"<?xml version=\"1.0\"?>"
"<s:Envelope"
" xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\""
" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body>"
"<u:GetExternalIPAddressResponse"
" xmlns:u=\"urn:schemas-upnp-org:service:WANIPConnection:1\">"
"<NewExternalIPAddress>123.10.20.30</NewExternalIPAddress>"
"</u:GetExternalIPAddressResponse>"
"</s:Body>"
"</s:Envelope>";
using namespace libtorrent;
void parser_callback(std::string& out, int token, char const* s, int len
@ -304,6 +334,28 @@ TORRENT_TEST(upnp_parser2)
TEST_EQUAL(xml_s.model, "Wireless-G ADSL Home Gateway");
}
TORRENT_TEST(upnp_parser3)
{
error_code_parse_state xml_s;
xml_parse(upnp_xml3, upnp_xml3 + sizeof(upnp_xml3)
, boost::bind(&find_error_code, _1, _2, _3, boost::ref(xml_s)));
std::cout << "error_code " << xml_s.error_code << std::endl;
TEST_EQUAL(xml_s.error_code, 402);
}
TORRENT_TEST(upnp_parser4)
{
ip_address_parse_state xml_s;
xml_parse(upnp_xml4, upnp_xml4 + sizeof(upnp_xml4)
, boost::bind(&find_ip_address, _1, _2, _3, boost::ref(xml_s)));
std::cout << "error_code " << xml_s.error_code << std::endl;
std::cout << "ip_address " << xml_s.ip_address << std::endl;
TEST_EQUAL(xml_s.error_code, -1);
TEST_EQUAL(xml_s.ip_address, "123.10.20.30");
}
TORRENT_TEST(tags)
{
test_parse("<a>foo<b/>bar</a>", "BaSfooEbSbarFa");