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