Commit 61a0f661 authored by Kunihiko Sakamoto's avatar Kunihiko Sakamoto Committed by Commit Bot

Extract signed exchange contents from CBOR

This patch teaches SignedExchangeHandler to decode signed exchange
body encoded with the application/http-exchange+cbor format [1].

The test file origin-signed-response-iframe.htxg was created using
gen-signedexchange of [2] with the following command:

gen-signedexchange -uri https://example.com/test.html \
    -content test.html -o origin-signed-response-iframe.htxg \
    -miRecordSize=100

where test.html is the html part of origin-signed-response-iframe.php
before this patch.

[1] https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html#rfc.section.5
[2] https://github.com/WICG/webpackage/pull/119

Bug: 803774
Change-Id: I4d7bf5215e825cfa084c431db6d2cc87219d0a34
Reviewed-on: https://chromium-review.googlesource.com/897172
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Cr-Commit-Position: refs/heads/master@{#534643}
parent 5fd5ad14
......@@ -11,51 +11,42 @@
#include "base/optional.h"
#include "mojo/public/cpp/system/data_pipe.h"
#include "net/base/completion_callback.h"
#include "net/filter/filter_source_stream.h"
#include "net/ssl/ssl_info.h"
#include "services/network/public/cpp/resource_response.h"
#include "url/gurl.h"
namespace net {
class SourceStream;
}
namespace content {
// IMPORTANT: Currenly SignedExchangeHandler doesn't implement any CBOR parsing
// logic nor verifying logic. It just behaves as if the passed body is a signed
// HTTP exchange which contains a request to "https://example.com/test.html" and
// a response with a payload which is equal to the original body.
// TODO(https://crbug.com/803774): Implement CBOR parsing logic and verifying
// IMPORTANT: Currenly SignedExchangeHandler doesn't implement any verifying
// logic.
class SignedExchangeHandler final : public net::FilterSourceStream {
// TODO(https://crbug.com/803774): Implement verifying logic.
class SignedExchangeHandler final {
public:
// TODO(https://crbug.com/803774): Add verification status here.
using ExchangeHeadersCallback =
base::OnceCallback<void(const GURL& request_url,
base::OnceCallback<void(net::Error error,
const GURL& request_url,
const std::string& request_method,
const network::ResourceResponseHead&,
std::unique_ptr<net::SourceStream> payload_stream,
base::Optional<net::SSLInfo>)>;
// Once constructed |this| starts reading the |body| and parses the response
// as a signed HTTP exchange. The response body of the exchange can be read
// from |this| as a net::SourceStream after |headers_callback| is called.
// from |payload_stream| passed to |headers_callback|.
SignedExchangeHandler(std::unique_ptr<net::SourceStream> body,
ExchangeHeadersCallback headers_callback);
~SignedExchangeHandler() override;
// net::FilterSourceStream:
int FilterData(net::IOBuffer* output_buffer,
int output_buffer_size,
net::IOBuffer* input_buffer,
int input_buffer_size,
int* consumed_bytes,
bool upstream_eof_reached) override;
std::string GetTypeAsString() const override;
~SignedExchangeHandler();
private:
void DoHeaderLoop();
void DidReadForHeaders(bool completed_syncly, int result);
bool MaybeRunHeadersCallback();
// TODO(https://crbug.com/803774): Remove this.
void FillMockExchangeHeaders();
void ReadLoop();
void DidRead(bool completed_syncly, int result);
bool RunHeadersCallback();
void RunErrorCallback(net::Error);
// Signed exchange contents.
GURL request_url_;
......@@ -64,16 +55,12 @@ class SignedExchangeHandler final : public net::FilterSourceStream {
base::Optional<net::SSLInfo> ssl_info_;
ExchangeHeadersCallback headers_callback_;
// Internal IOBuffer used during reading the header. Note that during parsing
// the header we don't really need the output buffer, but we still need to
// give some > 0 buffer.
scoped_refptr<net::IOBufferWithSize> header_out_buf_;
std::unique_ptr<net::SourceStream> source_;
// TODO(https://crbug.cxom/803774): Just for now. Implement the streaming
// parser.
scoped_refptr<net::IOBufferWithSize> read_buf_;
std::string original_body_string_;
size_t body_string_offset_ = 0;
base::WeakPtrFactory<SignedExchangeHandler> weak_factory_;
......
......@@ -10,10 +10,10 @@
namespace content {
SourceStreamToDataPipe::SourceStreamToDataPipe(
net::SourceStream* source,
std::unique_ptr<net::SourceStream> source,
mojo::ScopedDataPipeProducerHandle dest,
base::OnceCallback<void(int)> completion_callback)
: source_(source),
: source_(std::move(source)),
dest_(std::move(dest)),
completion_callback_(std::move(completion_callback)),
writable_handle_watcher_(FROM_HERE,
......
......@@ -22,9 +22,7 @@ namespace content {
class SourceStreamToDataPipe {
public:
// Reads out the data from |source| and write into |dest|.
// Note that this does not take the ownership of |source|, the caller
// needs to take care that it is kept alive.
SourceStreamToDataPipe(net::SourceStream* source,
SourceStreamToDataPipe(std::unique_ptr<net::SourceStream> source,
mojo::ScopedDataPipeProducerHandle dest,
base::OnceCallback<void(int)> completion_callback);
~SourceStreamToDataPipe();
......@@ -40,7 +38,7 @@ class SourceStreamToDataPipe {
void OnDataPipeClosed(MojoResult result);
void OnComplete(int result);
net::SourceStream* source_; // Not owned.
std::unique_ptr<net::SourceStream> source_;
mojo::ScopedDataPipeProducerHandle dest_;
base::OnceCallback<void(int)> completion_callback_;
......
......@@ -190,10 +190,18 @@ void WebPackageLoader::ConnectToClient(
}
void WebPackageLoader::OnHTTPExchangeFound(
net::Error error,
const GURL& request_url,
const std::string& request_method,
const network::ResourceResponseHead& resource_response,
std::unique_ptr<net::SourceStream> payload_stream,
base::Optional<net::SSLInfo> ssl_info) {
if (error) {
// This will eventually delete |this|.
client_->OnComplete(network::URLLoaderCompletionStatus(error));
return;
}
// TODO(https://crbug.com/803774): Handle no-GET request_method as a error.
DCHECK(original_response_timing_info_);
forwarding_client_->OnReceiveRedirect(
......@@ -213,7 +221,7 @@ void WebPackageLoader::OnHTTPExchangeFound(
pending_body_consumer_ = std::move(data_pipe.consumer_handle);
body_data_pipe_adapter_ = std::make_unique<SourceStreamToDataPipe>(
signed_exchange_handler_.get(), std::move(data_pipe.producer_handle),
std::move(payload_stream), std::move(data_pipe.producer_handle),
base::BindOnce(&WebPackageLoader::FinishReadingBody,
base::Unretained(this)));
......
......@@ -13,6 +13,10 @@
#include "services/network/public/cpp/net_adapters.h"
#include "services/network/public/interfaces/url_loader.mojom.h"
namespace net {
class SourceStream;
} // namespace net
namespace content {
class SignedExchangeHandler;
......@@ -66,9 +70,11 @@ class WebPackageLoader final : public network::mojom::URLLoaderClient,
// Called from |signed_exchange_handler_| when it finds an origin-signed HTTP
// exchange.
void OnHTTPExchangeFound(
net::Error error,
const GURL& request_url,
const std::string& request_method,
const network::ResourceResponseHead& resource_response,
std::unique_ptr<net::SourceStream> payload_stream,
base::Optional<net::SSLInfo> ssl_info);
void FinishReadingBody(int result);
......
......@@ -26,8 +26,6 @@ promise_test(function(t) {
return promise;
})
.then((event) => {
// TODO(https://crbug.com/80374): Currently this URL is hard coded in
// SignedExchangeHandler.
assert_equals(event.data.location, 'https://example.com/test.html');
});
}, 'Location of origin-signed HTTP response');
......
<?php
$fp = fopen("origin-signed-response-iframe.htxg", "rb");
header('Content-Type: application/http-exchange+cbor');
header("HTTP/1.0 200 OK");
fpassthru($fp);
?>
<!DOCTYPE html>
<body>
<script>
window.addEventListener('message', (event) => {
event.data.port.postMessage({location: document.location.href});
}, false);
</script>
hello<br>
world
</body>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment