Blame src/HTTPFetch.cc

Packit f70c98
/* --------------------------------------------------------------------------
Packit f70c98
Packit f70c98
   libmusicbrainz5 - Client library to access MusicBrainz
Packit f70c98
Packit f70c98
   Copyright (C) 2012 Andrew Hawkins
Packit f70c98
Packit f70c98
   This file is part of libmusicbrainz5.
Packit f70c98
Packit f70c98
   This library is free software; you can redistribute it and/or
Packit f70c98
   modify it under the terms of the GNU Lesser General Public
Packit f70c98
   License as published by the Free Software Foundation; either
Packit f70c98
   version 2.1 of the License, or (at your option) any later version.
Packit f70c98
Packit f70c98
   libmusicbrainz5 is distributed in the hope that it will be useful,
Packit f70c98
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit f70c98
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit f70c98
   Lesser General Public License for more details.
Packit f70c98
Packit f70c98
   You should have received a copy of the GNU General Public License
Packit f70c98
   along with this library.  If not, see <http://www.gnu.org/licenses/>.
Packit f70c98
Packit f70c98
     $Id$
Packit f70c98
Packit f70c98
----------------------------------------------------------------------------*/
Packit f70c98
Packit f70c98
#include "config.h"
Packit f70c98
#include "musicbrainz5/defines.h"
Packit f70c98
Packit f70c98
#include "musicbrainz5/HTTPFetch.h"
Packit f70c98
Packit f70c98
#include <stdlib.h>
Packit f70c98
#include <string.h>
Packit f70c98
Packit f70c98
#include "ne_session.h"
Packit f70c98
#include "ne_auth.h"
Packit f70c98
#include "ne_string.h"
Packit f70c98
#include "ne_request.h"
Packit f70c98
Packit Service 1b21de
#if defined(__GNUC__)
Packit Service 1b21de
__attribute__((constructor))
Packit Service 1b21de
#else
Packit Service 1b21de
	#error Non GCC compiler detected
Packit Service 1b21de
#endif
Packit Service 1b21de
static void initialize_neon() 
Packit Service 1b21de
{
Packit Service 1b21de
	ne_sock_init();
Packit Service 1b21de
}
Packit Service 1b21de
Packit Service 1b21de
#if defined(__GNUC__)
Packit Service 1b21de
__attribute__((destructor))
Packit Service 1b21de
#else
Packit Service 1b21de
	#error Non GCC compiler detected
Packit Service 1b21de
#endif
Packit Service 1b21de
static void destroy_neon() 
Packit Service 1b21de
{
Packit Service 1b21de
	ne_sock_exit();
Packit Service 1b21de
}
Packit Service 1b21de
Packit f70c98
class MusicBrainz5::CHTTPFetchPrivate
Packit f70c98
{
Packit f70c98
	public:
Packit f70c98
		CHTTPFetchPrivate()
Packit f70c98
		:	m_Port(80),
Packit f70c98
			m_Result(0),
Packit f70c98
			m_Status(0),
Packit f70c98
			m_ProxyPort(0)
Packit f70c98
		{
Packit f70c98
		}
Packit f70c98
Packit f70c98
		std::string m_UserAgent;
Packit f70c98
		std::string m_Host;
Packit f70c98
		int m_Port;
Packit f70c98
		std::vector<unsigned char> m_Data;
Packit f70c98
		int m_Result;
Packit f70c98
		int m_Status;
Packit f70c98
		std::string m_ErrorMessage;
Packit f70c98
		std::string m_UserName;
Packit f70c98
		std::string m_Password;
Packit f70c98
		std::string m_ProxyHost;
Packit f70c98
		int m_ProxyPort;
Packit f70c98
		std::string m_ProxyUserName;
Packit f70c98
		std::string m_ProxyPassword;
Packit f70c98
};
Packit f70c98
Packit f70c98
MusicBrainz5::CHTTPFetch::CHTTPFetch(const std::string& UserAgent, const std::string& Host, int Port)
Packit f70c98
:	m_d(new CHTTPFetchPrivate)
Packit f70c98
{
Packit f70c98
	m_d->m_UserAgent=UserAgent;
Packit f70c98
Packit f70c98
	for (std::string::size_type Pos=0;Pos<m_d->m_UserAgent.length();Pos++)
Packit f70c98
		if (m_d->m_UserAgent[Pos]=='-')
Packit f70c98
			m_d->m_UserAgent[Pos]='/';
Packit f70c98
Packit f70c98
 	m_d->m_Host=Host;
Packit f70c98
	m_d->m_Port=Port;
Packit f70c98
Packit f70c98
	// Parse http_proxy environmnent variable
Packit f70c98
	const char *http_proxy = getenv("http_proxy");
Packit f70c98
	if (http_proxy)
Packit f70c98
	{
Packit f70c98
		ne_uri uri;
Packit f70c98
		if (!ne_uri_parse(http_proxy, &uri))
Packit f70c98
		{
Packit f70c98
			if (uri.host)
Packit f70c98
				m_d->m_ProxyHost = uri.host;
Packit f70c98
			if (uri.port)
Packit f70c98
				m_d->m_ProxyPort = uri.port;
Packit f70c98
Packit f70c98
			if (uri.userinfo)
Packit f70c98
			{
Packit f70c98
				char *pos = strchr(uri.userinfo, ':');
Packit f70c98
				if (pos)
Packit f70c98
				{
Packit f70c98
					*pos = '\0';
Packit f70c98
					m_d->m_ProxyUserName = uri.userinfo;
Packit f70c98
					m_d->m_ProxyPassword = pos + 1;
Packit f70c98
				}
Packit f70c98
				else
Packit f70c98
				{
Packit f70c98
					m_d->m_ProxyUserName = uri.userinfo;
Packit f70c98
				}
Packit f70c98
			}
Packit f70c98
		}
Packit f70c98
Packit f70c98
		ne_uri_free(&uri);
Packit f70c98
	}
Packit f70c98
}
Packit f70c98
Packit f70c98
MusicBrainz5::CHTTPFetch::~CHTTPFetch()
Packit f70c98
{
Packit f70c98
	delete m_d;
Packit f70c98
}
Packit f70c98
Packit f70c98
void MusicBrainz5::CHTTPFetch::SetUserName(const std::string& UserName)
Packit f70c98
{
Packit f70c98
	m_d->m_UserName=UserName;
Packit f70c98
}
Packit f70c98
Packit f70c98
void MusicBrainz5::CHTTPFetch::SetPassword(const std::string& Password)
Packit f70c98
{
Packit f70c98
	m_d->m_Password=Password;
Packit f70c98
}
Packit f70c98
Packit f70c98
void MusicBrainz5::CHTTPFetch::SetProxyHost(const std::string& ProxyHost)
Packit f70c98
{
Packit f70c98
	m_d->m_ProxyHost=ProxyHost;
Packit f70c98
}
Packit f70c98
Packit f70c98
void MusicBrainz5::CHTTPFetch::SetProxyPort(int ProxyPort)
Packit f70c98
{
Packit f70c98
	m_d->m_ProxyPort=ProxyPort;
Packit f70c98
}
Packit f70c98
Packit f70c98
void MusicBrainz5::CHTTPFetch::SetProxyUserName(const std::string& ProxyUserName)
Packit f70c98
{
Packit f70c98
	m_d->m_ProxyUserName=ProxyUserName;
Packit f70c98
}
Packit f70c98
Packit f70c98
void MusicBrainz5::CHTTPFetch::SetProxyPassword(const std::string& ProxyPassword)
Packit f70c98
{
Packit f70c98
	m_d->m_ProxyPassword=ProxyPassword;
Packit f70c98
}
Packit f70c98
Packit f70c98
int MusicBrainz5::CHTTPFetch::Fetch(const std::string& URL, const std::string& Request)
Packit f70c98
{
Packit f70c98
	int Ret=0;
Packit f70c98
Packit f70c98
	m_d->m_Data.clear();
Packit f70c98
Packit f70c98
	ne_session *sess=ne_session_create("http", m_d->m_Host.c_str(), m_d->m_Port);
Packit f70c98
	if (sess)
Packit f70c98
	{
Packit f70c98
		ne_set_useragent(sess, m_d->m_UserAgent.c_str());
Packit f70c98
Packit f70c98
		ne_set_server_auth(sess, httpAuth, this);
Packit f70c98
Packit f70c98
		// Use proxy server
Packit f70c98
		if (!m_d->m_ProxyHost.empty())
Packit f70c98
		{
Packit f70c98
			ne_session_proxy(sess, m_d->m_ProxyHost.c_str(), m_d->m_ProxyPort);
Packit f70c98
			ne_set_proxy_auth(sess, proxyAuth, this);
Packit f70c98
		}
Packit f70c98
Packit f70c98
		ne_request *req = ne_request_create(sess, Request.c_str(), URL.c_str());
Packit f70c98
		if (Request=="PUT")
Packit f70c98
			ne_set_request_body_buffer(req,0,0);
Packit f70c98
Packit f70c98
		if (Request!="GET")
Packit f70c98
			ne_set_request_flag(req, NE_REQFLAG_IDEMPOTENT, 0);
Packit f70c98
Packit f70c98
		ne_add_response_body_reader(req, ne_accept_2xx, httpResponseReader, &m_d->m_Data);
Packit f70c98
Packit f70c98
		m_d->m_Result = ne_request_dispatch(req);
Packit f70c98
		m_d->m_Status = ne_get_status(req)->code;
Packit f70c98
Packit f70c98
		Ret=m_d->m_Data.size();
Packit f70c98
Packit f70c98
		ne_request_destroy(req);
Packit f70c98
Packit f70c98
		m_d->m_ErrorMessage = ne_get_error(sess);
Packit f70c98
Packit f70c98
		ne_session_destroy(sess);
Packit f70c98
Packit f70c98
		switch (m_d->m_Result)
Packit f70c98
		{
Packit f70c98
			case NE_OK:
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			case NE_CONNECT:
Packit f70c98
			case NE_LOOKUP:
Packit f70c98
				throw CConnectionError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			case NE_TIMEOUT:
Packit f70c98
				throw CTimeoutError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			case NE_AUTH:
Packit f70c98
			case NE_PROXYAUTH:
Packit f70c98
				throw CAuthenticationError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			default:
Packit f70c98
				throw CFetchError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
		}
Packit f70c98
Packit f70c98
		switch (m_d->m_Status)
Packit f70c98
		{
Packit f70c98
			case 200:
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			case 400:
Packit f70c98
				throw CRequestError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			case 401:
Packit f70c98
				throw CAuthenticationError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			case 404:
Packit f70c98
				throw CResourceNotFoundError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
Packit f70c98
			default:
Packit f70c98
				throw CFetchError(m_d->m_ErrorMessage);
Packit f70c98
				break;
Packit f70c98
		}
Packit f70c98
	}
Packit f70c98
Packit f70c98
	return Ret;
Packit f70c98
}
Packit f70c98
Packit f70c98
int MusicBrainz5::CHTTPFetch::httpAuth(void *userdata, const char *realm, int attempts,
Packit f70c98
					 char *username, char *password)
Packit f70c98
{
Packit f70c98
	realm=realm;
Packit f70c98
Packit f70c98
	MusicBrainz5::CHTTPFetch *Fetch = (MusicBrainz5::CHTTPFetch *)userdata;
Packit f70c98
	strncpy(username, Fetch->m_d->m_UserName.c_str(), NE_ABUFSIZ);
Packit f70c98
	strncpy(password, Fetch->m_d->m_Password.c_str(), NE_ABUFSIZ);
Packit f70c98
	return attempts;
Packit f70c98
}
Packit f70c98
Packit f70c98
int MusicBrainz5::CHTTPFetch::proxyAuth(void *userdata, const char *realm, int attempts,
Packit f70c98
					 char *username, char *password)
Packit f70c98
{
Packit f70c98
	realm=realm;
Packit f70c98
Packit f70c98
	MusicBrainz5::CHTTPFetch *Fetch = (MusicBrainz5::CHTTPFetch *)userdata;
Packit f70c98
	strncpy(username, Fetch->m_d->m_ProxyUserName.c_str(), NE_ABUFSIZ);
Packit f70c98
	strncpy(password, Fetch->m_d->m_ProxyPassword.c_str(), NE_ABUFSIZ);
Packit f70c98
	return attempts;
Packit f70c98
}
Packit f70c98
Packit f70c98
int MusicBrainz5::CHTTPFetch::httpResponseReader(void *userdata, const char *buf, size_t len)
Packit f70c98
{
Packit f70c98
	std::vector<unsigned char> *buffer = reinterpret_cast<std::vector<unsigned char> *>(userdata);
Packit f70c98
Packit f70c98
	buffer->insert(buffer->end(),buf,buf+len);
Packit f70c98
Packit f70c98
	return 0;
Packit f70c98
}
Packit f70c98
Packit f70c98
std::vector<unsigned char> MusicBrainz5::CHTTPFetch::Data() const
Packit f70c98
{
Packit f70c98
	return m_d->m_Data;
Packit f70c98
}
Packit f70c98
Packit f70c98
int MusicBrainz5::CHTTPFetch::Result() const
Packit f70c98
{
Packit f70c98
	return m_d->m_Result;
Packit f70c98
}
Packit f70c98
Packit f70c98
int MusicBrainz5::CHTTPFetch::Status() const
Packit f70c98
{
Packit f70c98
	return m_d->m_Status;
Packit f70c98
}
Packit f70c98
Packit f70c98
std::string MusicBrainz5::CHTTPFetch::ErrorMessage() const
Packit f70c98
{
Packit f70c98
	return m_d->m_ErrorMessage;
Packit f70c98
}