summaryrefslogtreecommitdiff
path: root/indra/llmessage/llhttpconstants.cpp
blob: 2134024a148b3db7fe08a47ea867f0b720310b34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
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;
}