Commit 651abb3f authored by horo@chromium.org's avatar horo@chromium.org

[Fetch API] Put body members directly on Response/Request

http://fetch.spec.whatwg.org/

https://github.com/whatwg/fetch/commit/a898f9a2941350aa625aa79b24673628ac2b2a8e
Request.body and Response.body is removed from the spec.
Body interface is introduced.

interface Body {
  readonly attribute boolean bodyUsed;
  Promise<ArrayBuffer> arrayBuffer();
  Promise<Blob> blob();
  Promise<FormData> formData();
  Promise<JSON> json();
  Promise<ScalarValueString> text();
};
Request implements Body;
Response implements Body;

BUG=411743,410197,410196
TEST=http/tests/serviceworker/ http/tests/local/serviceworker/

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

git-svn-id: svn://svn.chromium.org/blink/trunk@181793 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 12adc787
...@@ -5,7 +5,7 @@ self.addEventListener('fetch', function(event) { ...@@ -5,7 +5,7 @@ self.addEventListener('fetch', function(event) {
headers.push([key, value]); headers.push([key, value]);
}); });
if (event.request.url.indexOf('asText') != -1) { if (event.request.url.indexOf('asText') != -1) {
event.request.body.asText() event.request.text()
.then(function(result) { .then(function(result) {
resolve(new Response(JSON.stringify({ resolve(new Response(JSON.stringify({
method: event.request.method, method: event.request.method,
...@@ -14,7 +14,7 @@ self.addEventListener('fetch', function(event) { ...@@ -14,7 +14,7 @@ self.addEventListener('fetch', function(event) {
}))); })));
}) })
} else if (event.request.url.indexOf('asBlob') != -1) { } else if (event.request.url.indexOf('asBlob') != -1) {
event.request.body.asBlob() event.request.blob()
.then(function(result) { .then(function(result) {
resolve(new Response(JSON.stringify({ resolve(new Response(JSON.stringify({
method: event.request.method, method: event.request.method,
......
...@@ -21,9 +21,13 @@ var checkFetchResponseBody = function (hasBody, url, data) { ...@@ -21,9 +21,13 @@ var checkFetchResponseBody = function (hasBody, url, data) {
assert_equals(data.fetchResult, assert_equals(data.fetchResult,
'resolved', 'resolved',
'fetchResult must be resolved. url: ' + url); 'fetchResult must be resolved. url: ' + url);
assert_equals(data.hasBody, if (hasBody) {
hasBody, assert_not_equals(data.body, '',
'hasBody must match. url: ' + url); 'response must have body. url: ' + url);
} else {
assert_equals(data.body, '',
'response must not have body. url: ' + url);
}
}; };
var checkFetchResponseHeader = function (name, expected, url, data) { var checkFetchResponseHeader = function (name, expected, url, data) {
assert_equals(data.fetchResult, assert_equals(data.fetchResult,
......
<!DOCTYPE html> <!DOCTYPE html>
<title>Service Worker: fetch()</title> <title>Service Worker: Body mixin</title>
<script src="../resources/testharness.js"></script> <script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script> <script src="../resources/testharnessreport.js"></script>
<script src="resources/test-helpers.js"></script> <script src="resources/test-helpers.js"></script>
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
async_test(function(t) { async_test(function(t) {
var scope = 'resources/blank.html'; var scope = 'resources/blank.html';
service_worker_unregister_and_register( service_worker_unregister_and_register(
t, 'resources/fetch-body-stream-worker.js', scope) t, 'resources/fetch-body-mixin-worker.js', scope)
.then(function(registration) { .then(function(registration) {
return wait_for_update(t, registration); return wait_for_update(t, registration);
}) })
......
...@@ -75,15 +75,28 @@ self.addEventListener('fetch', function(event) { ...@@ -75,15 +75,28 @@ self.addEventListener('fetch', function(event) {
} else if (!params['noChange']) { } else if (!params['noChange']) {
request = new Request(request, init); request = new Request(request, init);
} }
var response;
fetch(request) fetch(request)
.then(function(res) { .then(function(res) {
// Send the result to fetch-access-control.html. response = res;
port.postMessage({fetchResult: 'resolved', res.text()
hasBody: !!res.body, .then(function(body) {
headers: headersToArray(res.headers), // Send the result to fetch-access-control.html.
type: res.type, port.postMessage(
originalURL: originalURL}); {
resolve(res); fetchResult: 'resolved',
body: body,
headers: headersToArray(response.headers),
type: response.type,
originalURL: originalURL
});
resolve(response);
})
.catch(function(e) {
// Send the result to fetch-access-control.html.
port.postMessage({fetchResult: 'error'});
reject();
});
}) })
.catch(function(e) { .catch(function(e) {
// Send the result to fetch-access-control.html. // Send the result to fetch-access-control.html.
......
...@@ -15,8 +15,8 @@ function doFetchTwiceTest(port) { ...@@ -15,8 +15,8 @@ function doFetchTwiceTest(port) {
fetch('doctype.html') fetch('doctype.html')
.then(function(response) { .then(function(response) {
var p1 = response.body.asText(); var p1 = response.text();
var p2 = response.body.asText(); var p2 = response.text();
p1.then(function(obj) { p1.then(function(obj) {
p1Out = obj; p1Out = obj;
...@@ -41,7 +41,7 @@ function doFetchTwiceTest(port) { ...@@ -41,7 +41,7 @@ function doFetchTwiceTest(port) {
function doArrayBufferTest(port) { function doArrayBufferTest(port) {
fetch('doctype.html') fetch('doctype.html')
.then(function(response) { .then(function(response) {
response.body.asArrayBuffer() response.arrayBuffer()
.then(function(b) { .then(function(b) {
port.postMessage('ArrayBuffer: ' + b.byteLength); port.postMessage('ArrayBuffer: ' + b.byteLength);
doFetchTwiceTest(port); doFetchTwiceTest(port);
...@@ -52,7 +52,7 @@ function doArrayBufferTest(port) { ...@@ -52,7 +52,7 @@ function doArrayBufferTest(port) {
function doBlobTest(port) { function doBlobTest(port) {
fetch('doctype.html') fetch('doctype.html')
.then(function(response) { .then(function(response) {
response.body.asBlob() response.blob()
.then(function(blob) { .then(function(blob) {
port.postMessage('Blob: ' + blob.size + " : " + blob.type); port.postMessage('Blob: ' + blob.size + " : " + blob.type);
doArrayBufferTest(port); doArrayBufferTest(port);
...@@ -63,7 +63,7 @@ function doBlobTest(port) { ...@@ -63,7 +63,7 @@ function doBlobTest(port) {
function doJSONFailedTest(port) { function doJSONFailedTest(port) {
fetch('doctype.html') fetch('doctype.html')
.then(function(response) { .then(function(response) {
response.body.asJSON() response.json()
.catch(function(e) { .catch(function(e) {
port.postMessage('JSON: ' + e.name); port.postMessage('JSON: ' + e.name);
doBlobTest(port); doBlobTest(port);
...@@ -74,7 +74,7 @@ function doJSONFailedTest(port) { ...@@ -74,7 +74,7 @@ function doJSONFailedTest(port) {
function doJSONTest(port) { function doJSONTest(port) {
fetch('simple.json') fetch('simple.json')
.then(function(response) { .then(function(response) {
response.body.asJSON() response.json()
.then(function(json) { .then(function(json) {
port.postMessage('JSON: ' + json['a'] + ' ' + json['b']); port.postMessage('JSON: ' + json['a'] + ' ' + json['b']);
doJSONFailedTest(port); doJSONFailedTest(port);
...@@ -85,7 +85,7 @@ function doJSONTest(port) { ...@@ -85,7 +85,7 @@ function doJSONTest(port) {
function doTextTest(port) { function doTextTest(port) {
fetch('doctype.html') fetch('doctype.html')
.then(function(response) { .then(function(response) {
response.body.asText() response.text()
.then(function(txt) { .then(function(txt) {
port.postMessage('Text: ' + txt); port.postMessage('Text: ' + txt);
doJSONTest(port); doJSONTest(port);
......
...@@ -27,7 +27,7 @@ function handleFetch(event) { ...@@ -27,7 +27,7 @@ function handleFetch(event) {
function handleFormPost(event) { function handleFormPost(event) {
event.respondWith(new Promise(function(resolve) { event.respondWith(new Promise(function(resolve) {
event.request.body.asText() event.request.text()
.then(function(result) { .then(function(result) {
resolve(new Response(event.request.method + ':' + result)); resolve(new Response(event.request.method + ':' + result));
}) })
......
...@@ -8,15 +8,7 @@ self.addEventListener('fetch', function(event) { ...@@ -8,15 +8,7 @@ self.addEventListener('fetch', function(event) {
event.request.headers.forEach(function(value, key) { event.request.headers.forEach(function(value, key) {
headers.push([key, value]); headers.push([key, value]);
}); });
if (!event.request.body) { event.request.text()
resolve(new Response(JSON.stringify({
method: event.request.method,
headers: headers,
body: null
})));
return;
}
event.request.body.asText()
.then(function(result) { .then(function(result) {
resolve(new Response(JSON.stringify({ resolve(new Response(JSON.stringify({
method: event.request.method, method: event.request.method,
......
...@@ -48,7 +48,7 @@ async_test(function(t) { ...@@ -48,7 +48,7 @@ async_test(function(t) {
body: new Blob(['Test Blob'], {type: 'test/type'}) body: new Blob(['Test Blob'], {type: 'test/type'})
}); });
fetch(request) fetch(request)
.then(function(response) { return response.body.asText(); }) .then(function(response) { return response.text(); })
.then(evalJsonp) .then(evalJsonp)
.then(function(result) { .then(function(result) {
assert_equals(result.method, 'POST'); assert_equals(result.method, 'POST');
...@@ -62,7 +62,7 @@ async_test(function(t) { ...@@ -62,7 +62,7 @@ async_test(function(t) {
var request = new Request('fetch-access-control.php', var request = new Request('fetch-access-control.php',
{method: 'POST', body: 'Test String'}); {method: 'POST', body: 'Test String'});
fetch(request) fetch(request)
.then(function(response) { return response.body.asText(); }) .then(function(response) { return response.text(); })
.then(evalJsonp) .then(evalJsonp)
.then(function(result) { .then(function(result) {
assert_equals(result.method, 'POST'); assert_equals(result.method, 'POST');
...@@ -80,7 +80,7 @@ async_test(function(t) { ...@@ -80,7 +80,7 @@ async_test(function(t) {
var request = new Request('fetch-access-control.php', var request = new Request('fetch-access-control.php',
{method: 'POST', body: array.buffer}); {method: 'POST', body: array.buffer});
fetch(request) fetch(request)
.then(function(response) { return response.body.asText(); }) .then(function(response) { return response.text(); })
.then(evalJsonp) .then(evalJsonp)
.then(function(result) { .then(function(result) {
assert_equals(result.method, 'POST'); assert_equals(result.method, 'POST');
...@@ -98,7 +98,7 @@ async_test(function(t) { ...@@ -98,7 +98,7 @@ async_test(function(t) {
var request = new Request('fetch-access-control.php', var request = new Request('fetch-access-control.php',
{method: 'POST', body: array}); {method: 'POST', body: array});
fetch(request) fetch(request)
.then(function(response) { return response.body.asText(); }) .then(function(response) { return response.text(); })
.then(evalJsonp) .then(evalJsonp)
.then(function(result) { .then(function(result) {
assert_equals(result.method, 'POST'); assert_equals(result.method, 'POST');
...@@ -118,7 +118,7 @@ async_test(function(t) { ...@@ -118,7 +118,7 @@ async_test(function(t) {
var request = new Request('fetch-access-control.php', var request = new Request('fetch-access-control.php',
{method: 'POST', body: formData}); {method: 'POST', body: formData});
fetch(request) fetch(request)
.then(function(response) { return response.body.asText(); }) .then(function(response) { return response.text(); })
.then(evalJsonp) .then(evalJsonp)
.then(function(result) { .then(function(result) {
assert_equals(result.method, 'POST'); assert_equals(result.method, 'POST');
......
...@@ -303,7 +303,9 @@ async_test(function(t) { ...@@ -303,7 +303,9 @@ async_test(function(t) {
assert_equals( assert_equals(
getContentType(request.headers), 'test/type', getContentType(request.headers), 'test/type',
'ContentType header of Request created with Blob body must be set.'); 'ContentType header of Request created with Blob body must be set.');
request.body.asText() assert_false(request.bodyUsed,
'bodyUsed must be true before calling text()');
request.text()
.then(function(result) { .then(function(result) {
assert_equals(result, 'Test Blob', assert_equals(result, 'Test Blob',
'Creating a Request with Blob body should success.'); 'Creating a Request with Blob body should success.');
...@@ -312,7 +314,7 @@ async_test(function(t) { ...@@ -312,7 +314,7 @@ async_test(function(t) {
assert_equals( assert_equals(
getContentType(request.headers), 'text/plain;charset=UTF-8', getContentType(request.headers), 'text/plain;charset=UTF-8',
'ContentType header of Request created with string must be set.'); 'ContentType header of Request created with string must be set.');
return request.body.asText(); return request.text();
}) })
.then(function(result) { .then(function(result) {
assert_equals(result, 'Test String', assert_equals(result, 'Test String',
...@@ -323,7 +325,7 @@ async_test(function(t) { ...@@ -323,7 +325,7 @@ async_test(function(t) {
for (var i = 0; i < text.length; ++i) for (var i = 0; i < text.length; ++i)
array[i] = text.charCodeAt(i); array[i] = text.charCodeAt(i);
request = new Request(URL, {method: 'POST', body: array.buffer}); request = new Request(URL, {method: 'POST', body: array.buffer});
return request.body.asText(); return request.text();
}) })
.then(function(result) { .then(function(result) {
assert_equals( assert_equals(
...@@ -335,7 +337,7 @@ async_test(function(t) { ...@@ -335,7 +337,7 @@ async_test(function(t) {
for (var i = 0; i < text.length; ++i) for (var i = 0; i < text.length; ++i)
array[i] = text.charCodeAt(i); array[i] = text.charCodeAt(i);
request = new Request(URL, {method: 'POST', body: array}); request = new Request(URL, {method: 'POST', body: array});
return request.body.asText(); return request.text();
}) })
.then(function(result) { .then(function(result) {
assert_equals( assert_equals(
...@@ -348,7 +350,7 @@ async_test(function(t) { ...@@ -348,7 +350,7 @@ async_test(function(t) {
formData.append('sample file', formData.append('sample file',
new File(['file content'], 'file.dat')); new File(['file content'], 'file.dat'));
request = new Request(URL, {method: 'POST', body: formData}); request = new Request(URL, {method: 'POST', body: formData});
return request.body.asText(); return request.text();
}) })
.then(function(result) { .then(function(result) {
var reg = new RegExp('multipart\/form-data; boundary=(.*)'); var reg = new RegExp('multipart\/form-data; boundary=(.*)');
...@@ -380,4 +382,6 @@ async_test(function(t) { ...@@ -380,4 +382,6 @@ async_test(function(t) {
t.done(); t.done();
}) })
.catch(unreached_rejection(t)); .catch(unreached_rejection(t));
assert_true(request.bodyUsed,
'bodyUsed must be true after calling text()');
}, 'Request body test in ServiceWorkerGlobalScope'); }, 'Request body test in ServiceWorkerGlobalScope');
...@@ -6,7 +6,7 @@ promise_test(function() { ...@@ -6,7 +6,7 @@ promise_test(function() {
response.headers.get('Content-Type'), response.headers.get('Content-Type'),
'text/plain;charset=UTF-8', 'text/plain;charset=UTF-8',
'A Response constructed with a string should have a Content-Type.'); 'A Response constructed with a string should have a Content-Type.');
return response.body.asText() return response.text()
.then(function(text) { .then(function(text) {
assert_equals(text, 'test string', assert_equals(text, 'test string',
'Response body text should match the string on construction.'); 'Response body text should match the string on construction.');
...@@ -20,7 +20,7 @@ promise_test(function() { ...@@ -20,7 +20,7 @@ promise_test(function() {
var response = new Response(buffer); var response = new Response(buffer);
assert_false(response.headers.has('Content-Type'), assert_false(response.headers.has('Content-Type'),
'A Response constructed with ArrayBuffer should not have a content type.'); 'A Response constructed with ArrayBuffer should not have a content type.');
return response.body.asArrayBuffer() return response.arrayBuffer()
.then(function(buffer) { .then(function(buffer) {
var resultIntView = new Int32Array(buffer); var resultIntView = new Int32Array(buffer);
assert_array_equals( assert_array_equals(
...@@ -37,7 +37,7 @@ promise_test(function() { ...@@ -37,7 +37,7 @@ promise_test(function() {
assert_false(response.headers.has('Content-Type'), assert_false(response.headers.has('Content-Type'),
'A Response constructed with ArrayBufferView ' + 'A Response constructed with ArrayBufferView ' +
'should not have a content type.'); 'should not have a content type.');
return response.body.asArrayBuffer() return response.arrayBuffer()
.then(function(buffer) { .then(function(buffer) {
var resultIntView = new Int32Array(buffer); var resultIntView = new Int32Array(buffer);
assert_array_equals( assert_array_equals(
...@@ -54,7 +54,7 @@ promise_test(function() { ...@@ -54,7 +54,7 @@ promise_test(function() {
assert_false(response.headers.has('Content-Type'), assert_false(response.headers.has('Content-Type'),
'A Response constructed with ArrayBufferView ' + 'A Response constructed with ArrayBufferView ' +
'should not have a content type.'); 'should not have a content type.');
return response.body.asArrayBuffer() return response.arrayBuffer()
.then(function(buffer) { .then(function(buffer) {
var resultIntView = new Int32Array(buffer); var resultIntView = new Int32Array(buffer);
assert_array_equals( assert_array_equals(
......
...@@ -122,9 +122,9 @@ ...@@ -122,9 +122,9 @@
'quota/StorageQuotaCallback.idl', 'quota/StorageQuotaCallback.idl',
'quota/StorageUsageCallback.idl', 'quota/StorageUsageCallback.idl',
'screen_orientation/ScreenOrientation.idl', 'screen_orientation/ScreenOrientation.idl',
'serviceworkers/Body.idl',
'serviceworkers/Cache.idl', 'serviceworkers/Cache.idl',
'serviceworkers/CacheStorage.idl', 'serviceworkers/CacheStorage.idl',
'serviceworkers/FetchBodyStream.idl',
'serviceworkers/FetchEvent.idl', 'serviceworkers/FetchEvent.idl',
'serviceworkers/Headers.idl', 'serviceworkers/Headers.idl',
'serviceworkers/HeadersForEachCallback.idl', 'serviceworkers/HeadersForEachCallback.idl',
...@@ -676,12 +676,12 @@ ...@@ -676,12 +676,12 @@
'screen_orientation/ScreenOrientationController.h', 'screen_orientation/ScreenOrientationController.h',
'screen_orientation/ScreenOrientationDispatcher.cpp', 'screen_orientation/ScreenOrientationDispatcher.cpp',
'screen_orientation/ScreenOrientationDispatcher.h', 'screen_orientation/ScreenOrientationDispatcher.h',
'serviceworkers/Body.cpp',
'serviceworkers/Body.h',
'serviceworkers/Cache.cpp', 'serviceworkers/Cache.cpp',
'serviceworkers/Cache.h', 'serviceworkers/Cache.h',
'serviceworkers/CacheStorage.cpp', 'serviceworkers/CacheStorage.cpp',
'serviceworkers/CacheStorage.h', 'serviceworkers/CacheStorage.h',
'serviceworkers/FetchBodyStream.cpp',
'serviceworkers/FetchBodyStream.h',
'serviceworkers/FetchEvent.cpp', 'serviceworkers/FetchEvent.cpp',
'serviceworkers/FetchEvent.h', 'serviceworkers/FetchEvent.h',
'serviceworkers/FetchHeaderList.cpp', 'serviceworkers/FetchHeaderList.cpp',
......
...@@ -3,34 +3,23 @@ ...@@ -3,34 +3,23 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "config.h" #include "config.h"
#include "modules/serviceworkers/FetchBodyStream.h" #include "modules/serviceworkers/Body.h"
#include "bindings/core/v8/ScriptPromiseResolver.h" #include "bindings/core/v8/ScriptPromiseResolver.h"
#include "bindings/core/v8/ScriptState.h" #include "bindings/core/v8/ScriptState.h"
#include "bindings/core/v8/V8ThrowException.h" #include "bindings/core/v8/V8ThrowException.h"
#include "core/dom/ExceptionCode.h"
#include "core/fileapi/Blob.h" #include "core/fileapi/Blob.h"
#include "core/fileapi/FileReaderLoader.h" #include "core/fileapi/FileReaderLoader.h"
#include "core/fileapi/FileReaderLoaderClient.h" #include "core/fileapi/FileReaderLoaderClient.h"
#include "modules/serviceworkers/ResponseInit.h"
#include "platform/NotImplemented.h"
#include "public/platform/WebServiceWorkerResponse.h"
namespace blink { namespace blink {
FetchBodyStream* FetchBodyStream::create(ExecutionContext* context, PassRefPtr<BlobDataHandle> blobDataHandle) ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type)
{ {
FetchBodyStream* fetchBodyStream = new FetchBodyStream(context, blobDataHandle); if (m_bodyUsed)
fetchBodyStream->suspendIfNeeded();
return fetchBodyStream;
}
ScriptPromise FetchBodyStream::readAsync(ScriptState* scriptState, ResponseType type)
{
if (m_hasRead)
return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError("Already read", scriptState->isolate())); return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError("Already read", scriptState->isolate()));
m_hasRead = true; m_bodyUsed = true;
m_responseType = type; m_responseType = type;
ASSERT(!m_resolver); ASSERT(!m_resolver);
...@@ -38,21 +27,27 @@ ScriptPromise FetchBodyStream::readAsync(ScriptState* scriptState, ResponseType ...@@ -38,21 +27,27 @@ ScriptPromise FetchBodyStream::readAsync(ScriptState* scriptState, ResponseType
ScriptPromise promise = m_resolver->promise(); ScriptPromise promise = m_resolver->promise();
FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsText; FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsText;
RefPtr<BlobDataHandle> blobHandle = blobDataHandle();
if (!blobHandle.get()) {
blobHandle = BlobDataHandle::create(BlobData::create(), 0);
}
switch (type) { switch (type) {
case ResponseAsArrayBuffer: case ResponseAsArrayBuffer:
readType = FileReaderLoader::ReadAsArrayBuffer; readType = FileReaderLoader::ReadAsArrayBuffer;
break; break;
case ResponseAsBlob: case ResponseAsBlob:
if (m_blobDataHandle->size() != kuint64max) { if (blobHandle->size() != kuint64max) {
// If the size of |m_blobDataHandle| is set correctly, creates Blob from it. // If the size of |blobHandle| is set correctly, creates Blob from
m_resolver->resolve(Blob::create(m_blobDataHandle)); // it.
m_resolver->resolve(Blob::create(blobHandle));
m_resolver.clear(); m_resolver.clear();
return promise; return promise;
} }
// If the size is not set, read as ArrayBuffer and create a new blob to get the size. // If the size is not set, read as ArrayBuffer and create a new blob to
// get the size.
// FIXME: This workaround is not good for performance. // FIXME: This workaround is not good for performance.
// When we will stop using Blob as a base system of FetchBodyStream to support stream, this problem should be solved. // When we will stop using Blob as a base system of Body to support
// stream, this problem should be solved.
readType = FileReaderLoader::ReadAsArrayBuffer; readType = FileReaderLoader::ReadAsArrayBuffer;
break; break;
case ResponseAsFormData: case ResponseAsFormData:
...@@ -67,59 +62,60 @@ ScriptPromise FetchBodyStream::readAsync(ScriptState* scriptState, ResponseType ...@@ -67,59 +62,60 @@ ScriptPromise FetchBodyStream::readAsync(ScriptState* scriptState, ResponseType
} }
m_loader = adoptPtr(new FileReaderLoader(readType, this)); m_loader = adoptPtr(new FileReaderLoader(readType, this));
m_loader->start(scriptState->executionContext(), m_blobDataHandle); m_loader->start(scriptState->executionContext(), blobHandle);
return promise; return promise;
} }
ScriptPromise FetchBodyStream::asArrayBuffer(ScriptState* scriptState) ScriptPromise Body::arrayBuffer(ScriptState* scriptState)
{ {
return readAsync(scriptState, ResponseAsArrayBuffer); return readAsync(scriptState, ResponseAsArrayBuffer);
} }
ScriptPromise FetchBodyStream::asBlob(ScriptState* scriptState) ScriptPromise Body::blob(ScriptState* scriptState)
{ {
return readAsync(scriptState, ResponseAsBlob); return readAsync(scriptState, ResponseAsBlob);
} }
ScriptPromise FetchBodyStream::asFormData(ScriptState* scriptState) ScriptPromise Body::formData(ScriptState* scriptState)
{ {
return readAsync(scriptState, ResponseAsFormData); return readAsync(scriptState, ResponseAsFormData);
} }
ScriptPromise FetchBodyStream::asJSON(ScriptState* scriptState) ScriptPromise Body::json(ScriptState* scriptState)
{ {
return readAsync(scriptState, ResponseAsJSON); return readAsync(scriptState, ResponseAsJSON);
} }
ScriptPromise FetchBodyStream::asText(ScriptState* scriptState) ScriptPromise Body::text(ScriptState* scriptState)
{ {
return readAsync(scriptState, ResponseAsText); return readAsync(scriptState, ResponseAsText);
} }
void FetchBodyStream::stop() bool Body::bodyUsed() const
{
return m_bodyUsed;
}
void Body::stop()
{ {
// Canceling the load will call didFail which will remove the resolver. // Canceling the load will call didFail which will remove the resolver.
if (m_resolver) if (m_resolver)
m_loader->cancel(); m_loader->cancel();
} }
bool FetchBodyStream::hasPendingActivity() const bool Body::hasPendingActivity() const
{ {
return m_resolver; return m_resolver;
} }
FetchBodyStream::FetchBodyStream(ExecutionContext* context, PassRefPtr<BlobDataHandle> blobDataHandle) Body::Body(ExecutionContext* context)
: ActiveDOMObject(context) : ActiveDOMObject(context)
, m_blobDataHandle(blobDataHandle) , m_bodyUsed(false)
, m_hasRead(false)
{ {
if (!m_blobDataHandle) {
m_blobDataHandle = BlobDataHandle::create(BlobData::create(), 0);
}
} }
void FetchBodyStream::resolveJSON() void Body::resolveJSON()
{ {
ASSERT(m_responseType == ResponseAsJSON); ASSERT(m_responseType == ResponseAsJSON);
ScriptState::Scope scope(m_resolver->scriptState()); ScriptState::Scope scope(m_resolver->scriptState());
...@@ -138,9 +134,9 @@ void FetchBodyStream::resolveJSON() ...@@ -138,9 +134,9 @@ void FetchBodyStream::resolveJSON()
} }
// FileReaderLoaderClient functions. // FileReaderLoaderClient functions.
void FetchBodyStream::didStartLoading() { } void Body::didStartLoading() { }
void FetchBodyStream::didReceiveData() { } void Body::didReceiveData() { }
void FetchBodyStream::didFinishLoading() void Body::didFinishLoading()
{ {
if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped())
return; return;
...@@ -150,7 +146,7 @@ void FetchBodyStream::didFinishLoading() ...@@ -150,7 +146,7 @@ void FetchBodyStream::didFinishLoading()
m_resolver->resolve(m_loader->arrayBufferResult()); m_resolver->resolve(m_loader->arrayBufferResult());
break; break;
case ResponseAsBlob: { case ResponseAsBlob: {
ASSERT(m_blobDataHandle->size() == kuint64max); ASSERT(blobDataHandle()->size() == kuint64max);
OwnPtr<BlobData> blobData = BlobData::create(); OwnPtr<BlobData> blobData = BlobData::create();
RefPtr<ArrayBuffer> buffer = m_loader->arrayBufferResult(); RefPtr<ArrayBuffer> buffer = m_loader->arrayBufferResult();
blobData->appendArrayBuffer(buffer.get()); blobData->appendArrayBuffer(buffer.get());
...@@ -173,7 +169,7 @@ void FetchBodyStream::didFinishLoading() ...@@ -173,7 +169,7 @@ void FetchBodyStream::didFinishLoading()
m_resolver.clear(); m_resolver.clear();
} }
void FetchBodyStream::didFail(FileError::ErrorCode code) void Body::didFail(FileError::ErrorCode code)
{ {
ASSERT(m_resolver); ASSERT(m_resolver);
if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped())
......
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef FetchBodyStream_h #ifndef Body_h
#define FetchBodyStream_h #define Body_h
#include "bindings/core/v8/ScriptPromise.h" #include "bindings/core/v8/ScriptPromise.h"
#include "bindings/core/v8/ScriptPromiseResolver.h" #include "bindings/core/v8/ScriptPromiseResolver.h"
...@@ -19,13 +19,15 @@ namespace blink { ...@@ -19,13 +19,15 @@ namespace blink {
class ScriptState; class ScriptState;
class FetchBodyStream FINAL class Body
: public GarbageCollectedFinalized<FetchBodyStream> : public GarbageCollectedFinalized<Body>
, public ScriptWrappable , public ScriptWrappable
, public ActiveDOMObject , public ActiveDOMObject
, public FileReaderLoaderClient { , public FileReaderLoaderClient {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
explicit Body(ExecutionContext*);
virtual ~Body() { }
enum ResponseType { enum ResponseType {
ResponseAsArrayBuffer, ResponseAsArrayBuffer,
ResponseAsBlob, ResponseAsBlob,
...@@ -34,22 +36,21 @@ public: ...@@ -34,22 +36,21 @@ public:
ResponseAsText ResponseAsText
}; };
static FetchBodyStream* create(ExecutionContext*, PassRefPtr<BlobDataHandle>); ScriptPromise arrayBuffer(ScriptState*);
ScriptPromise blob(ScriptState*);
ScriptPromise formData(ScriptState*);
ScriptPromise json(ScriptState*);
ScriptPromise text(ScriptState*);
ScriptPromise asArrayBuffer(ScriptState*); bool bodyUsed() const;
ScriptPromise asBlob(ScriptState*);
ScriptPromise asFormData(ScriptState*);
ScriptPromise asJSON(ScriptState*);
ScriptPromise asText(ScriptState*);
// ActiveDOMObject override. // ActiveDOMObject override.
virtual void stop() OVERRIDE; virtual void stop() OVERRIDE;
virtual bool hasPendingActivity() const OVERRIDE; virtual bool hasPendingActivity() const OVERRIDE;
void trace(Visitor*) { } virtual void trace(Visitor*) { }
private: private:
FetchBodyStream(ExecutionContext*, PassRefPtr<BlobDataHandle>);
ScriptPromise readAsync(ScriptState*, ResponseType); ScriptPromise readAsync(ScriptState*, ResponseType);
void resolveJSON(); void resolveJSON();
...@@ -59,13 +60,14 @@ private: ...@@ -59,13 +60,14 @@ private:
virtual void didFinishLoading() OVERRIDE; virtual void didFinishLoading() OVERRIDE;
virtual void didFail(FileError::ErrorCode) OVERRIDE; virtual void didFail(FileError::ErrorCode) OVERRIDE;
RefPtr<BlobDataHandle> m_blobDataHandle; virtual PassRefPtr<BlobDataHandle> blobDataHandle() = 0;
OwnPtr<FileReaderLoader> m_loader; OwnPtr<FileReaderLoader> m_loader;
bool m_hasRead; bool m_bodyUsed;
ResponseType m_responseType; ResponseType m_responseType;
RefPtr<ScriptPromiseResolver> m_resolver; RefPtr<ScriptPromiseResolver> m_resolver;
}; };
} // namespace blink } // namespace blink
#endif // FetchBodyStream_h #endif // Body_h
...@@ -2,20 +2,20 @@ ...@@ -2,20 +2,20 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
// http://fetch.spec.whatwg.org/#fetchbodystream // http://fetch.spec.whatwg.org/#body
[ [
RuntimeEnabled=ServiceWorker, RuntimeEnabled=ServiceWorker,
Exposed=ServiceWorker, Exposed=ServiceWorker,
NoInterfaceObject, NoInterfaceObject,
ActiveDOMObject, ActiveDOMObject,
GarbageCollected, GarbageCollected,
] interface FetchBodyStream { ] interface Body {
[CallWith=ScriptState] Promise asArrayBuffer(); readonly attribute boolean bodyUsed;
[CallWith=ScriptState] Promise asBlob(); [CallWith=ScriptState] Promise arrayBuffer();
[CallWith=ScriptState] Promise asJSON(); [CallWith=ScriptState] Promise blob();
[CallWith=ScriptState] Promise asText(); [CallWith=ScriptState] Promise json();
[CallWith=ScriptState] Promise text();
// Still to be implemented. // Still to be implemented.
// [CallWith=ScriptState] Promise asFormData(); // [CallWith=ScriptState] Promise formData();
}; };
...@@ -112,7 +112,7 @@ void FetchManager::Loader::didFinishLoading(unsigned long, double) ...@@ -112,7 +112,7 @@ void FetchManager::Loader::didFinishLoading(unsigned long, double)
response = response->createOpaqueFilteredResponse(); response = response->createOpaqueFilteredResponse();
break; break;
} }
m_resolver->resolve(Response::create(response)); m_resolver->resolve(Response::create(m_resolver->executionContext(), response));
notifyFinished(); notifyFinished();
} }
......
...@@ -44,7 +44,7 @@ private: ...@@ -44,7 +44,7 @@ private:
WebServiceWorkerRequest* m_webRequest; WebServiceWorkerRequest* m_webRequest;
}; };
Request* createRequestWithRequestData(FetchRequestData* request, const RequestInit& init, FetchRequestData::Mode mode, FetchRequestData::Credentials credentials, ExceptionState& exceptionState) Request* createRequestWithRequestData(ExecutionContext* context, FetchRequestData* request, const RequestInit& init, FetchRequestData::Mode mode, FetchRequestData::Credentials credentials, ExceptionState& exceptionState)
{ {
// "6. Let |mode| be |init|'s mode member if it is present, and // "6. Let |mode| be |init|'s mode member if it is present, and
// |fallbackMode| otherwise." // |fallbackMode| otherwise."
...@@ -94,8 +94,8 @@ Request* createRequestWithRequestData(FetchRequestData* request, const RequestIn ...@@ -94,8 +94,8 @@ Request* createRequestWithRequestData(FetchRequestData* request, const RequestIn
request->setMethod(XMLHttpRequest::uppercaseKnownHTTPMethod(AtomicString(init.method))); request->setMethod(XMLHttpRequest::uppercaseKnownHTTPMethod(AtomicString(init.method)));
} }
// "11. Let |r| be a new Request object associated with |request|, Headers // "11. Let |r| be a new Request object associated with |request|, Headers
// object, and FetchBodyStream object." // object."
Request* r = Request::create(request); Request* r = Request::create(context, request);
// "12. Let |headers| be a copy of |r|'s Headers object." // "12. Let |headers| be a copy of |r|'s Headers object."
// "13. If |init|'s headers member is present, set |headers| to |init|'s // "13. If |init|'s headers member is present, set |headers| to |init|'s
...@@ -149,9 +149,9 @@ Request* createRequestWithRequestData(FetchRequestData* request, const RequestIn ...@@ -149,9 +149,9 @@ Request* createRequestWithRequestData(FetchRequestData* request, const RequestIn
if (exceptionState.hadException()) if (exceptionState.hadException())
return 0; return 0;
} }
// "18. Set |r|'s FetchBodyStream object's MIME type to the result of // "18. Set |r|'s MIME type to the result of extracting a MIME type from
// extracting a MIME type from |r|'s request's header list." // |r|'s request's header list."
// FIXME: We don't have MIME type in FetchBodyStream object yet. // FIXME: We don't have MIME type in Request object yet.
// "19. Return |r|." // "19. Return |r|."
return r; return r;
...@@ -184,7 +184,7 @@ Request* Request::create(ExecutionContext* context, const String& input, const D ...@@ -184,7 +184,7 @@ Request* Request::create(ExecutionContext* context, const String& input, const D
request->setURL(parsedURL); request->setURL(parsedURL);
// "4. Set |fallbackMode| to CORS." // "4. Set |fallbackMode| to CORS."
// "5. Set |fallbackCredentials| to omit." // "5. Set |fallbackCredentials| to omit."
return createRequestWithRequestData(request, RequestInit(context, init, exceptionState), FetchRequestData::CORSMode, FetchRequestData::OmitCredentials, exceptionState); return createRequestWithRequestData(context, request, RequestInit(context, init, exceptionState), FetchRequestData::CORSMode, FetchRequestData::OmitCredentials, exceptionState);
} }
Request* Request::create(ExecutionContext* context, Request* input, ExceptionState& exceptionState) Request* Request::create(ExecutionContext* context, Request* input, ExceptionState& exceptionState)
...@@ -204,28 +204,34 @@ Request* Request::create(ExecutionContext* context, Request* input, const Dictio ...@@ -204,28 +204,34 @@ Request* Request::create(ExecutionContext* context, Request* input, const Dictio
// mode and credentials; it has the same effect. // mode and credentials; it has the same effect.
const FetchRequestData::Mode currentMode = request->mode(); const FetchRequestData::Mode currentMode = request->mode();
const FetchRequestData::Credentials currentCredentials = request->credentials(); const FetchRequestData::Credentials currentCredentials = request->credentials();
return createRequestWithRequestData(request, RequestInit(context, init, exceptionState), currentMode, currentCredentials, exceptionState); return createRequestWithRequestData(context, request, RequestInit(context, init, exceptionState), currentMode, currentCredentials, exceptionState);
} }
Request* Request::create(FetchRequestData* request) Request* Request::create(ExecutionContext* context, FetchRequestData* request)
{ {
return new Request(request); Request* r = new Request(context, request);
r->suspendIfNeeded();
return r;
} }
Request::Request(FetchRequestData* request) Request::Request(ExecutionContext* context, FetchRequestData* request)
: m_request(request) : Body(context)
, m_request(request)
, m_headers(Headers::create(m_request->headerList())) , m_headers(Headers::create(m_request->headerList()))
{ {
m_headers->setGuard(Headers::RequestGuard); m_headers->setGuard(Headers::RequestGuard);
} }
Request* Request::create(const WebServiceWorkerRequest& webRequest) Request* Request::create(ExecutionContext* context, const WebServiceWorkerRequest& webRequest)
{ {
return new Request(webRequest); Request* r = new Request(context, webRequest);
r->suspendIfNeeded();
return r;
} }
Request::Request(const WebServiceWorkerRequest& webRequest) Request::Request(ExecutionContext* context, const WebServiceWorkerRequest& webRequest)
: m_request(FetchRequestData::create(webRequest)) : Body(context)
, m_request(FetchRequestData::create(webRequest))
, m_headers(Headers::create(m_request->headerList())) , m_headers(Headers::create(m_request->headerList()))
{ {
m_headers->setGuard(Headers::RequestGuard); m_headers->setGuard(Headers::RequestGuard);
...@@ -247,16 +253,6 @@ String Request::url() const ...@@ -247,16 +253,6 @@ String Request::url() const
return url; return url;
} }
FetchBodyStream* Request::body(ExecutionContext* context)
{
if (!m_request->blobDataHandle())
return 0;
if (!m_fetchBodyStream)
m_fetchBodyStream = FetchBodyStream::create(context, m_request->blobDataHandle());
return m_fetchBodyStream;
}
String Request::referrer() const String Request::referrer() const
{ {
// "The referrer attribute's getter must return the empty string if // "The referrer attribute's getter must return the empty string if
...@@ -309,16 +305,21 @@ void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques ...@@ -309,16 +305,21 @@ void Request::populateWebServiceWorkerRequest(WebServiceWorkerRequest& webReques
// to plumb this information in to here. // to plumb this information in to here.
} }
void Request::setBodyBlobHandle(PassRefPtr<BlobDataHandle>blobHandle) void Request::setBodyBlobHandle(PassRefPtr<BlobDataHandle> blobDataHandle)
{
m_request->setBlobDataHandle(blobDataHandle);
}
PassRefPtr<BlobDataHandle> Request::blobDataHandle()
{ {
m_request->setBlobDataHandle(blobHandle); return m_request->blobDataHandle();
} }
void Request::trace(Visitor* visitor) void Request::trace(Visitor* visitor)
{ {
Body::trace(visitor);
visitor->trace(m_request); visitor->trace(m_request);
visitor->trace(m_headers); visitor->trace(m_headers);
visitor->trace(m_fetchBodyStream);
} }
} // namespace blink } // namespace blink
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "bindings/core/v8/Dictionary.h" #include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/ScriptWrappable.h" #include "bindings/core/v8/ScriptWrappable.h"
#include "modules/serviceworkers/FetchBodyStream.h" #include "modules/serviceworkers/Body.h"
#include "modules/serviceworkers/FetchRequestData.h" #include "modules/serviceworkers/FetchRequestData.h"
#include "modules/serviceworkers/Headers.h" #include "modules/serviceworkers/Headers.h"
#include "platform/heap/Handle.h" #include "platform/heap/Handle.h"
...@@ -23,22 +23,22 @@ class ResourceRequest; ...@@ -23,22 +23,22 @@ class ResourceRequest;
struct ThreadableLoaderOptions; struct ThreadableLoaderOptions;
class WebServiceWorkerRequest; class WebServiceWorkerRequest;
class Request FINAL : public GarbageCollected<Request>, public ScriptWrappable { class Request FINAL : public Body {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
virtual ~Request() { }
static Request* create(ExecutionContext*, const String&, ExceptionState&); static Request* create(ExecutionContext*, const String&, ExceptionState&);
static Request* create(ExecutionContext*, const String&, const Dictionary&, ExceptionState&); static Request* create(ExecutionContext*, const String&, const Dictionary&, ExceptionState&);
static Request* create(ExecutionContext*, Request*, ExceptionState&); static Request* create(ExecutionContext*, Request*, ExceptionState&);
static Request* create(ExecutionContext*, Request*, const Dictionary&, ExceptionState&); static Request* create(ExecutionContext*, Request*, const Dictionary&, ExceptionState&);
static Request* create(FetchRequestData*); static Request* create(ExecutionContext*, FetchRequestData*);
static Request* create(const WebServiceWorkerRequest&); static Request* create(ExecutionContext*, const WebServiceWorkerRequest&);
FetchRequestData* request() { return m_request; } FetchRequestData* request() { return m_request; }
String method() const; String method() const;
String url() const; String url() const;
Headers* headers() const { return m_headers; } Headers* headers() const { return m_headers; }
FetchBodyStream* body(ExecutionContext*);
String referrer() const; String referrer() const;
String mode() const; String mode() const;
String credentials() const; String credentials() const;
...@@ -47,15 +47,16 @@ public: ...@@ -47,15 +47,16 @@ public:
void setBodyBlobHandle(PassRefPtr<BlobDataHandle>); void setBodyBlobHandle(PassRefPtr<BlobDataHandle>);
void trace(Visitor*); virtual void trace(Visitor*) OVERRIDE;
private: private:
explicit Request(FetchRequestData*); Request(ExecutionContext*, FetchRequestData*);
explicit Request(const WebServiceWorkerRequest&); Request(ExecutionContext*, const WebServiceWorkerRequest&);
virtual PassRefPtr<BlobDataHandle> blobDataHandle() OVERRIDE;
Member<FetchRequestData> m_request; Member<FetchRequestData> m_request;
Member<Headers> m_headers; Member<Headers> m_headers;
Member<FetchBodyStream> m_fetchBodyStream;
}; };
} // namespace blink } // namespace blink
......
...@@ -19,7 +19,6 @@ enum RequestCredentials { "omit", "same-origin", "include" }; ...@@ -19,7 +19,6 @@ enum RequestCredentials { "omit", "same-origin", "include" };
readonly attribute ByteString method; readonly attribute ByteString method;
readonly attribute ScalarValueString url; readonly attribute ScalarValueString url;
readonly attribute Headers headers; readonly attribute Headers headers;
[CallWith=ExecutionContext] readonly attribute FetchBodyStream body;
readonly attribute DOMString referrer; readonly attribute DOMString referrer;
readonly attribute RequestMode mode; readonly attribute RequestMode mode;
...@@ -28,3 +27,5 @@ enum RequestCredentials { "omit", "same-origin", "include" }; ...@@ -28,3 +27,5 @@ enum RequestCredentials { "omit", "same-origin", "include" };
// FIXME: Implement the following: // FIXME: Implement the following:
// readonly attribute RequestContext context; // readonly attribute RequestContext context;
}; };
Request implements Body;
...@@ -71,7 +71,7 @@ TEST_F(ServiceWorkerRequestTest, FromAndToWebRequest) ...@@ -71,7 +71,7 @@ TEST_F(ServiceWorkerRequestTest, FromAndToWebRequest)
webRequest.setHeader(WebString::fromUTF8(headers[i].key), WebString::fromUTF8(headers[i].value)); webRequest.setHeader(WebString::fromUTF8(headers[i].key), WebString::fromUTF8(headers[i].value));
webRequest.setReferrer(referrer, referrerPolicy); webRequest.setReferrer(referrer, referrerPolicy);
Request* request = Request::create(webRequest); Request* request = Request::create(executionContext(), webRequest);
ASSERT(request); ASSERT(request);
EXPECT_EQ(url, request->url()); EXPECT_EQ(url, request->url());
EXPECT_EQ(method, request->method()); EXPECT_EQ(method, request->method());
......
...@@ -8,7 +8,6 @@ ...@@ -8,7 +8,6 @@
#include "bindings/core/v8/Dictionary.h" #include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "core/fileapi/Blob.h" #include "core/fileapi/Blob.h"
#include "modules/serviceworkers/FetchBodyStream.h"
#include "modules/serviceworkers/ResponseInit.h" #include "modules/serviceworkers/ResponseInit.h"
#include "public/platform/WebServiceWorkerResponse.h" #include "public/platform/WebServiceWorkerResponse.h"
#include "wtf/ArrayBuffer.h" #include "wtf/ArrayBuffer.h"
...@@ -47,12 +46,12 @@ Headers* createHeadersFromWebResponse(const WebServiceWorkerResponse& webRespons ...@@ -47,12 +46,12 @@ Headers* createHeadersFromWebResponse(const WebServiceWorkerResponse& webRespons
} }
Response* Response::create(Blob* body, const Dictionary& responseInit, ExceptionState& exceptionState) Response* Response::create(ExecutionContext* context, Blob* body, const Dictionary& responseInit, ExceptionState& exceptionState)
{ {
return create(body, ResponseInit(responseInit), exceptionState); return create(context, body, ResponseInit(responseInit), exceptionState);
} }
Response* Response::create(const String& body, const Dictionary& responseInit, ExceptionState& exceptionState) Response* Response::create(ExecutionContext* context, const String& body, const Dictionary& responseInit, ExceptionState& exceptionState)
{ {
OwnPtr<BlobData> blobData = BlobData::create(); OwnPtr<BlobData> blobData = BlobData::create();
blobData->appendText(body, false); blobData->appendText(body, false);
...@@ -60,28 +59,28 @@ Response* Response::create(const String& body, const Dictionary& responseInit, E ...@@ -60,28 +59,28 @@ Response* Response::create(const String& body, const Dictionary& responseInit, E
blobData->setContentType("text/plain;charset=UTF-8"); blobData->setContentType("text/plain;charset=UTF-8");
const long long length = blobData->length(); const long long length = blobData->length();
RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length));
return create(blob.get(), ResponseInit(responseInit), exceptionState); return create(context, blob.get(), ResponseInit(responseInit), exceptionState);
} }
Response* Response::create(const ArrayBuffer* body, const Dictionary& responseInit, ExceptionState& exceptionState) Response* Response::create(ExecutionContext* context, const ArrayBuffer* body, const Dictionary& responseInit, ExceptionState& exceptionState)
{ {
OwnPtr<BlobData> blobData = BlobData::create(); OwnPtr<BlobData> blobData = BlobData::create();
blobData->appendArrayBuffer(body); blobData->appendArrayBuffer(body);
const long long length = blobData->length(); const long long length = blobData->length();
RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length));
return create(blob.get(), ResponseInit(responseInit), exceptionState); return create(context, blob.get(), ResponseInit(responseInit), exceptionState);
} }
Response* Response::create(const ArrayBufferView* body, const Dictionary& responseInit, ExceptionState& exceptionState) Response* Response::create(ExecutionContext* context, const ArrayBufferView* body, const Dictionary& responseInit, ExceptionState& exceptionState)
{ {
OwnPtr<BlobData> blobData = BlobData::create(); OwnPtr<BlobData> blobData = BlobData::create();
blobData->appendArrayBufferView(body); blobData->appendArrayBufferView(body);
const long long length = blobData->length(); const long long length = blobData->length();
RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length)); RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), length));
return create(blob.get(), ResponseInit(responseInit), exceptionState); return create(context, blob.get(), ResponseInit(responseInit), exceptionState);
} }
Response* Response::create(Blob* body, const ResponseInit& responseInit, ExceptionState& exceptionState) Response* Response::create(ExecutionContext* context, Blob* body, const ResponseInit& responseInit, ExceptionState& exceptionState)
{ {
// "1. If |init|'s status member is not in the range 200 to 599, throw a // "1. If |init|'s status member is not in the range 200 to 599, throw a
// RangeError." // RangeError."
...@@ -94,8 +93,9 @@ Response* Response::create(Blob* body, const ResponseInit& responseInit, Excepti ...@@ -94,8 +93,9 @@ Response* Response::create(Blob* body, const ResponseInit& responseInit, Excepti
// token production, throw a TypeError." // token production, throw a TypeError."
// "3. Let |r| be a new Response object, associated with a new response, // "3. Let |r| be a new Response object, associated with a new response,
// Headers object, and FetchBodyStream object." // Headers object, and Body object."
Response* r = new Response(); Response* r = new Response(context);
r->suspendIfNeeded();
// "4. Set |r|'s response's status to |init|'s status member." // "4. Set |r|'s response's status to |init|'s status member."
r->m_response->setStatus(responseInit.status); r->m_response->setStatus(responseInit.status);
...@@ -133,21 +133,25 @@ Response* Response::create(Blob* body, const ResponseInit& responseInit, Excepti ...@@ -133,21 +133,25 @@ Response* Response::create(Blob* body, const ResponseInit& responseInit, Excepti
r->m_response->headerList()->append("Content-Type", body->type()); r->m_response->headerList()->append("Content-Type", body->type());
} }
// FIXME: "8. Set |r|'s FetchBodyStream object's MIME type to the result of // FIXME: "8. Set |r|'s MIME type to the result of extracting a MIME type
// extracting a MIME type from |r|'s response's header list." // from |r|'s response's header list."
// "9. Return |r|." // "9. Return |r|."
return r; return r;
} }
Response* Response::create(FetchResponseData* response) Response* Response::create(ExecutionContext* context, FetchResponseData* response)
{ {
return new Response(response); Response* r = new Response(context, response);
r->suspendIfNeeded();
return r;
} }
Response* Response::create(const WebServiceWorkerResponse& webResponse) Response* Response::create(ExecutionContext* context, const WebServiceWorkerResponse& webResponse)
{ {
return new Response(webResponse); Response* r = new Response(context, webResponse);
r->suspendIfNeeded();
return r;
} }
String Response::type() const String Response::type() const
...@@ -199,47 +203,46 @@ Headers* Response::headers() const ...@@ -199,47 +203,46 @@ Headers* Response::headers() const
return m_headers; return m_headers;
} }
FetchBodyStream* Response::body(ExecutionContext* context)
{
if (!m_response->blobDataHandle())
return 0;
if (!m_fetchBodyStream)
m_fetchBodyStream = FetchBodyStream::create(context, m_response->blobDataHandle());
return m_fetchBodyStream;
}
void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& response) void Response::populateWebServiceWorkerResponse(WebServiceWorkerResponse& response)
{ {
m_response->populateWebServiceWorkerResponse(response); m_response->populateWebServiceWorkerResponse(response);
} }
Response::Response() Response::Response(ExecutionContext* context)
: m_response(FetchResponseData::create()) : Body(context)
, m_response(FetchResponseData::create())
, m_headers(Headers::create(m_response->headerList())) , m_headers(Headers::create(m_response->headerList()))
{ {
m_headers->setGuard(Headers::ResponseGuard); m_headers->setGuard(Headers::ResponseGuard);
} }
Response::Response(FetchResponseData* response) Response::Response(ExecutionContext* context, FetchResponseData* response)
: m_response(response) : Body(context)
, m_response(response)
, m_headers(Headers::create(m_response->headerList())) , m_headers(Headers::create(m_response->headerList()))
{ {
m_headers->setGuard(Headers::ResponseGuard); m_headers->setGuard(Headers::ResponseGuard);
} }
// FIXME: Handle response body data. // FIXME: Handle response body data.
Response::Response(const WebServiceWorkerResponse& webResponse) Response::Response(ExecutionContext* context, const WebServiceWorkerResponse& webResponse)
: m_response(createFetchResponseDataFromWebResponse(webResponse)) : Body(context)
, m_response(createFetchResponseDataFromWebResponse(webResponse))
, m_headers(createHeadersFromWebResponse(webResponse)) , m_headers(createHeadersFromWebResponse(webResponse))
{ {
m_headers->setGuard(Headers::ResponseGuard); m_headers->setGuard(Headers::ResponseGuard);
} }
PassRefPtr<BlobDataHandle> Response::blobDataHandle()
{
return m_response->blobDataHandle();
}
void Response::trace(Visitor* visitor) void Response::trace(Visitor* visitor)
{ {
Body::trace(visitor);
visitor->trace(m_response); visitor->trace(m_response);
visitor->trace(m_headers); visitor->trace(m_headers);
visitor->trace(m_fetchBodyStream);
} }
} // namespace blink } // namespace blink
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#include "bindings/core/v8/Dictionary.h" #include "bindings/core/v8/Dictionary.h"
#include "bindings/core/v8/ScriptWrappable.h" #include "bindings/core/v8/ScriptWrappable.h"
#include "modules/serviceworkers/FetchBodyStream.h" #include "modules/serviceworkers/Body.h"
#include "modules/serviceworkers/FetchResponseData.h" #include "modules/serviceworkers/FetchResponseData.h"
#include "modules/serviceworkers/Headers.h" #include "modules/serviceworkers/Headers.h"
#include "platform/blob/BlobData.h" #include "platform/blob/BlobData.h"
...@@ -21,16 +21,17 @@ class ExceptionState; ...@@ -21,16 +21,17 @@ class ExceptionState;
class ResponseInit; class ResponseInit;
class WebServiceWorkerResponse; class WebServiceWorkerResponse;
class Response FINAL : public GarbageCollected<Response>, public ScriptWrappable { class Response FINAL : public Body {
DEFINE_WRAPPERTYPEINFO(); DEFINE_WRAPPERTYPEINFO();
public: public:
static Response* create(Blob*, const Dictionary&, ExceptionState&); virtual ~Response() { }
static Response* create(const String&, const Dictionary&, ExceptionState&); static Response* create(ExecutionContext*, Blob*, const Dictionary&, ExceptionState&);
static Response* create(const ArrayBuffer*, const Dictionary&, ExceptionState&); static Response* create(ExecutionContext*, const String&, const Dictionary&, ExceptionState&);
static Response* create(const ArrayBufferView*, const Dictionary&, ExceptionState&); static Response* create(ExecutionContext*, const ArrayBuffer*, const Dictionary&, ExceptionState&);
static Response* create(Blob*, const ResponseInit&, ExceptionState&); static Response* create(ExecutionContext*, const ArrayBufferView*, const Dictionary&, ExceptionState&);
static Response* create(FetchResponseData*); static Response* create(ExecutionContext*, Blob*, const ResponseInit&, ExceptionState&);
static Response* create(const WebServiceWorkerResponse&); static Response* create(ExecutionContext*, FetchResponseData*);
static Response* create(ExecutionContext*, const WebServiceWorkerResponse&);
String type() const; String type() const;
String url() const; String url() const;
...@@ -38,20 +39,19 @@ public: ...@@ -38,20 +39,19 @@ public:
String statusText() const; String statusText() const;
Headers* headers() const; Headers* headers() const;
FetchBodyStream* body(ExecutionContext*);
void populateWebServiceWorkerResponse(WebServiceWorkerResponse&); void populateWebServiceWorkerResponse(WebServiceWorkerResponse&);
void trace(Visitor*); virtual void trace(Visitor*) OVERRIDE;
private: private:
Response(); explicit Response(ExecutionContext*);
explicit Response(FetchResponseData*); Response(ExecutionContext*, FetchResponseData*);
explicit Response(const WebServiceWorkerResponse&); Response(ExecutionContext*, const WebServiceWorkerResponse&);
virtual PassRefPtr<BlobDataHandle> blobDataHandle() OVERRIDE;
Member<FetchResponseData> m_response; Member<FetchResponseData> m_response;
Member<Headers> m_headers; Member<Headers> m_headers;
Member<FetchBodyStream> m_fetchBodyStream;
}; };
} // namespace blink } // namespace blink
......
...@@ -12,6 +12,7 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque" }; ...@@ -12,6 +12,7 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque" };
Constructor(Blob? body, optional Dictionary responseInitDict), Constructor(Blob? body, optional Dictionary responseInitDict),
Constructor(ArrayBuffer input, optional Dictionary requestInitDict), Constructor(ArrayBuffer input, optional Dictionary requestInitDict),
Constructor(ArrayBufferView input, optional Dictionary requestInitDict), Constructor(ArrayBufferView input, optional Dictionary requestInitDict),
ConstructorCallWith=ExecutionContext,
RuntimeEnabled=ServiceWorker, RuntimeEnabled=ServiceWorker,
Exposed=ServiceWorker, Exposed=ServiceWorker,
RaisesException=Constructor, RaisesException=Constructor,
...@@ -23,5 +24,6 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque" }; ...@@ -23,5 +24,6 @@ enum ResponseType { "basic", "cors", "default", "error", "opaque" };
readonly attribute unsigned short status; readonly attribute unsigned short status;
readonly attribute ByteString statusText; readonly attribute ByteString statusText;
readonly attribute Headers headers; readonly attribute Headers headers;
[CallWith=ExecutionContext] readonly attribute FetchBodyStream body;
}; };
Response implements Body;
...@@ -5,6 +5,10 @@ ...@@ -5,6 +5,10 @@
#include "config.h" #include "config.h"
#include "bindings/core/v8/ExceptionState.h" #include "bindings/core/v8/ExceptionState.h"
#include "bindings/core/v8/ScriptState.h"
#include "core/dom/Document.h"
#include "core/frame/Frame.h"
#include "core/testing/DummyPageHolder.h"
#include "modules/serviceworkers/Response.h" #include "modules/serviceworkers/Response.h"
#include "modules/serviceworkers/FetchResponseData.h" #include "modules/serviceworkers/FetchResponseData.h"
#include "public/platform/WebServiceWorkerResponse.h" #include "public/platform/WebServiceWorkerResponse.h"
...@@ -13,19 +17,32 @@ ...@@ -13,19 +17,32 @@
namespace blink { namespace blink {
namespace { namespace {
TEST(ServiceWorkerResponseTest, FromFetchResponseData) class ServiceWorkerResponseTest : public ::testing::Test {
public:
ServiceWorkerResponseTest()
: m_page(DummyPageHolder::create(IntSize(1, 1))) { }
ScriptState* scriptState() { return ScriptState::forMainWorld(m_page->document().frame()); }
ExecutionContext* executionContext() { return scriptState()->executionContext(); }
private:
OwnPtr<DummyPageHolder> m_page;
};
TEST_F(ServiceWorkerResponseTest, FromFetchResponseData)
{ {
const KURL url(ParsedURLString, "http://www.response.com"); const KURL url(ParsedURLString, "http://www.response.com");
FetchResponseData* fetchResponseData = FetchResponseData::create(); FetchResponseData* fetchResponseData = FetchResponseData::create();
fetchResponseData->setURL(url); fetchResponseData->setURL(url);
Response* response = Response::create(fetchResponseData); Response* response = Response::create(executionContext(), fetchResponseData);
ASSERT(response); ASSERT(response);
EXPECT_EQ(url, response->url()); EXPECT_EQ(url, response->url());
} }
TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponse) TEST_F(ServiceWorkerResponseTest, FromWebServiceWorkerResponse)
{ {
const KURL url(ParsedURLString, "http://www.webresponse.com/"); const KURL url(ParsedURLString, "http://www.webresponse.com/");
const unsigned short status = 200; const unsigned short status = 200;
...@@ -39,7 +56,7 @@ TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponse) ...@@ -39,7 +56,7 @@ TEST(ServiceWorkerResponseTest, FromWebServiceWorkerResponse)
for (int i = 0; headers[i].key; ++i) for (int i = 0; headers[i].key; ++i)
webResponse.setHeader(WebString::fromUTF8(headers[i].key), WebString::fromUTF8(headers[i].value)); webResponse.setHeader(WebString::fromUTF8(headers[i].key), WebString::fromUTF8(headers[i].value));
Response* response = Response::create(webResponse); Response* response = Response::create(executionContext(), webResponse);
ASSERT(response); ASSERT(response);
EXPECT_EQ(url, response->url()); EXPECT_EQ(url, response->url());
EXPECT_EQ(status, response->status()); EXPECT_EQ(status, response->status());
......
...@@ -85,7 +85,7 @@ void ServiceWorkerGlobalScopeProxy::dispatchFetchEvent(int eventID, const WebSer ...@@ -85,7 +85,7 @@ void ServiceWorkerGlobalScopeProxy::dispatchFetchEvent(int eventID, const WebSer
{ {
ASSERT(m_workerGlobalScope); ASSERT(m_workerGlobalScope);
RespondWithObserver* observer = RespondWithObserver::create(m_workerGlobalScope, eventID); RespondWithObserver* observer = RespondWithObserver::create(m_workerGlobalScope, eventID);
Request* request = Request::create(webRequest); Request* request = Request::create(m_workerGlobalScope, webRequest);
RefPtrWillBeRawPtr<FetchEvent> fetchEvent(FetchEvent::create(observer, request)); RefPtrWillBeRawPtr<FetchEvent> fetchEvent(FetchEvent::create(observer, request));
fetchEvent->setIsReload(webRequest.isReload()); fetchEvent->setIsReload(webRequest.isReload());
m_workerGlobalScope->dispatchEvent(fetchEvent.release()); m_workerGlobalScope->dispatchEvent(fetchEvent.release());
......
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