spectrum2/backends/libyahoo2/httpfetch.cpp
2012-05-27 15:35:22 +02:00

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;
}