Commit ed423830 authored by mkwst@chromium.org's avatar mkwst@chromium.org

CREDENTIAL: Extend FormData opacity to created Request objects

Opaque FormData objects created from 'PasswordCredential::toFormData()'
need to persist their opacity through to Request objects, as defined in
https://w3c.github.io/webappsec/specs/credentialmanagement/#opaque-formdata-algorithms

This patch adjusts 'RequestInit', 'Body', and 'Request' such that opaque
'FormData' bodies lead to opaque 'Body' objects that reject read
attempts from JavaScript.

BUG=526995

Review URL: https://codereview.chromium.org/1305183009

git-svn-id: svn://svn.chromium.org/blink/trunk@201714 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 3ac81673
......@@ -76,4 +76,30 @@ test(function() {
assert_unreached("There should be nothing to iterate here.");
}
}, 'Verify properties of opaque FormData.');
function verifyBodyMethodBehavior(t, req, methodName) {
req[methodName]().then(
t.unreached_func("The 'Body::" + methodName + "()' method should reject."),
t.step_func_done(function (e) { assert_equals(e.name, "TypeError"); }));
}
// TODO(mkwst): 'Body' doesn't yet implement 'formData()'.
['arrayBuffer', 'blob', 'json', 'text'].forEach(function (methodName) {
async_test(function (t) {
var credential = new PasswordCredential('id', 'pencil');
var fd = credential.toFormData();
fd.append('n1', 'v1');
fd.append('n2', 'v2');
fd.append('n3', 'v3');
fd.append('n1', 'v4');
fd.append('n2', 'v5');
fd.append('n3', 'v6');
t.step(function () {
var r = new Request("http://127.0.0.1:8000", { body: fd, method: "POST" });
verifyBodyMethodBehavior(t, r, methodName);
});
}, "Verify behavior of 'Body::" + methodName + "()' for opaque Requests.");
});
</script>
......@@ -75,6 +75,7 @@ public:
void set(const String& name, Blob*, const String& filename = String());
void makeOpaque() { m_opaque = true; }
bool opaque() const { return m_opaque; }
private:
explicit DOMFormData(const WTF::TextEncoding&);
......
......@@ -104,6 +104,9 @@ public:
ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
{
if (m_opaque)
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "The body is opaque."));
if (bodyUsed())
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
......@@ -124,6 +127,9 @@ ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
ScriptPromise Body::blob(ScriptState* scriptState)
{
if (m_opaque)
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "The body is opaque."));
if (bodyUsed())
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
......@@ -140,6 +146,9 @@ ScriptPromise Body::blob(ScriptState* scriptState)
ScriptPromise Body::json(ScriptState* scriptState)
{
if (m_opaque)
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "The body is opaque."));
if (bodyUsed())
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
......@@ -155,6 +164,9 @@ ScriptPromise Body::json(ScriptState* scriptState)
ScriptPromise Body::text(ScriptState* scriptState)
{
if (m_opaque)
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "The body is opaque."));
if (bodyUsed())
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read"));
......@@ -186,7 +198,10 @@ bool Body::hasPendingActivity() const
return bodyBuffer()->hasPendingActivity();
}
Body::Body(ExecutionContext* context) : ActiveDOMObject(context), m_bodyPassed(false)
Body::Body(ExecutionContext* context)
: ActiveDOMObject(context)
, m_bodyPassed(false)
, m_opaque(false)
{
suspendIfNeeded();
}
......
......@@ -50,10 +50,14 @@ public:
ActiveDOMObject::trace(visitor);
}
void makeOpaque() { m_opaque = true; }
bool opaque() const { return m_opaque; }
private:
virtual String mimeType() const = 0;
bool m_bodyPassed;
bool m_opaque;
};
} // namespace blink
......
......@@ -263,6 +263,10 @@ Request* Request::createRequestWithRequestOrString(ScriptState* scriptState, Req
if (temporaryBody)
r->m_request->setBuffer(temporaryBody);
// https://w3c.github.io/webappsec/specs/credentialmanagement/#monkey-patching-fetch-2
if (init.opaque || (inputRequest && inputRequest->opaque()))
r->makeOpaque();
// "34. Set |r|'s MIME type to the result of extracting a MIME type from
// |r|'s request's header list."
r->m_request->setMIMEType(r->m_request->headerList()->extractMIMEType());
......
......@@ -12,6 +12,7 @@
#include "bindings/core/v8/V8Blob.h"
#include "bindings/core/v8/V8FormData.h"
#include "core/fileapi/Blob.h"
#include "core/html/DOMFormData.h"
#include "modules/fetch/FetchBlobDataConsumerHandle.h"
#include "modules/fetch/FetchFormDataConsumerHandle.h"
#include "modules/fetch/Headers.h"
......@@ -21,6 +22,7 @@
namespace blink {
RequestInit::RequestInit(ExecutionContext* context, const Dictionary& options, ExceptionState& exceptionState)
: opaque(false)
{
DictionaryHelper::get(options, "method", method);
DictionaryHelper::get(options, "headers", headers);
......@@ -49,7 +51,10 @@ RequestInit::RequestInit(ExecutionContext* context, const Dictionary& options, E
contentType = blobDataHandle->type();
body = FetchBlobDataConsumerHandle::create(context, blobDataHandle.release());
} else if (V8FormData::hasInstance(v8Body, isolate)) {
RefPtr<FormData> formData = V8FormData::toImpl(v8::Local<v8::Object>::Cast(v8Body))->createMultiPartFormData();
DOMFormData* domFormData = V8FormData::toImpl(v8::Local<v8::Object>::Cast(v8Body));
opaque = domFormData->opaque();
RefPtr<FormData> formData = domFormData->createMultiPartFormData();
// Here we handle formData->boundary() as a C-style string. See
// FormDataBuilder::generateUniqueBoundaryString.
contentType = AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + formData->boundary().data();
......
......@@ -32,6 +32,9 @@ public:
String credentials;
String redirect;
String integrity;
// https://w3c.github.io/webappsec/specs/credentialmanagement/#monkey-patching-fetch-2
bool opaque;
};
}
......
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