summaryrefslogtreecommitdiff
path: root/indra/llmessage/lliohttpserver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llmessage/lliohttpserver.cpp')
-rw-r--r--indra/llmessage/lliohttpserver.cpp192
1 files changed, 137 insertions, 55 deletions
diff --git a/indra/llmessage/lliohttpserver.cpp b/indra/llmessage/lliohttpserver.cpp
index 625dbb68b9..3b18a9177c 100644
--- a/indra/llmessage/lliohttpserver.cpp
+++ b/indra/llmessage/lliohttpserver.cpp
@@ -4,30 +4,25 @@
* @date 2005-10-05
* @brief Implementation of the http server classes
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2007, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
* Second Life Viewer Source Code
- * The source code in this file ("Source Code") is provided by Linden Lab
- * to you under the terms of the GNU General Public License, version 2.0
- * ("GPL"), unless you have obtained a separate licensing agreement
- * ("Other License"), formally executed by you and Linden Lab. Terms of
- * the GPL can be found in doc/GPL-license.txt in this distribution, or
- * online at http://secondlife.com/developers/opensource/gplv2
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
*
- * There are special exceptions to the terms and conditions of the GPL as
- * it is applied to this Source Code. View the full text of the exception
- * in the file doc/FLOSS-exception.txt in this software distribution, or
- * online at http://secondlife.com/developers/opensource/flossexception
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * By copying, modifying or distributing this software, you acknowledge
- * that you have read and understood your obligations described above,
- * and agree to abide by those obligations.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
- * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
- * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
- * COMPLETENESS OR PERFORMANCE.
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
* $/LicenseInfo$
*/
@@ -47,6 +42,7 @@
#include "llpumpio.h"
#include "llsd.h"
#include "llsdserialize_xml.h"
+#include "llstat.h"
#include "llstl.h"
#include "lltimer.h"
@@ -55,12 +51,15 @@
#include <boost/tokenizer.hpp>
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 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");
+const std::string CONTEXT_REQUEST("request");
+const std::string CONTEXT_RESPONSE("response");
+const std::string CONTEXT_VERB("verb");
+const std::string CONTEXT_HEADERS("headers");
+const std::string HTTP_VERB_GET("GET");
+const std::string HTTP_VERB_PUT("PUT");
+const std::string HTTP_VERB_POST("POST");
+const std::string HTTP_VERB_DELETE("DELETE");
+const std::string HTTP_VERB_OPTIONS("OPTIONS");
static LLIOHTTPServer::timing_callback_t sTimingCallback = NULL;
static void* sTimingCallbackData = NULL;
@@ -69,7 +68,12 @@ class LLHTTPPipe : public LLIOPipe
{
public:
LLHTTPPipe(const LLHTTPNode& node)
- : mNode(node), mResponse(NULL), mState(STATE_INVOKE), mChainLock(0), mStatusCode(0)
+ : mNode(node),
+ mResponse(NULL),
+ mState(STATE_INVOKE),
+ mChainLock(0),
+ mLockedPump(NULL),
+ mStatusCode(0)
{ }
virtual ~LLHTTPPipe()
{
@@ -99,12 +103,14 @@ private:
// from LLHTTPNode::Response
virtual void result(const LLSD&);
+ virtual void extendedResult(S32 code, const std::string& body, const LLSD& headers);
+
virtual void status(S32 code, const std::string& message);
void nullPipe();
private:
- Response() {;} // Must be accessed through LLPointer.
+ Response() : mPipe(NULL) {} // Must be accessed through LLPointer.
LLHTTPPipe* mPipe;
};
friend class Response;
@@ -117,7 +123,8 @@ private:
STATE_DELAYED,
STATE_LOCKED,
STATE_GOOD_RESULT,
- STATE_STATUS_RESULT
+ STATE_STATUS_RESULT,
+ STATE_EXTENDED_RESULT
};
State mState;
@@ -130,6 +137,7 @@ private:
LLSD mGoodResult;
S32 mStatusCode;
std::string mStatusMessage;
+ LLSD mHeaders;
};
LLIOPipe::EStatus LLHTTPPipe::process_impl(
@@ -164,27 +172,53 @@ 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)
{
+ LLPerfBlock getblock("http_get");
mNode.get(LLHTTPNode::ResponsePtr(mResponse), context);
}
else if(verb == HTTP_VERB_PUT)
{
+ LLPerfBlock putblock("http_put");
LLSD input;
- LLSDSerialize::fromXML(input, istr);
+ if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
+ {
+ LLSDSerialize::fromXML(input, istr);
+ }
+ else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
+ {
+ std::stringstream strstrm;
+ strstrm << istr.rdbuf();
+ input = strstrm.str();
+ }
mNode.put(LLHTTPNode::ResponsePtr(mResponse), context, input);
}
else if(verb == HTTP_VERB_POST)
{
+ LLPerfBlock postblock("http_post");
LLSD input;
- LLSDSerialize::fromXML(input, istr);
+ if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_LLSD)
+ {
+ LLSDSerialize::fromXML(input, istr);
+ }
+ else if (mNode.getContentType() == LLHTTPNode::CONTENT_TYPE_TEXT)
+ {
+ std::stringstream strstrm;
+ strstrm << istr.rdbuf();
+ input = strstrm.str();
+ }
mNode.post(LLHTTPNode::ResponsePtr(mResponse), context, input);
}
else if(verb == HTTP_VERB_DELETE)
{
+ LLPerfBlock delblock("http_delete");
mNode.del(LLHTTPNode::ResponsePtr(mResponse), context);
}
+ else if(verb == HTTP_VERB_OPTIONS)
+ {
+ mNode.options(LLHTTPNode::ResponsePtr(mResponse), context);
+ }
else
{
mResponse->methodNotAllowed();
@@ -203,7 +237,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
}
// Log all HTTP transactions.
- llinfos << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
+ // TODO: Add a way to log these to their own file instead of indra.log
+ // It is just too spammy to be in indra.log.
+ lldebugs << verb << " " << context[CONTEXT_REQUEST]["path"].asString()
<< " " << mStatusCode << " " << mStatusMessage << " " << delta
<< "s" << llendl;
@@ -229,7 +265,9 @@ LLIOPipe::EStatus LLHTTPPipe::process_impl(
case STATE_GOOD_RESULT:
{
- context[CONTEXT_RESPONSE]["contentType"] = "application/xml";
+ LLSD headers = mHeaders;
+ headers["Content-Type"] = "application/llsd+xml";
+ context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = headers;
LLBufferStream ostr(channels, buffer.get());
LLSDSerialize::toXML(mGoodResult, ostr);
@@ -238,11 +276,22 @@ 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());
- ostr << mStatusMessage << std::ends;
+ ostr << mStatusMessage;
+
+ return STATUS_DONE;
+ }
+ case STATE_EXTENDED_RESULT:
+ {
+ context[CONTEXT_RESPONSE][CONTEXT_HEADERS] = mHeaders;
+ context[CONTEXT_RESPONSE]["statusCode"] = mStatusCode;
+ LLBufferStream ostr(channels, buffer.get());
+ ostr << mStatusMessage;
return STATUS_DONE;
}
@@ -285,9 +334,25 @@ void LLHTTPPipe::Response::result(const LLSD& r)
mPipe->mStatusMessage = "OK";
mPipe->mGoodResult = r;
mPipe->mState = STATE_GOOD_RESULT;
+ mPipe->mHeaders = mHeaders;
mPipe->unlockChain();
}
+void LLHTTPPipe::Response::extendedResult(S32 code, const std::string& body, const LLSD& headers)
+{
+ if(! mPipe)
+ {
+ llwarns << "LLHTTPPipe::Response::status: NULL pipe" << llendl;
+ return;
+ }
+
+ mPipe->mStatusCode = code;
+ mPipe->mStatusMessage = body;
+ mPipe->mHeaders = headers;
+ mPipe->mState = STATE_EXTENDED_RESULT;
+ mPipe->unlockChain();
+}
+
// virtual
void LLHTTPPipe::Response::status(S32 code, const std::string& message)
{
@@ -300,6 +365,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();
}
@@ -336,7 +402,7 @@ void LLHTTPPipe::unlockChain()
class LLHTTPResponseHeader : public LLIOPipe
{
public:
- LLHTTPResponseHeader() {}
+ LLHTTPResponseHeader() : mCode(0) {}
virtual ~LLHTTPResponseHeader() {}
protected:
@@ -387,17 +453,25 @@ 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());
@@ -446,7 +520,7 @@ protected:
* seek orfor string assignment.
* @returns Returns true if a line was found.
*/
- bool readLine(
+ bool readHeaderLine(
const LLChannelDescriptors& channels,
buffer_ptr_t buffer,
U8* dest,
@@ -517,7 +591,7 @@ LLHTTPResponder::~LLHTTPResponder()
//lldebugs << "destroying LLHTTPResponder" << llendl;
}
-bool LLHTTPResponder::readLine(
+bool LLHTTPResponder::readHeaderLine(
const LLChannelDescriptors& channels,
buffer_ptr_t buffer,
U8* dest,
@@ -595,7 +669,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
#endif
PUMP_DEBUG;
- if(readLine(channels, buffer, (U8*)buf, len))
+ if(readHeaderLine(channels, buffer, (U8*)buf, len))
{
bool read_next_line = false;
bool parse_all = true;
@@ -604,11 +678,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;
@@ -658,7 +733,13 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
if(read_next_line)
{
len = HEADER_BUFFER_SIZE;
- readLine(channels, buffer, (U8*)buf, len);
+ if (!readHeaderLine(channels, buffer, (U8*)buf, len))
+ {
+ // Failed to read the header line, probably too long.
+ // readHeaderLine already marked the channel/buffer as bad.
+ keep_parsing = false;
+ break;
+ }
}
if(0 == len)
{
@@ -683,7 +764,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
read_next_line = true;
std::string name(buf, pos_colon - buf);
std::string value(pos_colon + 2);
- LLString::toLower(name);
+ LLStringUtil::toLower(name);
if("content-length" == name)
{
lldebugs << "Content-Length: " << value << llendl;
@@ -691,7 +772,7 @@ LLIOPipe::EStatus LLHTTPResponder::process_impl(
}
else
{
- LLString::trimTail(value);
+ LLStringUtil::trimTail(value);
mHeaders[name] = value;
}
}
@@ -719,12 +800,12 @@ 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)
{
- lldebugs << "LLHTTPResponder::process_impl found node for "
- << mAbsPathAndQuery << llendl;
+ //llinfos << "LLHTTPResponder::process_impl found node for "
+ // << mAbsPathAndQuery << llendl;
// Copy everything after mLast read to the out.
LLBufferArray::segment_iterator_t seg_iter;
@@ -763,12 +844,13 @@ 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();
if (protocolHandler)
{
+ lldebugs << "HTTP context: " << context << llendl;
protocolHandler->build(chain, context);
}
else