1/*
2 * Copyright (C) 2009 Apple Inc. All Rights Reserved.
3 * Copyright (C) 2009, 2011 Google Inc. All Rights Reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 *
26 */
27
28#include "config.h"
29
30#include "WorkerScriptLoader.h"
31
32#include "ResourceResponse.h"
33#include "ScriptExecutionContext.h"
34#include "SecurityOrigin.h"
35#include "TextResourceDecoder.h"
36#include "WorkerGlobalScope.h"
37#include "WorkerScriptLoaderClient.h"
38#include "WorkerThreadableLoader.h"
39#include <wtf/Ref.h>
40#include <wtf/RefPtr.h>
41
42namespace WebCore {
43
44WorkerScriptLoader::WorkerScriptLoader()
45    : m_client(0)
46    , m_failed(false)
47    , m_identifier(0)
48    , m_finishing(false)
49{
50}
51
52WorkerScriptLoader::~WorkerScriptLoader()
53{
54}
55
56void WorkerScriptLoader::loadSynchronously(ScriptExecutionContext* scriptExecutionContext, const URL& url, CrossOriginRequestPolicy crossOriginRequestPolicy)
57{
58    m_url = url;
59
60    std::unique_ptr<ResourceRequest> request(createResourceRequest());
61    if (!request)
62        return;
63
64    ASSERT_WITH_SECURITY_IMPLICATION(scriptExecutionContext->isWorkerGlobalScope());
65
66    ThreadableLoaderOptions options;
67    options.setAllowCredentials(AllowStoredCredentials);
68    options.crossOriginRequestPolicy = crossOriginRequestPolicy;
69    options.setSendLoadCallbacks(SendCallbacks);
70
71    WorkerThreadableLoader::loadResourceSynchronously(toWorkerGlobalScope(scriptExecutionContext), *request, *this, options);
72}
73
74void WorkerScriptLoader::loadAsynchronously(ScriptExecutionContext* scriptExecutionContext, const URL& url, CrossOriginRequestPolicy crossOriginRequestPolicy, WorkerScriptLoaderClient* client)
75{
76    ASSERT(client);
77    m_client = client;
78    m_url = url;
79
80    std::unique_ptr<ResourceRequest> request(createResourceRequest());
81    if (!request)
82        return;
83
84    ThreadableLoaderOptions options;
85    options.setAllowCredentials(AllowStoredCredentials);
86    options.crossOriginRequestPolicy = crossOriginRequestPolicy;
87    options.setSendLoadCallbacks(SendCallbacks);
88
89    // During create, callbacks may happen which remove the last reference to this object.
90    Ref<WorkerScriptLoader> protect(*this);
91    m_threadableLoader = ThreadableLoader::create(scriptExecutionContext, this, *request, options);
92}
93
94const URL& WorkerScriptLoader::responseURL() const
95{
96    ASSERT(!failed());
97    return m_responseURL;
98}
99
100std::unique_ptr<ResourceRequest> WorkerScriptLoader::createResourceRequest()
101{
102    auto request = std::make_unique<ResourceRequest>(m_url);
103    request->setHTTPMethod("GET");
104    return WTF::move(request);
105}
106
107void WorkerScriptLoader::didReceiveResponse(unsigned long identifier, const ResourceResponse& response)
108{
109    if (response.httpStatusCode() / 100 != 2 && response.httpStatusCode()) {
110        m_failed = true;
111        return;
112    }
113    m_responseURL = response.url();
114    m_responseEncoding = response.textEncodingName();
115    if (m_client)
116        m_client->didReceiveResponse(identifier, response);
117}
118
119void WorkerScriptLoader::didReceiveData(const char* data, int len)
120{
121    if (m_failed)
122        return;
123
124    if (!m_decoder) {
125        if (!m_responseEncoding.isEmpty())
126            m_decoder = TextResourceDecoder::create("text/javascript", m_responseEncoding);
127        else
128            m_decoder = TextResourceDecoder::create("text/javascript", "UTF-8");
129    }
130
131    if (!len)
132        return;
133
134    if (len == -1)
135        len = strlen(data);
136
137    m_script.append(m_decoder->decode(data, len));
138}
139
140void WorkerScriptLoader::didFinishLoading(unsigned long identifier, double)
141{
142    if (m_failed) {
143        notifyError();
144        return;
145    }
146
147    if (m_decoder)
148        m_script.append(m_decoder->flush());
149
150    m_identifier = identifier;
151    notifyFinished();
152}
153
154void WorkerScriptLoader::didFail(const ResourceError&)
155{
156    notifyError();
157}
158
159void WorkerScriptLoader::didFailRedirectCheck()
160{
161    notifyError();
162}
163
164void WorkerScriptLoader::notifyError()
165{
166    m_failed = true;
167    notifyFinished();
168}
169
170String WorkerScriptLoader::script()
171{
172    return m_script.toString();
173}
174
175void WorkerScriptLoader::notifyFinished()
176{
177    if (!m_client || m_finishing)
178        return;
179
180    m_finishing = true;
181    m_client->notifyFinished();
182}
183
184} // namespace WebCore
185