159 lines
4 KiB
C++
159 lines
4 KiB
C++
|
|
#include "httpfetch.h"
|
|
#include "transport/logging.h"
|
|
|
|
DEFINE_LOGGER(logger, "HTTPFetch");
|
|
|
|
static int url_to_host_port_path(const char *url,
|
|
char *host, int *port, char *path, int *ssl)
|
|
{
|
|
char *urlcopy = NULL;
|
|
char *slash = NULL;
|
|
char *colon = NULL;
|
|
|
|
/*
|
|
* http://hostname
|
|
* http://hostname/
|
|
* http://hostname/path
|
|
* http://hostname/path:foo
|
|
* http://hostname:port
|
|
* http://hostname:port/
|
|
* http://hostname:port/path
|
|
* http://hostname:port/path:foo
|
|
* and https:// variants of the above
|
|
*/
|
|
|
|
if (strstr(url, "http://") == url) {
|
|
urlcopy = strdup(url + 7);
|
|
} else if (strstr(url, "https://") == url) {
|
|
urlcopy = strdup(url + 8);
|
|
*ssl = 1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
|
|
slash = strchr(urlcopy, '/');
|
|
colon = strchr(urlcopy, ':');
|
|
|
|
if (!colon || (slash && slash < colon)) {
|
|
if (*ssl)
|
|
*port = 443;
|
|
else
|
|
*port = 80;
|
|
} else {
|
|
*colon = 0;
|
|
*port = atoi(colon + 1);
|
|
}
|
|
|
|
if (!slash) {
|
|
strcpy(path, "/");
|
|
} else {
|
|
strcpy(path, slash);
|
|
*slash = 0;
|
|
}
|
|
|
|
strcpy(host, urlcopy);
|
|
|
|
free(urlcopy);
|
|
|
|
return 1;
|
|
}
|
|
|
|
HTTPFetch::HTTPFetch(Swift::BoostIOServiceThread *ioService, Swift::ConnectionFactory *factory) : m_ioService(ioService), m_factory(factory) {
|
|
m_afterHeader = false;
|
|
}
|
|
|
|
HTTPFetch::~HTTPFetch() {
|
|
}
|
|
|
|
void HTTPFetch::_connected(boost::shared_ptr<Swift::Connection> conn, const std::string url, bool error) {
|
|
if (error) {
|
|
_disconnected(conn);
|
|
}
|
|
else {
|
|
char host[255];
|
|
int port = 80;
|
|
char path[255];
|
|
int ssl = 0;
|
|
if (!url_to_host_port_path(url.c_str(), host, &port, path, &ssl))
|
|
return;
|
|
|
|
static char buff[2048];
|
|
snprintf(buff, sizeof(buff),
|
|
"GET %s HTTP/1.1\r\n"
|
|
"Host: %s\r\n"
|
|
"User-Agent: Mozilla/4.5 [en] (1/1)\r\n"
|
|
"Accept: */*\r\n"
|
|
"%s" "\r\n", path, host,
|
|
"Connection: close\r\n");
|
|
LOG4CXX_INFO(logger, "Sending " << buff << "\n");
|
|
conn->write(Swift::createSafeByteArray(buff));
|
|
}
|
|
}
|
|
|
|
void HTTPFetch::_disconnected(boost::shared_ptr<Swift::Connection> conn) {
|
|
conn->onConnectFinished.disconnect_all_slots();
|
|
conn->onDisconnected.disconnect_all_slots();
|
|
conn->onDataRead.disconnect_all_slots();
|
|
|
|
if (m_buffer.size() == 0) {
|
|
onURLFetched("");
|
|
}
|
|
else {
|
|
std::string img = m_buffer.substr(m_buffer.find("\r\n\r\n") + 4);
|
|
onURLFetched(img);
|
|
}
|
|
}
|
|
|
|
void HTTPFetch::_read(boost::shared_ptr<Swift::Connection> conn, boost::shared_ptr<Swift::SafeByteArray> data) {
|
|
std::string d(data->begin(), data->end());
|
|
// std::cout << d << "\n";
|
|
std::string img = d.substr(d.find("\r\n\r\n") + 4);
|
|
if (d.find("Location: ") == std::string::npos) {
|
|
m_buffer += d;
|
|
}
|
|
else {
|
|
d = d.substr(d.find("Location: ") + 10);
|
|
if (d.find("\r") == std::string::npos) {
|
|
d = d.substr(0, d.find("\n"));
|
|
}
|
|
else {
|
|
d = d.substr(0, d.find("\r"));
|
|
}
|
|
LOG4CXX_INFO(logger, "Next url is '" << d << "'");
|
|
fetchURL(d);
|
|
conn->onConnectFinished.disconnect_all_slots();
|
|
conn->onDisconnected.disconnect_all_slots();
|
|
conn->onDataRead.disconnect_all_slots();
|
|
}
|
|
}
|
|
|
|
bool HTTPFetch::fetchURL(const std::string &url) {
|
|
char host[255];
|
|
int port = 80;
|
|
char path[255];
|
|
char buff[1024];
|
|
int ssl = 0;
|
|
if (!url_to_host_port_path(url.c_str(), host, &port, path, &ssl)) {
|
|
LOG4CXX_ERROR(logger, "Invalid URL " << url);
|
|
return false;
|
|
}
|
|
|
|
LOG4CXX_INFO(logger, "Connecting to " << host << ":" << port);
|
|
|
|
boost::asio::ip::tcp::resolver resolver(*m_ioService->getIOService());
|
|
boost::asio::ip::tcp::resolver::query query(host, "");
|
|
boost::asio::ip::address address;
|
|
for(boost::asio::ip::tcp::resolver::iterator i = resolver.resolve(query); i != boost::asio::ip::tcp::resolver::iterator(); ++i) {
|
|
boost::asio::ip::tcp::endpoint end = *i;
|
|
address = end.address();
|
|
break;
|
|
}
|
|
|
|
boost::shared_ptr<Swift::Connection> conn = m_factory->createConnection();
|
|
conn->onConnectFinished.connect(boost::bind(&HTTPFetch::_connected, this, conn, url, _1));
|
|
conn->onDisconnected.connect(boost::bind(&HTTPFetch::_disconnected, this, conn));
|
|
conn->onDataRead.connect(boost::bind(&HTTPFetch::_read, this, conn, _1));
|
|
conn->connect(Swift::HostAddressPort(Swift::HostAddress(address), port));
|
|
return true;
|
|
}
|