summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
Diffstat (limited to 'indra')
-rw-r--r--indra/cmake/CMakeLists.txt1
-rw-r--r--indra/llcommon/llkeythrottle.h35
-rw-r--r--indra/llmessage/llcurl.cpp54
-rw-r--r--indra/llmessage/llcurl.h28
-rw-r--r--indra/llmessage/llhttpclient.cpp43
-rw-r--r--indra/llmessage/llhttpnode.cpp27
-rw-r--r--indra/llmessage/llhttpnode.h88
-rw-r--r--indra/llmessage/lliohttpserver.cpp48
-rw-r--r--indra/newview/CMakeLists.txt1
-rw-r--r--indra/test/lliohttpserver_tut.cpp17
10 files changed, 223 insertions, 119 deletions
diff --git a/indra/cmake/CMakeLists.txt b/indra/cmake/CMakeLists.txt
index 9cc34ea159..f0bb241961 100644
--- a/indra/cmake/CMakeLists.txt
+++ b/indra/cmake/CMakeLists.txt
@@ -63,7 +63,6 @@ set(cmake_SOURCE_FILES
PNG.cmake
Python.cmake
QuickTime.cmake
- Smartheap.cmake
TemplateCheck.cmake
UI.cmake
UnixInstall.cmake
diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h
index 61a43b2dad..ac2f4254f2 100644
--- a/indra/llcommon/llkeythrottle.h
+++ b/indra/llcommon/llkeythrottle.h
@@ -55,28 +55,31 @@ class LLKeyThrottleImpl
protected:
struct Entry {
U32 count;
- BOOL blocked;
+ bool blocked;
- Entry() : count(0), blocked(FALSE) { }
+ Entry() : count(0), blocked(false) { }
};
typedef std::map<T, Entry> EntryMap;
- EntryMap * prevMap;
- EntryMap * currMap;
+ EntryMap* prevMap;
+ EntryMap* currMap;
U32 countLimit;
// maximum number of keys allowed per interval
U64 intervalLength; // each map covers this time period (usec or frame number)
U64 startTime; // start of the time period (usec or frame number)
-
// currMap started counting at this time
// prevMap covers the previous interval
- LLKeyThrottleImpl() : prevMap(0), currMap(0),
- countLimit(0), intervalLength(1),
- startTime(0) { };
+ LLKeyThrottleImpl() :
+ prevMap(NULL),
+ currMap(NULL),
+ countLimit(0),
+ intervalLength(1),
+ startTime(0)
+ {}
static U64 getTime()
{
@@ -93,7 +96,9 @@ template< class T >
class LLKeyThrottle
{
public:
- LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE) // realtime = FALSE for frame-based throttle, TRUE for usec real-time throttle
+ // @param realtime = FALSE for frame-based throttle, TRUE for usec
+ // real-time throttle
+ LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE)
: m(* new LLKeyThrottleImpl<T>)
{
setParameters( limit, interval, realtime );
@@ -149,7 +154,7 @@ public:
}
U32 prevCount = 0;
- BOOL prevBlocked = FALSE;
+ bool prevBlocked = false;
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
if (prev != m.prevMap->end())
@@ -198,17 +203,17 @@ public:
noteAction(id);
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
curr.count = llmax(m.countLimit, curr.count);
- curr.blocked = TRUE;
+ curr.blocked = true;
}
- // returns TRUE if key is blocked
- BOOL isThrottled(const T& id) const
+ // returns true if key is blocked
+ bool isThrottled(const T& id) const
{
if (m.currMap->empty()
&& m.prevMap->empty())
{
// most of the time we'll fall in here
- return FALSE;
+ return false;
}
// NOTE, we ignore the case where id is in the map but the map is stale.
@@ -226,7 +231,7 @@ public:
{
return entry->second.blocked;
}
- return FALSE;
+ return false;
}
// Get the throttling parameters
diff --git a/indra/llmessage/llcurl.cpp b/indra/llmessage/llcurl.cpp
index e282f49438..5a426c7238 100644
--- a/indra/llmessage/llcurl.cpp
+++ b/indra/llmessage/llcurl.cpp
@@ -113,6 +113,15 @@ LLCurl::Responder::~Responder()
}
// virtual
+void LLCurl::Responder::error(
+ U32 status,
+ const std::string& reason,
+ const LLSD&)
+{
+ error(status, reason);
+}
+
+// virtual
void LLCurl::Responder::error(U32 status, const std::string& reason)
{
llinfos << status << ": " << reason << llendl;
@@ -124,38 +133,16 @@ void LLCurl::Responder::result(const LLSD& content)
}
// virtual
-void LLCurl::Responder::completedRaw(U32 status, const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
+void LLCurl::Responder::completedRaw(
+ U32 status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
{
- if (isGoodStatus(status))
- {
- LLSD content;
- LLBufferStream istr(channels, buffer.get());
- LLSDSerialize::fromXML(content, istr);
-/*
- const S32 parseError = -1;
- if(LLSDSerialize::fromXML(content, istr) == parseError)
- {
- mStatus = 498;
- mReason = "Client Parse Error";
- }
-*/
- completed(status, reason, content);
- }
- else if (status == 400)
- {
- // Get reason from buffer
- char tbuf[4096];
- S32 len = 4096;
- buffer->readAfter(channels.in(), NULL, (U8*)tbuf, len);
- tbuf[len] = 0;
- completed(status, std::string(tbuf), LLSD());
- }
- else
- {
- completed(status, reason, LLSD());
- }
+ LLSD content;
+ LLBufferStream istr(channels, buffer.get());
+ LLSDSerialize::fromXML(content, istr);
+ completed(status, reason, content);
}
// virtual
@@ -167,10 +154,7 @@ void LLCurl::Responder::completed(U32 status, const std::string& reason, const L
}
else
{
- // *NOTE: This is kind of messed up. This should probably call
- // the full error method which then provides a default impl
- // which calls the thinner method.
- error(status, reason);
+ error(status, reason, content);
}
}
diff --git a/indra/llmessage/llcurl.h b/indra/llmessage/llcurl.h
index 1b3d3f6266..b7634d420f 100644
--- a/indra/llmessage/llcurl.h
+++ b/indra/llmessage/llcurl.h
@@ -84,17 +84,31 @@ public:
return((200 <= status) && (status < 300));
}
+ virtual void error(
+ U32 status,
+ const std::string& reason,
+ const LLSD& content);
+ //< called by completed() on bad status
+
virtual void error(U32 status, const std::string& reason);
- // called with non-200 status codes
+ //< called by default error(status, reason, content)
virtual void result(const LLSD& content);
-
- // Override point for clients that may want to use this class when the response is some other format besides LLSD
- virtual void completedRaw(U32 status, const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer);
+ //< called by completed for good status codes.
+
+ virtual void completedRaw(
+ U32 status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer);
+ /**< Override point for clients that may want to use this
+ class when the response is some other format besides LLSD
+ */
- virtual void completed(U32 status, const std::string& reason, const LLSD& content);
+ virtual void completed(
+ U32 status,
+ const std::string& reason,
+ const LLSD& content);
/**< The default implemetnation calls
either:
* result(), or
diff --git a/indra/llmessage/llhttpclient.cpp b/indra/llmessage/llhttpclient.cpp
index 859f3c1536..52cb8fe1c3 100644
--- a/indra/llmessage/llhttpclient.cpp
+++ b/indra/llmessage/llhttpclient.cpp
@@ -205,9 +205,7 @@ static void request(
Injector* body_injector,
LLCurl::ResponderPtr responder,
const F32 timeout = HTTP_REQUEST_EXPIRY_SECS,
- const LLSD& headers = LLSD(),
- S32 offset = 0,
- S32 bytes = 0)
+ const LLSD& headers = LLSD())
{
if (!LLHTTPClient::hasPump())
{
@@ -216,7 +214,7 @@ static void request(
}
LLPumpIO::chain_t chain;
- LLURLRequest *req = new LLURLRequest(method, url);
+ LLURLRequest* req = new LLURLRequest(method, url);
req->checkRootCertificate(true);
// Insert custom headers is the caller sent any
@@ -235,7 +233,7 @@ static void request(
//to not use the proxy (read: llurlrequest.cpp)
if ((iter->first == "Pragma") && (iter->second.asString() == ""))
{
- req->useProxy(FALSE);
+ req->useProxy(false);
}
header << iter->first << ": " << iter->second.asString() ;
lldebugs << "header = " << header.str() << llendl;
@@ -258,34 +256,27 @@ static void request(
chain.push_back(LLIOPipe::ptr_t(body_injector));
}
- if (method == LLURLRequest::HTTP_GET && (offset > 0 || bytes > 0))
- {
- std::string range = llformat("Range: bytes=%d-%d", offset,offset+bytes-1);
- req->addHeader(range.c_str());
- }
-
chain.push_back(LLIOPipe::ptr_t(req));
theClientPump->addChain(chain, timeout);
}
-void LLHTTPClient::getByteRange(const std::string& url,
- S32 offset, S32 bytes,
- ResponderPtr responder,
- const LLSD& headers,
- const F32 timeout)
+void LLHTTPClient::getByteRange(
+ const std::string& url,
+ S32 offset,
+ S32 bytes,
+ ResponderPtr responder,
+ const LLSD& hdrs,
+ const F32 timeout)
{
- // *FIX: Why is the headers argument ignored? Phoenix 2008-04-28
- request(
- url,
- LLURLRequest::HTTP_GET,
- NULL,
- responder,
- timeout,
- LLSD(), // WTF? Shouldn't this be used?
- offset,
- bytes);
+ LLSD headers = hdrs;
+ if(offset > 0 || bytes > 0)
+ {
+ std::string range = llformat("bytes=%d-%d", offset, offset+bytes-1);
+ headers["Range"] = range;
+ }
+ request(url,LLURLRequest::HTTP_GET, NULL, responder, timeout, headers);
}
void LLHTTPClient::head(const std::string& url, ResponderPtr responder, const F32 timeout)
diff --git a/indra/llmessage/llhttpnode.cpp b/indra/llmessage/llhttpnode.cpp
index 196aa5f8cf..91605b4008 100644
--- a/indra/llmessage/llhttpnode.cpp
+++ b/indra/llmessage/llhttpnode.cpp
@@ -174,6 +174,26 @@ LLSD LLHTTPNode::del(const LLSD&) const
throw NotImplemented();
}
+// virtual
+void LLHTTPNode::options(ResponsePtr response, const LLSD& context) const
+{
+ //llinfos << "options context: " << context << llendl;
+
+ // default implementation constructs an url to the documentation.
+ std::string host = context[CONTEXT_REQUEST]["headers"]["host"].asString();
+ if(host.empty())
+ {
+ response->status(400, "Bad Request -- need Host header");
+ return;
+ }
+ std::ostringstream ostr;
+ ostr << "http://" << host << "/web/server/api";
+ ostr << context[CONTEXT_REQUEST]["path"].asString();
+ static const std::string DOC_HEADER("X-Documentation-URL");
+ response->addHeader(DOC_HEADER, ostr.str());
+ response->status(200, "OK");
+}
+
// virtual
LLHTTPNode* LLHTTPNode::getChild(const std::string& name, LLSD& context) const
@@ -386,6 +406,13 @@ void LLHTTPNode::Response::methodNotAllowed()
status(405, "Method Not Allowed");
}
+void LLHTTPNode::Response::addHeader(
+ const std::string& name,
+ const std::string& value)
+{
+ mHeaders[name] = value;
+}
+
void LLHTTPNode::describe(Description& desc) const
{
desc.shortInfo("unknown service (missing describe() method)");
diff --git a/indra/llmessage/llhttpnode.h b/indra/llmessage/llhttpnode.h
index e27056a51f..54715f2b38 100644
--- a/indra/llmessage/llhttpnode.h
+++ b/indra/llmessage/llhttpnode.h
@@ -82,33 +82,79 @@ public:
*/
//@{
public:
- virtual LLSD get() const;
- virtual LLSD put(const LLSD& input) const;
- virtual LLSD post(const LLSD& input) const;
- virtual LLSD del(const LLSD& context) const;
+ virtual LLSD get() const;
+ virtual LLSD put(const LLSD& input) const;
+ virtual LLSD post(const LLSD& input) const;
+ virtual LLSD del(const LLSD& context) const;
- class Response : public LLRefCount
- {
- protected:
- virtual ~Response();
+ class Response : public LLRefCount
+ {
+ protected:
+ virtual ~Response();
- public:
- virtual void result(const LLSD&) = 0;
- virtual void status(S32 code, const std::string& message) = 0;
+ public:
+ /**
+ * @brief Return the LLSD content and a 200 OK.
+ */
+ virtual void result(const LLSD&) = 0;
+
+ /**
+ * @brief return status code and reason string on http header,
+ * but do not return a payload.
+ */
+ virtual void status(S32 code, const std::string& message) = 0;
+
+ /**
+ * @brief Return no body, just status code and 'UNKNOWN ERROR'.
+ */
+ void status(S32 code);
+
+ void notFound(const std::string& message);
+ void notFound();
+ void methodNotAllowed();
+
+ /**
+ * @breif Add a name: value http header.
+ *
+ * No effort is made to ensure the response is a valid http
+ * header.
+ * The headers are stored as a map of header name : value.
+ * Though HTTP allows the same header name to be transmitted
+ * more than once, this implementation only stores a header
+ * name once.
+ * @param name The name of the header, eg, "Content-Encoding"
+ * @param value The value of the header, eg, "gzip"
+ */
+ void addHeader(const std::string& name, const std::string& value);
+
+ protected:
+ /**
+ * @brief Headers to be sent back with the HTTP response.
+ *
+ * Protected class membership since derived classes are
+ * expected to use it and there is no use case yet for other
+ * uses. If such a use case arises, I suggest making a
+ * headers() public method, and moving this member data into
+ * private.
+ */
+ LLSD mHeaders;
+ };
- void status(S32 code);
- void notFound(const std::string& message);
- void notFound();
- void methodNotAllowed();
- };
- typedef LLPointer<Response> ResponsePtr;
+ typedef LLPointer<Response> ResponsePtr;
- virtual void get(ResponsePtr, const LLSD& context) const;
- virtual void put(ResponsePtr, const LLSD& context, const LLSD& input) const;
- virtual void post(ResponsePtr, const LLSD& context, const LLSD& input) const;
- virtual void del(ResponsePtr, const LLSD& context) const;
+ virtual void get(ResponsePtr, const LLSD& context) const;
+ virtual void put(
+ ResponsePtr,
+ const LLSD& context,
+ const LLSD& input) const;
+ virtual void post(
+ ResponsePtr,
+ const LLSD& context,
+ const LLSD& input) const;
+ virtual void del(ResponsePtr, const LLSD& context) const;
+ virtual void options(ResponsePtr, const LLSD& context) const;
//@}
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index ec5cb93d69..90f8ef7638 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -57,10 +57,13 @@
static const char HTTP_VERSION_STR[] = "HTTP/1.0";
static const std::string CONTEXT_REQUEST("request");
static const std::string CONTEXT_RESPONSE("response");
+static const std::string CONTEXT_VERB("verb");
+static const std::string CONTEXT_HEADERS("headers");
static const std::string HTTP_VERB_GET("GET");
static const std::string HTTP_VERB_PUT("PUT");
static const std::string HTTP_VERB_POST("POST");
static const std::string HTTP_VERB_DELETE("DELETE");
+static const std::string HTTP_VERB_OPTIONS("OPTIONS");
static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;
static void* sTimingCallbackData = NULL;
@@ -130,6 +133,7 @@ private:
LLSD mGoodResult;
S32 mStatusCode;
std::string mStatusMessage;
+ LLSD mHeaders;
};
LLIOPipe::EStatus LLHTTPPipe::process_impl(
@@ -164,7 +168,7 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
static LLTimer timer;
timer.reset();
- std::string verb = context[CONTEXT_REQUEST]["verb"];
+ std::string verb = context[CONTEXT_REQUEST][CONTEXT_VERB];
if(verb == HTTP_VERB_GET)
{
mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
@@ -185,6 +189,10 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
{
mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
}
+ else if(verb == HTTP_VERB_OPTIONS)
+ {
+ mNode.options(LLHTTPNode::ResponsePtr(mResponse), context);
+ }
else
{
mResponse->methodNotAllowed();
@@ -231,7 +239,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
case STATE_GOOD_RESULT:
{
- context[CONTEXT_RESPONSE]["contentType"] = "application/xml";
+ LLSD headers = mHeaders;
+ headers["Content-Type"] = "application/xml";
+ context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
LLBufferStream ostr(channels, buffer.get());
LLSDSerialize::toXML(mGoodResult, ostr);
@@ -240,7 +250,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
case STATE_STATUS_RESULT:
{
- context[CONTEXT_RESPONSE]["contentType"] = "text/plain";
+ LLSD headers = mHeaders;
+ headers["Content-Type"] = "text/plain";
+ context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
context[CONTEXT_RESPONSE]["statusMessage"] = mStatusMessage;
LLBufferStream ostr(channels, buffer.get());
@@ -287,6 +299,7 @@ void LLHTTPPipe::Response::result(const LLSD& r)
mPipe->mStatusMessage = "OK";
mPipe->mGoodResult = r;
mPipe->mState = STATE_GOOD_RESULT;
+ mPipe->mHeaders = mHeaders;
mPipe->unlockChain();
}
@@ -302,6 +315,7 @@ void LLHTTPPipe::Response::status(S32 code, const std::string& message)
mPipe->mStatusCode = code;
mPipe->mStatusMessage = message;
mPipe->mState = STATE_STATUS_RESULT;
+ mPipe->mHeaders = mHeaders;
mPipe->unlockChain();
}
@@ -389,17 +403,24 @@ LLIOPipe::EStatus LLHTTPResponseHeader::process_impl(
}
ostr << HTTP_VERSION_STR << " " << code << " " << message << "\r\n";
-
- std::string type = context[CONTEXT_RESPONSE]["contentType"].asString();
- if (!type.empty())
- {
- ostr << "Content-Type: " << type << "\r\n";
- }
S32 content_length = buffer->countAfter(channels.in(), NULL);
if(0 < content_length)
{
ostr << "Content-Length: " << content_length << "\r\n";
}
+ // *NOTE: This guard can go away once the LLSD static map
+ // iterator is available. Phoenix. 2008-05-09
+ LLSD headers = context[CONTEXT_RESPONSE][CONTEXT_HEADERS];
+ if(headers.isDefined())
+ {
+ LLSD::map_iterator iter = headers.beginMap();
+ LLSD::map_iterator end = headers.endMap();
+ for(; iter != end; ++iter)
+ {
+ ostr << (*iter).first << ": " << (*iter).second.asString()
+ << "\r\n";
+ }
+ }
ostr << "\r\n";
LLChangeChannel change(channels.in(), channels.out());
@@ -606,11 +627,12 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
read_next_line = true;
LLMemoryStream header((U8*)buf, len);
header >> mVerb;
-
+
if((HTTP_VERB_GET == mVerb)
|| (HTTP_VERB_POST == mVerb)
|| (HTTP_VERB_PUT == mVerb)
- || (HTTP_VERB_DELETE == mVerb))
+ || (HTTP_VERB_DELETE == mVerb)
+ || (HTTP_VERB_OPTIONS == mVerb))
{
header >> mAbsPathAndQuery;
header >> mVersion;
@@ -721,7 +743,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
{
// hey, hey, we should have everything now, so we pass it to
// a content handler.
- context[CONTEXT_REQUEST]["verb"] = mVerb;
+ context[CONTEXT_REQUEST][CONTEXT_VERB] = mVerb;
const LLHTTPNode* node = mRootNode.traverse(mPath, context);
if(node)
{
@@ -765,7 +787,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
= mBuildContext["remote-host"];
context[CONTEXT_REQUEST]["remote-port"]
= mBuildContext["remote-port"];
- context[CONTEXT_REQUEST]["headers"] = mHeaders;
+ context[CONTEXT_REQUEST][CONTEXT_HEADERS] = mHeaders;
const LLChainIOFactory* protocolHandler
= node->getProtocolHandler();
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index 20876d630f..85cb5dd007 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -28,7 +28,6 @@ include(LScript)
include(Linking)
include(Mozlib)
include(NDOF)
-include(Smartheap)
include(TemplateCheck)
include(UI)
include(UnixInstall)
diff --git a/indra/test/lliohttpserver_tut.cpp b/indra/test/lliohttpserver_tut.cpp
index 5401d1a8ae..e5607cdad7 100644
--- a/indra/test/lliohttpserver_tut.cpp
+++ b/indra/test/lliohttpserver_tut.cpp
@@ -327,6 +327,23 @@ namespace tut
ensure_starts_with("large echo status", result, "HTTP/1.0 200 OK\r\n");
}
+ template<> template<>
+ void HTTPServiceTestObject::test<8>()
+ {
+ // test the OPTIONS http method -- the default implementation
+ // should return the X-Documentation-URL
+ std::ostringstream http_request;
+ http_request << "OPTIONS / HTTP/1.0\r\nHost: localhost\r\n\r\n";
+ bool timeout = false;
+ std::string result = makeRequest("/", http_request.str(), timeout);
+ ensure_starts_with("OPTIONS verb ok", result, "HTTP/1.0 200 OK\r\n");
+ ensure_contains(
+ "Doc url header exists",
+ result,
+ "X-Documentation-URL: http://localhost");
+ }
+
+
/* TO DO:
test generation of not found and method not allowed errors
*/