Files
SingularityViewer/indra/newview/hipporestrequest.cpp
Siana Gearz 179f4ddabb The Octopus Feature
___
                     .-'   `'.
                    /         \
                    |         ;
                    |         |           ___.--,
           _.._     |0) ~ (0) |    _.---'`__.-( (_.
    __.--'`_.. '.__.\    '--. \_.-' ,.--'`     `""`
   ( ,.--'`   ',__ /./;   ;, '.__.'`    __
   _`) )  .---.__.' / |   |\   \__..--""  """--.,_
  `---' .'.''-._.-'`_./  /\ '.  \ _.-~~~````~~~-._`-.__.'
        | |  .' _.-' |  |  \  \  '.               `~---`
         \ \/ .'     \  \   '. '-._)
          \/ /        \  \    `=.__`~-.
     jgs  / /\         `) )    / / `"".`\
    , _.-'.'\ \        / /    ( (     / /
     `--~`   ) )    .-'.'      '.'.  | (
            (/`    ( (`          ) )  '-;
             `      '-;         (-'
2011-03-24 23:54:23 +01:00

352 lines
8.9 KiB
C++

#include "llviewerprecompiledheaders.h"
#include "hipporestrequest.h"
#ifndef CURL_STATICLIB
#define CURL_STATICLIB 1
#endif
#include <curl/curl.h>
#include <stdtypes.h>
#include <llbufferstream.h>
#include <llerror.h>
#include <llhttpclient.h>
#include <llurlrequest.h>
#include <llxmltree.h>
// ********************************************************************
class HippoRestComplete : public LLURLRequestComplete
{
public:
HippoRestComplete(HippoRestHandler *handler) :
mHandler(handler),
mStatus(499),
mReason("Request completed w/o status")
{
}
~HippoRestComplete()
{
delete mHandler;
}
// Called once for each header received, prior to httpStatus
void header(const std::string& header, const std::string& value)
{
mHandler->addHeader(header, value);
}
// Always called on request completion, prior to complete
void httpStatus(U32 status, const std::string& reason)
{
LLURLRequestComplete::httpStatus(status, reason);
mStatus = status;
mReason = reason;
}
void complete(const LLChannelDescriptors &channels, const buffer_ptr_t &buffer)
{
mHandler->handle(mStatus, mReason, channels, buffer);
}
private:
HippoRestHandler *mHandler;
int mStatus;
std::string mReason;
};
// ********************************************************************
static std::string gEmptyString;
void HippoRestHandler::addHeader(const std::string &header, const std::string &content)
{
mHeaders[header] = content;
}
bool HippoRestHandler::hasHeader(const std::string &header) const
{
return (mHeaders.find(header) != mHeaders.end());
}
const std::string &HippoRestHandler::getHeader(const std::string &header) const
{
std::map<std::string, std::string>::const_iterator it;
it = mHeaders.find(header);
if (it != mHeaders.end()) {
return it->second;
} else {
return gEmptyString;
}
}
// ********************************************************************
void HippoRestHandlerRaw::handle(int status, const std::string &reason,
const LLChannelDescriptors &channels,
const boost::shared_ptr<LLBufferArray> &body)
{
if (status == 200) {
std::string data;
LLBufferArray *buffer = body.get();
LLBufferArray::segment_iterator_t it, end = buffer->endSegment();
for (it=buffer->beginSegment(); it!=end; ++it)
if (it->isOnChannel(channels.in()))
data.append((char*)it->data(), it->size());
result(data);
} else {
llwarns << "Rest request error " << status << ": " << reason << llendl;
}
}
void HippoRestHandlerXml::handle(int status, const std::string &reason,
const LLChannelDescriptors &channels,
const boost::shared_ptr<LLBufferArray> &body)
{
if (status == 200) {
LLXmlTree *tree = new LLXmlTree();
bool success = tree->parseBufferStart();
LLBufferArray *buffer = body.get();
LLBufferArray::segment_iterator_t it, end = buffer->endSegment();
for (it=buffer->beginSegment(); success && (it!=end); ++it)
if (it->isOnChannel(channels.in()))
success = success && tree->parseBuffer((char*)it->data(), it->size());
success = success && tree->parseBufferFinalize();
if (success) result(tree);
delete tree;
} else {
llwarns << "Rest request error " << status << ": " << reason << llendl;
}
}
// ********************************************************************
class BodyData : public LLIOPipe
{
public:
virtual ~BodyData() { }
virtual const char *getContentMimeType() const = 0;
};
class BodyDataRaw : public BodyData
{
public:
explicit BodyDataRaw(const std::string &data) :
mData(data)
{
}
virtual ~BodyDataRaw() { }
const char *getContentMimeType() const { return "application/octet-stream"; }
EStatus process_impl(const LLChannelDescriptors &channels,
buffer_ptr_t &buffer, bool &eos,
LLSD &context, LLPumpIO *pump)
{
LLBufferStream ostream(channels, buffer.get());
ostream.write(mData.data(), mData.size());
eos = true;
return STATUS_DONE;
}
private:
std::string mData;
};
class BodyDataXml : public BodyData
{
public:
explicit BodyDataXml(const LLXmlTree *tree) :
mTree(tree)
{
}
virtual ~BodyDataXml()
{
if (mTree) delete mTree;
}
const char *getContentMimeType() const { return "application/xml"; }
EStatus process_impl(const LLChannelDescriptors &channels,
buffer_ptr_t &buffer, bool &eos,
LLSD &context, LLPumpIO *pump)
{
std::string data;
mTree->write(data);
LLBufferStream ostream(channels, buffer.get());
ostream.write(data.data(), data.size());
eos = true;
return STATUS_DONE;
}
private:
const LLXmlTree *mTree;
};
// ********************************************************************
static void request(const std::string &url,
LLURLRequest::ERequestAction method,
BodyData *body,
HippoRestHandler *handler, float timeout);
// static
void HippoRestRequest::get(const std::string &url,
HippoRestHandler *handler, float timeout)
{
request(url, LLURLRequest::HTTP_GET, 0, handler, timeout);
}
// static
void HippoRestRequest::put(const std::string &url, const std::string &body,
HippoRestHandler *handler, float timeout)
{
request(url, LLURLRequest::HTTP_PUT, new BodyDataRaw(body), handler, timeout);
}
// static
void HippoRestRequest::put(const std::string &url, const LLXmlTree *body,
HippoRestHandler *handler, float timeout)
{
request(url, LLURLRequest::HTTP_PUT, new BodyDataXml(body), handler, timeout);
}
// static
void HippoRestRequest::post(const std::string &url, const std::string &body,
HippoRestHandler *handler, float timeout)
{
request(url, LLURLRequest::HTTP_POST, new BodyDataRaw(body), handler, timeout);
}
// static
void HippoRestRequest::post(const std::string &url, const LLXmlTree *body,
HippoRestHandler *handler, float timeout)
{
request(url, LLURLRequest::HTTP_POST, new BodyDataXml(body), handler, timeout);
}
// ********************************************************************
static void request(const std::string &url,
LLURLRequest::ERequestAction method,
BodyData *body,
HippoRestHandler *handler, float timeout)
{
if (!LLHTTPClient::hasPump())
{
// !!! responder->completed(U32_MAX, "No pump", LLSD());
return;
}
LLPumpIO::chain_t chain;
LLURLRequest *req = new LLURLRequest(method, url);
req->checkRootCertificate(true);
/*
// Insert custom headers if the caller sent any
if (headers.isMap())
{
LLSD::map_const_iterator iter = headers.beginMap();
LLSD::map_const_iterator end = headers.endMap();
for (; iter != end; ++iter)
{
std::ostringstream header;
//if the header is "Pragma" with no value
//the caller intends to force libcurl to drop
//the Pragma header it so gratuitously inserts
//Before inserting the header, force libcurl
//to not use the proxy (read: llurlrequest.cpp)
static const std::string PRAGMA("Pragma");
if ((iter->first == PRAGMA) && (iter->second.asString().empty()))
{
req->useProxy(false);
}
header << iter->first << ": " << iter->second.asString() ;
lldebugs << "header = " << header.str() << llendl;
req->addHeader(header.str().c_str());
}
}
*/
if ((method != LLURLRequest::HTTP_PUT) && (method != LLURLRequest::HTTP_POST)) {
std::string accept = "Accept: ";
accept += handler->getAcceptMimeType();
req->addHeader(accept.c_str());
}
req->setCallback(new HippoRestComplete(handler));
if ((method == LLURLRequest::HTTP_PUT) || (method == LLURLRequest::HTTP_POST)) {
std::string content = "Content-Type: ";
content += body->getContentMimeType();
req->addHeader(content.c_str());
chain.push_back(LLIOPipe::ptr_t(body));
}
chain.push_back(LLIOPipe::ptr_t(req));
LLHTTPClient::getPump().addChain(chain, timeout);
}
// ********************************************************************
static size_t curlWrite(void *ptr, size_t size, size_t nmemb, void *userData)
{
std::string *result = (std::string*)userData;
size_t bytes = (size * nmemb);
result->append((char*)ptr, bytes);
return nmemb;
}
// static
int HippoRestRequest::getBlocking(const std::string &url, std::string *result)
{
llinfos << "Requesting: " << url << llendl;
char curlErrorBuffer[CURL_ERROR_SIZE];
CURL* curlp = curl_easy_init();
curl_easy_setopt(curlp, CURLOPT_NOSIGNAL, 1); // don't use SIGALRM for timeouts
curl_easy_setopt(curlp, CURLOPT_TIMEOUT, 5); // seconds
curl_easy_setopt(curlp, CURLOPT_WRITEFUNCTION, curlWrite);
curl_easy_setopt(curlp, CURLOPT_WRITEDATA, result);
curl_easy_setopt(curlp, CURLOPT_URL, url.c_str());
curl_easy_setopt(curlp, CURLOPT_ERRORBUFFER, curlErrorBuffer);
curl_easy_setopt(curlp, CURLOPT_FAILONERROR, 1);
*result = "";
S32 curlSuccess = curl_easy_perform(curlp);
S32 httpStatus = 499;
curl_easy_getinfo(curlp, CURLINFO_RESPONSE_CODE, &httpStatus);
if (curlSuccess != 0) {
llwarns << "CURL ERROR (HTTP Status " << httpStatus << "): " << curlErrorBuffer << llendl;
} else if (httpStatus != 200) {
llwarns << "HTTP Error " << httpStatus << ", but no Curl error." << llendl;
}
curl_easy_cleanup(curlp);
return httpStatus;
}