The Octopus Feature
___
.-' `'.
/ \
| ;
| | ___.--,
_.._ |0) ~ (0) | _.---'`__.-( (_.
__.--'`_.. '.__.\ '--. \_.-' ,.--'` `""`
( ,.--'` ',__ /./; ;, '.__.'` __
_`) ) .---.__.' / | |\ \__..--"" """--.,_
`---' .'.''-._.-'`_./ /\ '. \ _.-~~~````~~~-._`-.__.'
| | .' _.-' | | \ \ '. `~---`
\ \/ .' \ \ '. '-._)
\/ / \ \ `=.__`~-.
jgs / /\ `) ) / / `"".`\
, _.-'.'\ \ / / ( ( / /
`--~` ) ) .-'.' '.'. | (
(/` ( (` ) ) '-;
` '-; (-'
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
|
||||
#include "llviewerprecompiledheaders.h"
|
||||
|
||||
#include "hipporestrequest.h"
|
||||
@@ -8,7 +9,303 @@
|
||||
#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)
|
||||
|
||||
Reference in New Issue
Block a user