1
0
Fork 0

Merge branch 'devel' of https://github.com/triAGENS/ArangoDB into devel

This commit is contained in:
Heiko Kernbach 2013-10-08 19:52:49 +02:00
commit 5570caac29
10 changed files with 117 additions and 12 deletions

View File

@ -1,6 +1,21 @@
v1.4
----
* added startup option `--server.allow-method-override`
This option can be set to allow overriding the HTTP request method in a request using
one of the following custom headers:
- x-http-method-override
- x-http-method
- x-method-override
This allows bypassing proxies and tools that would otherwise just let certain types of
requests pass. Enabling this option may impose a security risk, so it should only be
used in very controlled environments.
The default value for this option is `false` (no method overriding allowed).
* added "details" URL parameter for bulk import API
Setting the `details` URL parameter to `true` in a call to POST `/_api/import` will make

View File

@ -425,6 +425,16 @@ Command-Line Options added {#NewFeatures14Options}
The following command-line options have been added for _arangod_ in ArangoDB 1.4:
* `--server.allow-method-override`: this option can be set to allow overriding the
HTTP request method in a request using one of the following custom headers:
- x-http-method-override
- x-http-method
- x-method-override
Using this option allows bypassing proxies and tools that would otherwise just
let certain types of requests pass. Enabling this option may impose a security
risk, so it should only be used in very controlled environments.
The default value for this option is `false` (no method overriding allowed).
* `--scheduler.maximal-queue-size`: limits the size of the asynchronous request
execution queue. Please have a look at @ref NewFeatures14Async for more details.

View File

@ -116,6 +116,10 @@ Command-Line Options for arangod {#CommandLineArangod}
@anchor CommandLineArangoKeepAliveTimeout
@copydetails triagens::rest::ApplicationEndpointServer::_keepAliveTimeout
@CLEARPAGE
@anchor CommandLineArangoAllowMethodOverride
@copydetails triagens::rest::ApplicationEndpointServer::_allowMethodOverride
@CLEARPAGE
@anchor CommandLineArangoKeyFile
@copydetails triagens::rest::ApplicationEndpointServer::_httpsKeyfile

View File

@ -157,7 +157,7 @@ Handler::status_e RestBatchHandler::execute() {
// set up request object for the part
LOGGER_TRACE("part header is " << string(headerStart, headerLength));
HttpRequest* request = new HttpRequest(_request->connectionInfo(), headerStart, headerLength);
HttpRequest* request = new HttpRequest(_request->connectionInfo(), headerStart, headerLength, false);
if (request == 0) {
generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_OUT_OF_MEMORY);

View File

@ -101,6 +101,7 @@ ApplicationEndpointServer::ApplicationEndpointServer (ApplicationServer* applica
_httpPort(),
_endpoints(),
_keepAliveTimeout(300.0),
_allowMethodOverride(false),
_backlogSize(10),
_httpsKeyfile(),
_cafile(),
@ -216,6 +217,7 @@ void ApplicationEndpointServer::setupOptions (map<string, ProgramOptionsDescript
;
options[ApplicationServer::OPTIONS_SERVER + ":help-admin"]
("server.allow-method-override", &_allowMethodOverride, "allow HTTP method override using special headers")
("server.keep-alive-timeout", &_keepAliveTimeout, "keep-alive timeout in seconds")
("server.backlog-size", &_backlogSize, "listen backlog size")
;
@ -543,6 +545,7 @@ bool ApplicationEndpointServer::prepare () {
_endpointList.dump();
_handlerFactory = new HttpHandlerFactory(_authenticationRealm,
_allowMethodOverride,
_setContext,
_contextData);

View File

@ -404,6 +404,33 @@ namespace triagens {
double _keepAliveTimeout;
////////////////////////////////////////////////////////////////////////////////
/// @brief allow HTTP method override via custom headers?
///
/// @CMDOPT{\--server.allow-method-override}
///
/// When this option is set to `true`, the HTTP request method will optionally
/// be fetched from one of the following HTTP request headers if present in
/// the request:
///
/// - `x-http-method`
/// - `x-http-method-override`
/// - `x-method-override`
///
/// If the option is set to `true` and any of these headers is set, the
/// request method will be overriden by the value of the header. For example,
/// this allows issuing an HTTP DELETE request which to the outside world will
/// look like an HTTP GET request. This allows bypassing proxies and tools that
/// will only let certain request types pass.
///
/// Setting this option to `true` may impose a security risk so it should only
/// be used in controlled environments.
///
/// The default value for this option is `false`.
////////////////////////////////////////////////////////////////////////////////
bool _allowMethodOverride;
////////////////////////////////////////////////////////////////////////////////
/// @brief listen backlog size
///

View File

@ -56,9 +56,11 @@ using namespace std;
////////////////////////////////////////////////////////////////////////////////
HttpHandlerFactory::HttpHandlerFactory (std::string const& authenticationRealm,
bool allowMethodOverride,
context_fptr setContext,
void* setContextData)
: _authenticationRealm(authenticationRealm),
_allowMethodOverride(allowMethodOverride),
_setContext(setContext),
_setContextData(setContextData),
_notFound(0) {
@ -70,6 +72,7 @@ HttpHandlerFactory::HttpHandlerFactory (std::string const& authenticationRealm,
HttpHandlerFactory::HttpHandlerFactory (HttpHandlerFactory const& that)
: _authenticationRealm(that._authenticationRealm),
_allowMethodOverride(that._allowMethodOverride),
_setContext(that._setContext),
_setContextData(that._setContextData),
_constructors(that._constructors),
@ -84,9 +87,10 @@ HttpHandlerFactory::HttpHandlerFactory (HttpHandlerFactory const& that)
HttpHandlerFactory& HttpHandlerFactory::operator= (HttpHandlerFactory const& that) {
if (this != &that) {
_authenticationRealm = that._authenticationRealm,
_setContext = that._setContext,
_setContextData = that._setContextData,
_authenticationRealm = that._authenticationRealm;
_allowMethodOverride = that._allowMethodOverride;
_setContext = that._setContext;
_setContextData = that._setContextData;
_constructors = that._constructors;
_datas = that._datas;
_prefixes = that._prefixes;
@ -180,7 +184,8 @@ HttpRequest* HttpHandlerFactory::createRequest (ConnectionInfo const& info,
}
#endif
HttpRequest* request = new HttpRequest(info, ptr, length);
HttpRequest* request = new HttpRequest(info, ptr, length, _allowMethodOverride);
if (request != 0) {
setRequestContext(request);
}

View File

@ -126,6 +126,7 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
HttpHandlerFactory (std::string const&,
bool,
context_fptr,
void*);
@ -247,6 +248,12 @@ namespace triagens {
string _authenticationRealm;
////////////////////////////////////////////////////////////////////////////////
/// @brief allow overriding HTTP request method with custom headers
////////////////////////////////////////////////////////////////////////////////
bool _allowMethodOverride;
////////////////////////////////////////////////////////////////////////////////
/// @brief set context callback
////////////////////////////////////////////////////////////////////////////////

View File

@ -56,7 +56,10 @@ static char const* EMPTY_STR = "";
/// @brief http request constructor
////////////////////////////////////////////////////////////////////////////////
HttpRequest::HttpRequest (ConnectionInfo const& info, char const* header, size_t length)
HttpRequest::HttpRequest (ConnectionInfo const& info,
char const* header,
size_t length,
bool allowMethodOverride)
: _requestPath(EMPTY_STR),
_headers(5),
_values(10),
@ -74,7 +77,8 @@ HttpRequest::HttpRequest (ConnectionInfo const& info, char const* header, size_t
_databaseName(),
_user(),
_requestContext(0),
_isRequestContextOwner(false) {
_isRequestContextOwner(false),
_allowMethodOverride(allowMethodOverride) {
// copy request - we will destroy/rearrange the content to compute the
// headers and values in-place
@ -110,7 +114,8 @@ HttpRequest::HttpRequest ()
_databaseName(),
_user(),
_requestContext(0),
_isRequestContextOwner(false) {
_isRequestContextOwner(false),
_allowMethodOverride(false) {
}
////////////////////////////////////////////////////////////////////////////////
@ -503,8 +508,10 @@ size_t HttpRequest::bodySize () const {
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////
int HttpRequest::setBody (char const* newBody, size_t length) {
int HttpRequest::setBody (char const* newBody,
size_t length) {
_body = TRI_DuplicateString2Z(TRI_UNKNOWN_MEM_ZONE, newBody, length);
if (_body == 0) {
return TRI_ERROR_OUT_OF_MEMORY;
}
@ -531,7 +538,9 @@ TRI_json_t* HttpRequest::toJson (char** errmsg) {
/// @brief sets a header field
////////////////////////////////////////////////////////////////////////////////
void HttpRequest::setHeader (char const* key, size_t keyLength, char const* value) {
void HttpRequest::setHeader (char const* key,
size_t keyLength,
char const* value) {
if (keyLength == 14 && memcmp(key, "content-length", keyLength) == 0) { // 14 = strlen("content-length")
_contentLength = TRI_Int64String(value);
}
@ -539,6 +548,22 @@ void HttpRequest::setHeader (char const* key, size_t keyLength, char const* valu
parseCookies(value);
}
else {
if (_allowMethodOverride &&
keyLength >= 13 &&
*key == 'x' && *(key + 1) == '-') {
// handle x-... headers
// override HTTP method?
if ((keyLength == 13 && memcmp(key, "x-http-method", keyLength) == 0) ||
(keyLength == 17 && memcmp(key, "x-method-override", keyLength) == 0) ||
(keyLength == 22 && memcmp(key, "x-http-method-override", keyLength) == 0)) {
string overridenType(value);
StringUtils::tolowerInPlace(&overridenType);
_type = getRequestType(overridenType.c_str(), overridenType.size());
}
}
_headers.insert(key, keyLength, value);
}
}
@ -623,7 +648,8 @@ void HttpRequest::setUser (string const& user) {
/// @brief determine the header type
////////////////////////////////////////////////////////////////////////////////
HttpRequest::HttpRequestType HttpRequest::getRequestType (const char* ptr, const size_t length) {
HttpRequest::HttpRequestType HttpRequest::getRequestType (const char* ptr,
const size_t length) {
switch (length) {
case 3:
if (ptr[0] == 'g' && ptr[1] == 'e' && ptr[2] == 't') {

View File

@ -119,7 +119,8 @@ namespace triagens {
HttpRequest (ConnectionInfo const&,
char const*,
size_t);
size_t,
bool);
////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
@ -687,6 +688,13 @@ namespace triagens {
////////////////////////////////////////////////////////////////////////////////
bool _isRequestContextOwner;
////////////////////////////////////////////////////////////////////////////////
/// @brief whether or not overriding the HTTP method via custom headers
/// (x-http-method, x-method-override or x-http-method-override) is allowed
////////////////////////////////////////////////////////////////////////////////
bool _allowMethodOverride;
};
}
}