blob: 12abda25ca090f91c927b8068ddaa89041737f01 [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Copyright (c) 2013 Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "net/http/shell/http_stream_shell_loader.h"
#include "net/base/io_buffer.h"
#include "net/base/net_errors.h"
#include "net/http/http_request_info.h"
#include "net/http/http_response_headers.h"
#include "net/http/http_response_info.h"
#include "net/http/http_stream_parser.h"
#include "net/http/http_util.h"
// These are a few helper functions used by sub classes implemented for
// different platforms. The original code of these functions below are from
// chromium/net/http/http_stream_parser.cc.
namespace net {
/* static */
std::string HttpStreamShellLoader::GetResponseHeaderLines(
const net::HttpResponseHeaders& headers) {
std::string raw_headers = headers.raw_headers();
const char* null_separated_headers = raw_headers.c_str();
const char* header_line = null_separated_headers;
std::string cr_separated_headers;
while (header_line[0] != 0) {
cr_separated_headers += header_line;
cr_separated_headers += "\n";
header_line += strlen(header_line) + 1;
}
return cr_separated_headers;
}
// Return true if |headers| contain multiple |field_name| fields with different
// values.
/* static */
bool HttpStreamShellLoader::HeadersContainMultipleCopiesOfField(
const net::HttpResponseHeaders& headers,
const std::string& field_name) {
void* it = NULL;
std::string field_value;
if (!headers.EnumerateHeader(&it, field_name, &field_value))
return false;
// There's at least one |field_name| header. Check if there are any more
// such headers, and if so, return true if they have different values.
std::string field_value2;
while (headers.EnumerateHeader(&it, field_name, &field_value2)) {
if (field_value != field_value2)
return true;
}
return false;
}
// Parser response headers.
int HttpStreamShellLoader::ParseResponseHeaders(const char* buf,
int buf_len, const HttpRequestInfo* request, HttpResponseInfo* response) {
// Do the parse
std::string raw_headers = HttpUtil::AssembleRawHeaders(buf, buf_len);
response->headers = new HttpResponseHeaders(raw_headers);
// Headers are parsed, validate a few special cases
DCHECK(response->headers);
// Check for multiple Content-Length headers with no Transfer-Encoding
// header. If they exist, and have distinct values, it's a potential
// response smuggling attack.
if (!response->headers->HasHeader("Transfer-Encoding")) {
if (HeadersContainMultipleCopiesOfField(*response->headers,
"Content-Length"))
return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_LENGTH;
}
// Check for multiple Content-Disposition or Location headers. If they
// exist, it's also a potential response smuggling attack.
if (HeadersContainMultipleCopiesOfField(*response->headers,
"Content-Disposition"))
return ERR_RESPONSE_HEADERS_MULTIPLE_CONTENT_DISPOSITION;
if (HeadersContainMultipleCopiesOfField(*response->headers, "Location"))
return ERR_RESPONSE_HEADERS_MULTIPLE_LOCATION;
response->vary_data.Init(*request, *response->headers);
DVLOG(1) << __FUNCTION__ << "()"
<< " content_length = \""
<< response->headers->GetContentLength() << "\n\""
<< " headers = \"" << GetResponseHeaderLines(*response->headers)
<< "\"";
return OK;
}
} // namespace net