1/* 2 * Copyright (C) 2006, 2007, 2009 Apple Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 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 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 14 * its contributors may be used to endorse or promote products derived 15 * from this software without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29#include "config.h" 30#include "SubresourceLoader.h" 31 32#include "DocumentLoader.h" 33#include "Frame.h" 34#include "FrameLoader.h" 35#include "ResourceHandle.h" 36#include "SecurityOrigin.h" 37#include "SubresourceLoaderClient.h" 38#include <wtf/RefCountedLeakCounter.h> 39 40namespace WebCore { 41 42#ifndef NDEBUG 43static WTF::RefCountedLeakCounter subresourceLoaderCounter("SubresourceLoader"); 44#endif 45 46SubresourceLoader::SubresourceLoader(Frame* frame, SubresourceLoaderClient* client, bool sendResourceLoadCallbacks, bool shouldContentSniff) 47 : ResourceLoader(frame, sendResourceLoadCallbacks, shouldContentSniff) 48 , m_client(client) 49 , m_loadingMultipartContent(false) 50{ 51#ifndef NDEBUG 52 subresourceLoaderCounter.increment(); 53#endif 54 m_documentLoader->addSubresourceLoader(this); 55} 56 57SubresourceLoader::~SubresourceLoader() 58{ 59#ifndef NDEBUG 60 subresourceLoaderCounter.decrement(); 61#endif 62} 63 64PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff) 65{ 66 if (!frame) 67 return 0; 68 69 FrameLoader* fl = frame->loader(); 70 if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || fl->activeDocumentLoader()->isStopping())) 71 return 0; 72 73 ResourceRequest newRequest = request; 74 75 if (securityCheck == DoSecurityCheck 76 && SecurityOrigin::restrictAccessToLocal() 77 && !SecurityOrigin::canLoad(request.url(), String(), frame->document())) { 78 FrameLoader::reportLocalLoadFailed(frame, request.url().string()); 79 return 0; 80 } 81 82 if (SecurityOrigin::shouldHideReferrer(request.url(), fl->outgoingReferrer())) 83 newRequest.clearHTTPReferrer(); 84#ifdef ANDROID_FIX 85 else if (request.httpReferrer().isEmpty()) 86#else 87 else if (!request.httpReferrer()) 88#endif 89 newRequest.setHTTPReferrer(fl->outgoingReferrer()); 90 FrameLoader::addHTTPOriginIfNeeded(newRequest, fl->outgoingOrigin()); 91 92 // Use the original request's cache policy for two reasons: 93 // 1. For POST requests, we mutate the cache policy for the main resource, 94 // but we do not want this to apply to subresources 95 // 2. Delegates that modify the cache policy using willSendRequest: should 96 // not affect any other resources. Such changes need to be done 97 // per request. 98 if (newRequest.isConditional()) 99 newRequest.setCachePolicy(ReloadIgnoringCacheData); 100 else 101 newRequest.setCachePolicy(fl->originalRequest().cachePolicy()); 102 103 fl->addExtraFieldsToSubresourceRequest(newRequest); 104 105 RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff))); 106 if (!subloader->load(newRequest)) 107 return 0; 108 109 return subloader.release(); 110} 111 112void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) 113{ 114 // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it. 115 KURL previousURL = request().url(); 116 117 ResourceLoader::willSendRequest(newRequest, redirectResponse); 118 if (!previousURL.isNull() && !newRequest.isNull() && previousURL != newRequest.url() && m_client) 119 m_client->willSendRequest(this, newRequest, redirectResponse); 120} 121 122void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 123{ 124 RefPtr<SubresourceLoader> protect(this); 125 126 if (m_client) 127 m_client->didSendData(this, bytesSent, totalBytesToBeSent); 128} 129 130void SubresourceLoader::didReceiveResponse(const ResourceResponse& r) 131{ 132 ASSERT(!r.isNull()); 133 134 if (r.isMultipart()) 135 m_loadingMultipartContent = true; 136 137 // Reference the object in this method since the additional processing can do 138 // anything including removing the last reference to this object; one example of this is 3266216. 139 RefPtr<SubresourceLoader> protect(this); 140 141 if (m_client) 142 m_client->didReceiveResponse(this, r); 143 144 // The loader can cancel a load if it receives a multipart response for a non-image 145 if (reachedTerminalState()) 146 return; 147 ResourceLoader::didReceiveResponse(r); 148 149 RefPtr<SharedBuffer> buffer = resourceData(); 150 if (m_loadingMultipartContent && buffer && buffer->size()) { 151 // Since a subresource loader does not load multipart sections progressively, 152 // deliver the previously received data to the loader all at once now. 153 // Then clear the data to make way for the next multipart section. 154 if (m_client) 155 m_client->didReceiveData(this, buffer->data(), buffer->size()); 156 clearResourceData(); 157 158 // After the first multipart section is complete, signal to delegates that this load is "finished" 159 m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this); 160 didFinishLoadingOnePart(); 161 } 162} 163 164void SubresourceLoader::didReceiveData(const char* data, int length, long long lengthReceived, bool allAtOnce) 165{ 166 // Reference the object in this method since the additional processing can do 167 // anything including removing the last reference to this object; one example of this is 3266216. 168 RefPtr<SubresourceLoader> protect(this); 169 170 ResourceLoader::didReceiveData(data, length, lengthReceived, allAtOnce); 171 172 // A subresource loader does not load multipart sections progressively. 173 // So don't deliver any data to the loader yet. 174 if (!m_loadingMultipartContent && m_client) 175 m_client->didReceiveData(this, data, length); 176} 177 178void SubresourceLoader::didFinishLoading() 179{ 180 if (cancelled()) 181 return; 182 ASSERT(!reachedTerminalState()); 183 184 // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves. 185 RefPtr<SubresourceLoader> protect(this); 186 187 if (m_client) 188 m_client->didFinishLoading(this); 189 190 m_handle = 0; 191 192 if (cancelled()) 193 return; 194 m_documentLoader->removeSubresourceLoader(this); 195 ResourceLoader::didFinishLoading(); 196} 197 198void SubresourceLoader::didFail(const ResourceError& error) 199{ 200 if (cancelled()) 201 return; 202 ASSERT(!reachedTerminalState()); 203 204 // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves. 205 RefPtr<SubresourceLoader> protect(this); 206 207 if (m_client) 208 m_client->didFail(this, error); 209 210 m_handle = 0; 211 212 if (cancelled()) 213 return; 214 m_documentLoader->removeSubresourceLoader(this); 215 ResourceLoader::didFail(error); 216} 217 218void SubresourceLoader::didCancel(const ResourceError& error) 219{ 220 ASSERT(!reachedTerminalState()); 221 222 // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves. 223 RefPtr<SubresourceLoader> protect(this); 224 225 if (m_client) 226 m_client->didFail(this, error); 227 228 if (cancelled()) 229 return; 230 231 // The only way the subresource loader can reach the terminal state here is if the run loop spins when calling 232 // m_client->didFail. This should in theory not happen which is why the assert is here. 233 ASSERT(!reachedTerminalState()); 234 if (reachedTerminalState()) 235 return; 236 237 m_documentLoader->removeSubresourceLoader(this); 238 ResourceLoader::didCancel(error); 239} 240 241bool SubresourceLoader::shouldUseCredentialStorage() 242{ 243 RefPtr<SubresourceLoader> protect(this); 244 245 bool shouldUse; 246 if (m_client && m_client->getShouldUseCredentialStorage(this, shouldUse)) 247 return shouldUse; 248 249 return ResourceLoader::shouldUseCredentialStorage(); 250} 251 252void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) 253{ 254 RefPtr<SubresourceLoader> protect(this); 255 256 if (m_client) 257 m_client->didReceiveAuthenticationChallenge(this, challenge); 258 259 // The SubResourceLoaderClient may have cancelled this ResourceLoader in response to the challenge. 260 // If that's the case, don't call didReceiveAuthenticationChallenge 261 if (reachedTerminalState()) 262 return; 263 264 ResourceLoader::didReceiveAuthenticationChallenge(challenge); 265} 266 267void SubresourceLoader::receivedCancellation(const AuthenticationChallenge& challenge) 268{ 269 ASSERT(!reachedTerminalState()); 270 271 RefPtr<SubresourceLoader> protect(this); 272 273 if (m_client) 274 m_client->receivedCancellation(this, challenge); 275 276 ResourceLoader::receivedCancellation(challenge); 277} 278 279 280} 281