Request* Request::clone(ExceptionState& exceptionState) const { if (bodyUsed()) { exceptionState.throwTypeError("Request body is already used"); return nullptr; } FetchRequestData* request = m_request->clone(); if (blobDataHandle() && isBodyConsumed()) { // Currently the only methods that can consume body data without // setting 'body passed' flag consume entire body (e.g. text()). Thus // we can set an empty blob to the new request instead of creating a // draining stream. // TODO(yhirano): Fix this once Request.body is introduced. OwnPtr<BlobData> blobData = BlobData::create(); blobData->setContentType(blobDataHandle()->type()); request->setBlobDataHandle(BlobDataHandle::create(blobData.release(), 0)); } Headers* headers = Headers::create(request->headerList()); headers->setGuard(m_headers->guard()); Request* r = new Request(executionContext(), request, headers); r->suspendIfNeeded(); return r; }
void Body::didFinishLoading() { if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) return; switch (m_responseType) { case ResponseAsArrayBuffer: m_resolver->resolve(DOMArrayBuffer::create(m_loader->arrayBufferResult())); break; case ResponseAsBlob: { ASSERT(blobDataHandle()->size() == kuint64max); OwnPtr<BlobData> blobData = BlobData::create(); RefPtr<ArrayBuffer> buffer = m_loader->arrayBufferResult(); blobData->appendArrayBuffer(buffer.get()); const size_t length = blobData->length(); m_resolver->resolve(Blob::create(BlobDataHandle::create(blobData.release(), length))); break; } case ResponseAsFormData: ASSERT_NOT_REACHED(); break; case ResponseAsJSON: resolveJSON(); break; case ResponseAsText: m_resolver->resolve(m_loader->stringResult()); break; default: ASSERT_NOT_REACHED(); } m_resolver.clear(); }
void Body::pullSource() { if (!m_streamAccessed) { // We do not download data unless the user explicitly uses the // ReadableStream object in order to avoid performance regression, // because currently Chrome cannot handle Streams efficiently // especially with ServiceWorker or Blob. return; } if (m_bodyUsed) { m_stream->error(DOMException::create(InvalidStateError, "The stream is locked.")); return; } ASSERT(!m_loader); if (buffer()) { // If the body has a body buffer, we read all data from the buffer and // create a blob and then put the data from the blob to |m_stream|. // FIXME: Put the data directry from the buffer. buffer()->readAllAndCreateBlobHandle(contentTypeForBuffer(), new BlobHandleReceiver(this)); return; } RefPtr<BlobDataHandle> blobHandle = blobDataHandle(); if (!blobHandle.get()) { blobHandle = BlobDataHandle::create(BlobData::create(), 0); } readAsyncFromBlob(blobHandle); }
ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type) { if (m_bodyUsed) return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read")); // When the main thread sends a V8::TerminateExecution() signal to a worker // thread, any V8 API on the worker thread starts returning an empty // handle. This can happen in Body::readAsync. To avoid the situation, we // first check the ExecutionContext and return immediately if it's already // gone (which means that the V8::TerminateExecution() signal has been sent // to this worker thread). ExecutionContext* executionContext = scriptState->executionContext(); if (!executionContext) return ScriptPromise(); m_bodyUsed = true; m_responseType = type; ASSERT(!m_resolver); m_resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = m_resolver->promise(); if (m_streamAccessed) { // 'body' attribute was accessed and the stream source started pulling. switch (m_stream->state()) { case ReadableStream::Readable: readAllFromStream(scriptState); return promise; case ReadableStream::Waiting: // m_loader is working and m_resolver will be resolved when it // ends. return promise; case ReadableStream::Closed: case ReadableStream::Errored: m_resolver->resolve(m_stream->closed(scriptState).v8Value()); return promise; break; } ASSERT_NOT_REACHED(); return promise; } if (buffer()) { buffer()->readAllAndCreateBlobHandle(contentTypeForBuffer(), new BlobHandleReceiver(this)); return promise; } readAsyncFromBlob(blobDataHandle()); return promise; }
void FetchResponseData::populateWebServiceWorkerResponse(WebServiceWorkerResponse& response) { if (m_internalResponse) { m_internalResponse->populateWebServiceWorkerResponse(response); response.setResponseType(fetchTypeToWebType(m_type)); return; } response.setURL(url()); response.setStatus(status()); response.setStatusText(statusMessage()); response.setResponseType(fetchTypeToWebType(m_type)); for (size_t i = 0; i < headerList()->size(); ++i) { const FetchHeaderList::Header* header = headerList()->list()[i].get(); response.appendHeader(header->first, header->second); } response.setBlobDataHandle(blobDataHandle()); }
ScriptPromise Body::readAsync(ScriptState* scriptState, ResponseType type) { if (m_bodyUsed) return ScriptPromise::reject(scriptState, V8ThrowException::createTypeError(scriptState->isolate(), "Already read")); // When the main thread sends a V8::TerminateExecution() signal to a worker // thread, any V8 API on the worker thread starts returning an empty // handle. This can happen in Body::readAsync. To avoid the situation, we // first check the ExecutionContext and return immediately if it's already // gone (which means that the V8::TerminateExecution() signal has been sent // to this worker thread). ExecutionContext* executionContext = scriptState->executionContext(); if (!executionContext) return ScriptPromise(); m_bodyUsed = true; m_responseType = type; ASSERT(!m_resolver); m_resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = m_resolver->promise(); FileReaderLoader::ReadType readType = FileReaderLoader::ReadAsText; RefPtr<BlobDataHandle> blobHandle = blobDataHandle(); if (!blobHandle.get()) { blobHandle = BlobDataHandle::create(BlobData::create(), 0); } switch (type) { case ResponseAsArrayBuffer: readType = FileReaderLoader::ReadAsArrayBuffer; break; case ResponseAsBlob: if (blobHandle->size() != kuint64max) { // If the size of |blobHandle| is set correctly, creates Blob from // it. m_resolver->resolve(Blob::create(blobHandle)); m_resolver.clear(); return promise; } // 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. // When we will stop using Blob as a base system of Body to support // stream, this problem should be solved. readType = FileReaderLoader::ReadAsArrayBuffer; break; case ResponseAsFormData: // FIXME: Implement this. ASSERT_NOT_REACHED(); break; case ResponseAsJSON: case ResponseAsText: break; default: ASSERT_NOT_REACHED(); } m_loader = adoptPtr(new FileReaderLoader(readType, this)); m_loader->start(executionContext, blobHandle); return promise; }