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 40 namespace WebCore { 41 42 #ifndef NDEBUG 43 static WTF::RefCountedLeakCounter subresourceLoaderCounter("SubresourceLoader"); 44 #endif 45 46 SubresourceLoader::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 57 SubresourceLoader::~SubresourceLoader() 58 { 59 #ifndef NDEBUG 60 subresourceLoaderCounter.decrement(); 61 #endif 62 } 63 64 PassRefPtr<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 112 void 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 122 void 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 130 void 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 164 void 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 178 void 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 198 void 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 218 void 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 241 bool 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 252 void 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 267 void 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