blob: f6f6459b6a897199b7f8dd4c405af5eef96c7de9 [file] [log] [blame]
// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/public/platform/web_url_request_util.h"
#include <stddef.h>
#include <stdint.h>
#include <limits>
#include "base/check.h"
#include "base/notreached.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "services/network/public/mojom/data_pipe_getter.mojom-blink.h"
#include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h"
#include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/mixed_content.mojom-blink.h"
#include "third_party/blink/public/mojom/loader/resource_load_info.mojom-blink.h"
#include "third_party/blink/public/platform/cross_variant_mojo_util.h"
#include "third_party/blink/public/platform/file_path_conversion.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/web_data.h"
#include "third_party/blink/public/platform/web_http_body.h"
#include "third_party/blink/public/platform/web_http_header_visitor.h"
#include "third_party/blink/public/platform/web_string.h"
#include "third_party/blink/public/platform/web_url_request.h"
#include "third_party/blink/renderer/platform/loader/mixed_content.h"
#include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
#include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
#include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
namespace blink {
namespace {
class HeaderFlattener : public WebHTTPHeaderVisitor {
public:
HeaderFlattener() = default;
~HeaderFlattener() override = default;
void VisitHeader(const WebString& name, const WebString& value) override {
const String wtf_name = name;
const String wtf_value = value;
// Skip over referrer headers found in the header map because we already
// pulled it out as a separate parameter.
if (EqualIgnoringASCIICase(wtf_name, "referer"))
return;
if (!buffer_.IsEmpty())
buffer_.Append("\r\n");
buffer_.Append(wtf_name);
buffer_.Append(": ");
buffer_.Append(wtf_value);
}
WebString GetBuffer() { return buffer_.ToString(); }
private:
StringBuilder buffer_;
};
} // namespace
WebString GetWebURLRequestHeadersAsString(const WebURLRequest& request) {
HeaderFlattener flattener;
request.VisitHttpHeaderFields(&flattener);
return flattener.GetBuffer();
}
WebHTTPBody GetWebHTTPBodyForRequestBody(
const network::ResourceRequestBody& input) {
WebHTTPBody http_body;
http_body.Initialize();
http_body.SetIdentifier(input.identifier());
http_body.SetContainsPasswordData(input.contains_sensitive_info());
for (auto& element : *input.elements()) {
switch (element.type()) {
case network::DataElement::Tag::kBytes: {
const auto& bytes = element.As<network::DataElementBytes>().bytes();
http_body.AppendData(
WebData(reinterpret_cast<const char*>(bytes.data()), bytes.size()));
break;
}
case network::DataElement::Tag::kFile: {
const auto& file = element.As<network::DataElementFile>();
base::Optional<base::Time> modification_time;
if (!file.expected_modification_time().is_null())
modification_time = file.expected_modification_time();
http_body.AppendFileRange(
FilePathToWebString(file.path()), file.offset(),
(file.length() != std::numeric_limits<uint64_t>::max())
? file.length()
: -1,
modification_time);
break;
}
case network::DataElement::Tag::kDataPipe: {
http_body.AppendDataPipe(
element.As<network::DataElementDataPipe>().CloneDataPipeGetter());
break;
}
case network::DataElement::Tag::kChunkedDataPipe:
NOTREACHED();
break;
}
}
return http_body;
}
scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebURLRequest(
const WebURLRequest& request) {
scoped_refptr<network::ResourceRequestBody> request_body;
if (request.HttpBody().IsNull()) {
return request_body;
}
const std::string& method = request.HttpMethod().Latin1();
// GET and HEAD requests shouldn't have http bodies.
DCHECK(method != "GET" && method != "HEAD");
return GetRequestBodyForWebHTTPBody(request.HttpBody());
}
scoped_refptr<network::ResourceRequestBody> GetRequestBodyForWebHTTPBody(
const WebHTTPBody& httpBody) {
scoped_refptr<network::ResourceRequestBody> request_body =
new network::ResourceRequestBody();
size_t i = 0;
WebHTTPBody::Element element;
while (httpBody.ElementAt(i++, element)) {
switch (element.type) {
case HTTPBodyElementType::kTypeData:
request_body->AppendBytes(element.data.Copy().ReleaseVector());
break;
case HTTPBodyElementType::kTypeFile:
if (element.file_length == -1) {
request_body->AppendFileRange(
WebStringToFilePath(element.file_path), 0,
std::numeric_limits<uint64_t>::max(),
element.modification_time.value_or(base::Time()));
} else {
request_body->AppendFileRange(
WebStringToFilePath(element.file_path),
static_cast<uint64_t>(element.file_start),
static_cast<uint64_t>(element.file_length),
element.modification_time.value_or(base::Time()));
}
break;
case HTTPBodyElementType::kTypeBlob: {
DCHECK(element.optional_blob);
mojo::Remote<mojom::blink::Blob> blob_remote(
std::move(element.optional_blob));
mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
data_pipe_getter_remote;
blob_remote->AsDataPipeGetter(
data_pipe_getter_remote.InitWithNewPipeAndPassReceiver());
request_body->AppendDataPipe(
ToCrossVariantMojoType(std::move(data_pipe_getter_remote)));
break;
}
case HTTPBodyElementType::kTypeDataPipe: {
mojo::Remote<network::mojom::blink::DataPipeGetter> data_pipe_getter(
std::move(element.data_pipe_getter));
// Set the cloned DataPipeGetter to the output |request_body|, while
// keeping the original message pipe back in the input |httpBody|. This
// way the consumer of the |httpBody| can retrieve the data pipe
// multiple times (e.g. during redirects) until the request is finished.
mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
cloned_getter;
data_pipe_getter->Clone(cloned_getter.InitWithNewPipeAndPassReceiver());
request_body->AppendDataPipe(
ToCrossVariantMojoType(std::move(cloned_getter)));
element.data_pipe_getter = data_pipe_getter.Unbind();
break;
}
}
}
request_body->set_identifier(httpBody.Identifier());
request_body->set_contains_sensitive_info(httpBody.ContainsPasswordData());
return request_body;
}
mojom::blink::RequestContextType GetRequestContextTypeForWebURLRequest(
const WebURLRequest& request) {
return static_cast<mojom::blink::RequestContextType>(
request.GetRequestContext());
}
network::mojom::blink::RequestDestination GetRequestDestinationForWebURLRequest(
const WebURLRequest& request) {
return static_cast<network::mojom::blink::RequestDestination>(
request.GetRequestDestination());
}
mojom::blink::MixedContentContextType
GetMixedContentContextTypeForWebURLRequest(const WebURLRequest& request) {
return MixedContent::ContextTypeFromRequestContext(
request.GetRequestContext(), MixedContent::CheckModeForPlugin::kLax);
}
} // namespace blink