Skip to content

Commit

Permalink
Merge pull request #5118: DragonDisk fails to create directories via …
Browse files Browse the repository at this point in the history
…S3: MissingContentLength

Reviewed-by: Loic Dachary <ldachary@redhat.com>
  • Loading branch information
ldachary committed Jul 15, 2015
2 parents 1e5d79a + 56c2688 commit da1ec57
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
6 changes: 6 additions & 0 deletions doc/radosgw/config-ref.rst
Expand Up @@ -316,6 +316,12 @@ Ceph configuration file, the default value will be set automatically.
:Default: ``admin``


``rgw content length compat``

:Description: Enable compatability handling of FCGI requests with both CONTENT_LENGTH AND HTTP_CONTENT_LENGTH set.
:Type: Boolean
:Default: ``false``

Regions
=======

Expand Down
1 change: 1 addition & 0 deletions src/common/config_opts.h
Expand Up @@ -947,6 +947,7 @@ OPTION(rgw_socket_path, OPT_STR, "") // path to unix domain socket, if not spe
OPTION(rgw_host, OPT_STR, "") // host for radosgw, can be an IP, default is 0.0.0.0
OPTION(rgw_port, OPT_STR, "") // port to listen, format as "8080" "5000", if not specified, rgw will not run external fcgi
OPTION(rgw_dns_name, OPT_STR, "")
OPTION(rgw_content_length_compat, OPT_BOOL, false) // Check both HTTP_CONTENT_LENGTH and CONTENT_LENGTH in fcgi env
OPTION(rgw_script_uri, OPT_STR, "") // alternative value for SCRIPT_URI if not set in request
OPTION(rgw_request_uri, OPT_STR, "") // alternative value for REQUEST_URI if not set in request
OPTION(rgw_swift_url, OPT_STR, "") // the swift url, being published by the internal swift auth
Expand Down
69 changes: 68 additions & 1 deletion src/rgw/rgw_rest.cc
Expand Up @@ -1301,6 +1301,22 @@ RGWRESTMgr::~RGWRESTMgr()
delete default_mgr;
}

static int64_t parse_content_length(const char *content_length)
{
int64_t len = -1;

if (*content_length == '\0') {
len = 0;
} else {
string err;
len = strict_strtoll(content_length, 10, &err);
if (!err.empty()) {
len = -1;
}
}

return len;
}
int RGWREST::preprocess(struct req_state *s, RGWClientIO *cio)
{
req_info& info = s->info;
Expand Down Expand Up @@ -1348,7 +1364,58 @@ int RGWREST::preprocess(struct req_state *s, RGWClientIO *cio)
}

url_decode(s->info.request_uri, s->decoded_uri);
s->length = info.env->get("CONTENT_LENGTH");

/* FastCGI specification, section 6.3
* http://www.fastcgi.com/devkit/doc/fcgi-spec.html#S6.3
* ===
* The Authorizer application receives HTTP request information from the Web
* server on the FCGI_PARAMS stream, in the same format as a Responder. The
* Web server does not send CONTENT_LENGTH, PATH_INFO, PATH_TRANSLATED, and
* SCRIPT_NAME headers.
* ===
* Ergo if we are in Authorizer role, we MUST look at HTTP_CONTENT_LENGTH
* instead of CONTENT_LENGTH for the Content-Length.
*
* There is one slight wrinkle in this, and that's older versions of
* nginx/lighttpd/apache setting BOTH headers. As a result, we have to check
* both headers and can't always simply pick A or B.
*/
const char* content_length = info.env->get("CONTENT_LENGTH");
const char* http_content_length = info.env->get("HTTP_CONTENT_LENGTH");
if (!http_content_length != !content_length) {
/* Easy case: one or the other is missing */
s->length = (content_length ? content_length : http_content_length);
} else if (s->cct->_conf->rgw_content_length_compat && content_length && http_content_length) {
/* Hard case: Both are set, we have to disambiguate */
int64_t content_length_i, http_content_length_i;

content_length_i = parse_content_length(content_length);
http_content_length_i = parse_content_length(http_content_length);

// Now check them:
if (http_content_length_i < 0) {
// HTTP_CONTENT_LENGTH is invalid, ignore it
} else if (content_length_i < 0) {
// CONTENT_LENGTH is invalid, and HTTP_CONTENT_LENGTH is valid
// Swap entries
content_length = http_content_length;
} else {
// both CONTENT_LENGTH and HTTP_CONTENT_LENGTH are valid
// Let's pick the larger size
if (content_length_i < http_content_length_i) {
// prefer the larger value
content_length = http_content_length;
}
}
s->length = content_length;
// End of: else if (s->cct->_conf->rgw_content_length_compat && content_length &&
// http_content_length)
} else {
/* no content length was defined */
s->length = NULL;
}


if (s->length) {
if (*s->length == '\0') {
s->content_length = 0;
Expand Down

0 comments on commit da1ec57

Please sign in to comment.