summaryrefslogtreecommitdiff
path: root/indra/llmessage/llhttpconstants.cpp
diff options
context:
space:
mode:
authorDon Kjer <don@lindenlab.com>2013-03-13 06:26:25 +0000
committerDon Kjer <don@lindenlab.com>2013-03-13 06:26:25 +0000
commitf945415210f0e18c2c6d941fda6b7d45cb0f06f1 (patch)
treecf93ca0d9596a82a8fc7a4d1b1f0ee263ea5549e /indra/llmessage/llhttpconstants.cpp
parent54cdc322b8f2bd35b289cacf3493622e7cc51194 (diff)
Large changes to the LLCurl::Responder API, as well as pulling in some changes to common libraries from the server codebase:
* Additional error checking in http handlers. * Uniform log spam for http errors. * Switch to using constants for http heads and status codes. * Fixed bugs in incorrectly checking if parsing LLSD xml resulted in an error. * Reduced spam regarding LLSD parsing errors in the default completedRaw http handler. It should not longer be necessary to short-circuit completedRaw to avoid spam. * Ported over a few bug fixes from the server code. * Switch mode http status codes to use S32 instead of U32. * Ported LLSD::asStringRef from server code; avoids copying strings all over the place. * Ported server change to LLSD::asBinary; this always returns a reference now instead of copying the entire binary blob. * Ported server pretty notation format (and pretty binary format) to llsd serialization. * The new LLCurl::Responder API no longer has two error handlers to choose from. Overriding the following methods have been deprecated: ** error - use httpFailure ** errorWithContent - use httpFailure ** result - use httpSuccess ** completed - use httpCompleted ** completedHeader - no longer necessary; call getResponseHeaders() from a completion method to obtain these headers. * In order to 'catch' a completed http request, override one of these methods: ** httpSuccess - Called for any 2xx status code. ** httpFailure - Called for any non-2xx status code. ** httpComplete - Called for all status codes. Default implementation is to call either httpSuccess or httpFailure. * It is recommended to keep these methods protected/private in order to avoid triggering of these methods without using a 'push' method (see below). * Uniform error handling should followed whenever possible by calling a variant of this during httpFailure: ** llwarns << dumpResponse() << llendl; * Be sure to include LOG_CLASS(your_class_name) in your class in order for the log entry to give more context. * In order to 'push' a result into the responder, you should no longer call error, errorWithContent, result, or completed. * Nor should you directly call httpSuccess/Failure/Completed (unless passing a message up to a parent class). * Instead, you can set the internal content of a responder and trigger a corresponding method using the following methods: ** successResult - Sets results and calls httpSuccess ** failureResult - Sets results and calls httpFailure ** completedResult - Sets results and calls httpCompleted * To obtain information about a the response from a reponder method, use the following getters: ** getStatus - HTTP status code ** getReason - Reason string ** getContent - Content (Parsed body LLSD) ** getResponseHeaders - Response Headers (LLSD map) ** getHTTPMethod - HTTP method of the request ** getURL - URL of the request * It is still possible to override completeRaw if you want to manipulate data directly out of LLPumpIO. * See indra/llmessage/llcurl.h for more information.
Diffstat (limited to 'indra/llmessage/llhttpconstants.cpp')
-rw-r--r--indra/llmessage/llhttpconstants.cpp219
1 files changed, 219 insertions, 0 deletions
diff --git a/indra/llmessage/llhttpconstants.cpp b/indra/llmessage/llhttpconstants.cpp
new file mode 100644
index 0000000000..2134024a14
--- /dev/null
+++ b/indra/llmessage/llhttpconstants.cpp
@@ -0,0 +1,219 @@
+/**
+ * @file llhttpconstants.cpp
+ * @brief Implementation of the HTTP request / response constant lookups
+ *
+ * $LicenseInfo:firstyear=2013&license=viewergpl$
+ *
+ * Copyright (c) 2013, Linden Research, Inc.
+ *
+ * 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://secondlifegrid.net/programs/open_source/licensing/gplv2
+ *
+ * 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://secondlifegrid.net/programs/open_source/licensing/flossexception
+ *
+ * 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.
+ *
+ * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
+ * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
+ * COMPLETENESS OR PERFORMANCE.
+ * $/LicenseInfo$
+ */
+
+#include "linden_common.h"
+#include "llhttpconstants.h"
+#include "lltimer.h"
+
+// for curl_getdate() (apparently parsing RFC 1123 dates is hard)
+#include <curl/curl.h>
+
+const std::string HTTP_HEADER_ACCEPT("Accept");
+const std::string HTTP_HEADER_ACCEPT_CHARSET("Accept-Charset");
+const std::string HTTP_HEADER_ACCEPT_ENCODING("Accept-Encoding");
+const std::string HTTP_HEADER_ACCEPT_LANGUAGE("Accept-Language");
+const std::string HTTP_HEADER_ACCEPT_RANGES("Accept-Ranges");
+const std::string HTTP_HEADER_AGE("Age");
+const std::string HTTP_HEADER_ALLOW("Allow");
+const std::string HTTP_HEADER_AUTHORIZATION("Authorization");
+const std::string HTTP_HEADER_CACHE_CONTROL("Cache-Control");
+const std::string HTTP_HEADER_CONNECTION("Connection");
+const std::string HTTP_HEADER_CONTENT_DESCRIPTION("Content-Description");
+const std::string HTTP_HEADER_CONTENT_ENCODING("Content-Encoding");
+const std::string HTTP_HEADER_CONTENT_ID("Content-ID");
+const std::string HTTP_HEADER_CONTENT_LANGUAGE("Content-Language");
+const std::string HTTP_HEADER_CONTENT_LENGTH("Content-Length");
+const std::string HTTP_HEADER_CONTENT_LOCATION("Content-Location");
+const std::string HTTP_HEADER_CONTENT_MD5("Content-MD5");
+const std::string HTTP_HEADER_CONTENT_RANGE("Content-Range");
+const std::string HTTP_HEADER_CONTENT_TRANSFER_ENCODING("Content-Transfer-Encoding");
+const std::string HTTP_HEADER_CONTENT_TYPE("Content-Type");
+const std::string HTTP_HEADER_COOKIE("Cookie");
+const std::string HTTP_HEADER_DATE("Date");
+const std::string HTTP_HEADER_DESTINATION("Destination");
+const std::string HTTP_HEADER_ETAG("ETag");
+const std::string HTTP_HEADER_EXPECT("Expect");
+const std::string HTTP_HEADER_EXPIRES("Expires");
+const std::string HTTP_HEADER_FROM("From");
+const std::string HTTP_HEADER_HOST("Host");
+const std::string HTTP_HEADER_IF_MATCH("If-Match");
+const std::string HTTP_HEADER_IF_MODIFIED_SINCE("If-Modified-Since");
+const std::string HTTP_HEADER_IF_NONE_MATCH("If-None-Match");
+const std::string HTTP_HEADER_IF_RANGE("If-Range");
+const std::string HTTP_HEADER_IF_UNMODIFIED_SINCE("If-Unmodified-Since");
+const std::string HTTP_HEADER_KEEP_ALIVE("Keep-Alive");
+const std::string HTTP_HEADER_LAST_MODIFIED("Last-Modified");
+const std::string HTTP_HEADER_LOCATION("Location");
+const std::string HTTP_HEADER_MAX_FORWARDS("Max-Forwards");
+const std::string HTTP_HEADER_MIME_VERSION("MIME-Version");
+const std::string HTTP_HEADER_PRAGMA("Pragma");
+const std::string HTTP_HEADER_PROXY_AUTHENTICATE("Proxy-Authenticate");
+const std::string HTTP_HEADER_PROXY_AUTHORIZATION("Proxy-Authorization");
+const std::string HTTP_HEADER_RANGE("Range");
+const std::string HTTP_HEADER_REFERER("Referer");
+const std::string HTTP_HEADER_RETRY_AFTER("Retry-After");
+const std::string HTTP_HEADER_SERVER("Server");
+const std::string HTTP_HEADER_SET_COOKIE("Set-Cookie");
+const std::string HTTP_HEADER_TE("TE");
+const std::string HTTP_HEADER_TRAILER("Trailer");
+const std::string HTTP_HEADER_TRANSFER_ENCODING("Transfer-Encoding");
+const std::string HTTP_HEADER_UPGRADE("Upgrade");
+const std::string HTTP_HEADER_USER_AGENT("User-Agent");
+const std::string HTTP_HEADER_VARY("Vary");
+const std::string HTTP_HEADER_VIA("Via");
+const std::string HTTP_HEADER_WARNING("Warning");
+const std::string HTTP_HEADER_WWW_AUTHENTICATE("WWW-Authenticate");
+
+
+// Sadly, our proxied headers do not follow http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html
+// We need to deal with lowercase headers
+const std::string HTTP_HEADER_LOWER_ACCEPT_LANGUAGE("accept-language");
+const std::string HTTP_HEADER_LOWER_CACHE_CONTROL("cache-control");
+const std::string HTTP_HEADER_LOWER_CONTENT_LENGTH("content-length");
+const std::string HTTP_HEADER_LOWER_CONTENT_TYPE("content-type");
+const std::string HTTP_HEADER_LOWER_HOST("host");
+const std::string HTTP_HEADER_LOWER_USER_AGENT("user-agent");
+const std::string HTTP_HEADER_LOWER_X_FORWARDED_FOR("x-forwarded-for");
+
+const std::string HTTP_CONTENT_LLSD_XML("application/llsd+xml");
+const std::string HTTP_CONTENT_OCTET_STREAM("application/octet-stream");
+const std::string HTTP_CONTENT_XML("application/xml");
+const std::string HTTP_CONTENT_JSON("application/json");
+const std::string HTTP_CONTENT_TEXT_HTML("text/html");
+const std::string HTTP_CONTENT_TEXT_HTML_UTF8("text/html; charset=utf-8");
+const std::string HTTP_CONTENT_TEXT_PLAIN_UTF8("text/plain; charset=utf-8");
+const std::string HTTP_CONTENT_TEXT_LLSD("text/llsd");
+const std::string HTTP_CONTENT_TEXT_XML("text/xml");
+const std::string HTTP_CONTENT_TEXT_LSL("text/lsl");
+const std::string HTTP_CONTENT_TEXT_PLAIN("text/plain");
+const std::string HTTP_CONTENT_IMAGE_X_J2C("image/x-j2c");
+const std::string HTTP_CONTENT_IMAGE_J2C("image/j2c");
+const std::string HTTP_CONTENT_IMAGE_JPEG("image/jpeg");
+const std::string HTTP_CONTENT_IMAGE_PNG("image/png");
+const std::string HTTP_CONTENT_IMAGE_BMP("image/bmp");
+
+const std::string HTTP_VERB_INVALID("(invalid)");
+const std::string HTTP_VERB_HEAD("HEAD");
+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_MOVE("MOVE");
+const std::string HTTP_VERB_OPTIONS("OPTIONS");
+
+const std::string& httpMethodAsVerb(EHTTPMethod method)
+{
+ static const std::string VERBS[] =
+ {
+ HTTP_VERB_INVALID,
+ HTTP_VERB_HEAD,
+ HTTP_VERB_GET,
+ HTTP_VERB_PUT,
+ HTTP_VERB_POST,
+ HTTP_VERB_DELETE,
+ HTTP_VERB_MOVE,
+ HTTP_VERB_OPTIONS
+ };
+ if(((S32)method <=0) || ((S32)method >= HTTP_METHOD_COUNT))
+ {
+ return VERBS[0];
+ }
+ return VERBS[method];
+}
+
+bool isHttpInformationalStatus(S32 status)
+{
+ // Check for status 1xx.
+ return((100 <= status) && (status < 200));
+}
+
+bool isHttpGoodStatus(S32 status)
+{
+ // Check for status 2xx.
+ return((200 <= status) && (status < 300));
+}
+
+bool isHttpRedirectStatus(S32 status)
+{
+ // Check for status 3xx.
+ return((300 <= status) && (status < 400));
+}
+
+bool isHttpClientErrorStatus(S32 status)
+{
+ // Status 499 is sometimes used for re-interpreted status 2xx errors
+ // based on body content. Treat these as potentially retryable 'server' status errors,
+ // since we do not have enough context to know if this will always fail.
+ if (HTTP_INTERNAL_ERROR == status) return false;
+
+ // Check for status 5xx.
+ return((400 <= status) && (status < 500));
+}
+
+bool isHttpServerErrorStatus(S32 status)
+{
+ // Status 499 is sometimes used for re-interpreted status 2xx errors.
+ // Allow retry of these, since we don't have enough information in this
+ // context to know if this will always fail.
+ if (HTTP_INTERNAL_ERROR == status) return true;
+
+ // Check for status 5xx.
+ return((500 <= status) && (status < 600));
+}
+
+// Parses 'Retry-After' header contents and returns seconds until retry should occur.
+bool getSecondsUntilRetryAfter(const std::string& retry_after, F32& seconds_to_wait)
+{
+ // *TODO: This needs testing! Not in use yet.
+ // Examples of Retry-After headers:
+ // Retry-After: Fri, 31 Dec 1999 23:59:59 GMT
+ // Retry-After: 120
+
+ // Check for number of seconds version, first:
+ char* end = 0;
+ // Parse as double
+ double seconds = std::strtod(retry_after.c_str(), &end);
+ if ( end != 0 && *end == 0 )
+ {
+ // Successful parse
+ seconds_to_wait = (F32) seconds;
+ return true;
+ }
+
+ // Parse rfc1123 date.
+ time_t date = curl_getdate(retry_after.c_str(), NULL );
+ if (-1 == date) return false;
+
+ seconds_to_wait = (F32)date - (F32)LLTimer::getTotalSeconds();
+ return true;
+}
+