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 } 55 56 SubresourceLoader::~SubresourceLoader() 57 { 58 #ifndef NDEBUG 59 subresourceLoaderCounter.decrement(); 60 #endif 61 } 62 63 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, SubresourceLoaderClient* client, const ResourceRequest& request, SecurityCheckPolicy securityCheck, bool sendResourceLoadCallbacks, bool shouldContentSniff, const String& optionalOutgoingReferrer, bool shouldBufferData) 64 { 65 if (!frame) 66 return 0; 67 68 FrameLoader* fl = frame->loader(); 69 if (securityCheck == DoSecurityCheck && (fl->state() == FrameStateProvisional || !fl->activeDocumentLoader() || fl->activeDocumentLoader()->isStopping())) 70 return 0; 71 72 ResourceRequest newRequest = request; 73 74 if (securityCheck == DoSecurityCheck && !frame->document()->securityOrigin()->canDisplay(request.url())) { 75 FrameLoader::reportLocalLoadFailed(frame, request.url().string()); 76 return 0; 77 } 78 79 String outgoingReferrer; 80 String outgoingOrigin; 81 if (optionalOutgoingReferrer.isNull()) { 82 outgoingReferrer = fl->outgoingReferrer(); 83 outgoingOrigin = fl->outgoingOrigin(); 84 } else { 85 outgoingReferrer = optionalOutgoingReferrer; 86 outgoingOrigin = SecurityOrigin::createFromString(outgoingReferrer)->toString(); 87 } 88 89 if (SecurityOrigin::shouldHideReferrer(request.url(), outgoingReferrer)) 90 newRequest.clearHTTPReferrer(); 91 else if (!request.httpReferrer()) 92 newRequest.setHTTPReferrer(outgoingReferrer); 93 FrameLoader::addHTTPOriginIfNeeded(newRequest, outgoingOrigin); 94 95 fl->addExtraFieldsToSubresourceRequest(newRequest); 96 97 RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, client, sendResourceLoadCallbacks, shouldContentSniff))); 98 subloader->setShouldBufferData(shouldBufferData); 99 subloader->documentLoader()->addSubresourceLoader(subloader.get()); 100 if (!subloader->init(newRequest)) 101 return 0; 102 103 return subloader.release(); 104 } 105 106 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const ResourceResponse& redirectResponse) 107 { 108 // Store the previous URL because the call to ResourceLoader::willSendRequest will modify it. 109 KURL previousURL = request().url(); 110 111 ResourceLoader::willSendRequest(newRequest, redirectResponse); 112 if (!previousURL.isNull() && !newRequest.isNull() && previousURL != newRequest.url() && m_client) 113 m_client->willSendRequest(this, newRequest, redirectResponse); 114 } 115 116 void SubresourceLoader::didSendData(unsigned long long bytesSent, unsigned long long totalBytesToBeSent) 117 { 118 RefPtr<SubresourceLoader> protect(this); 119 120 if (m_client) 121 m_client->didSendData(this, bytesSent, totalBytesToBeSent); 122 } 123 124 void SubresourceLoader::didReceiveResponse(const ResourceResponse& r) 125 { 126 ASSERT(!r.isNull()); 127 128 if (r.isMultipart()) 129 m_loadingMultipartContent = true; 130 131 // Reference the object in this method since the additional processing can do 132 // anything including removing the last reference to this object; one example of this is 3266216. 133 RefPtr<SubresourceLoader> protect(this); 134 135 if (m_client) 136 m_client->didReceiveResponse(this, r); 137 138 // The loader can cancel a load if it receives a multipart response for a non-image 139 if (reachedTerminalState()) 140 return; 141 ResourceLoader::didReceiveResponse(r); 142 143 RefPtr<SharedBuffer> buffer = resourceData(); 144 if (m_loadingMultipartContent && buffer && buffer->size()) { 145 // Since a subresource loader does not load multipart sections progressively, 146 // deliver the previously received data to the loader all at once now. 147 // Then clear the data to make way for the next multipart section. 148 if (m_client) 149 m_client->didReceiveData(this, buffer->data(), buffer->size()); 150 clearResourceData(); 151 152 // After the first multipart section is complete, signal to delegates that this load is "finished" 153 m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this); 154 didFinishLoadingOnePart(0); 155 } 156 } 157 158 void SubresourceLoader::didReceiveData(const char* data, int length, long long encodedDataLength, bool allAtOnce) 159 { 160 // Reference the object in this method since the additional processing can do 161 // anything including removing the last reference to this object; one example of this is 3266216. 162 RefPtr<SubresourceLoader> protect(this); 163 164 ResourceLoader::didReceiveData(data, length, encodedDataLength, allAtOnce); 165 166 // A subresource loader does not load multipart sections progressively. 167 // So don't deliver any data to the loader yet. 168 if (!m_loadingMultipartContent && m_client) 169 m_client->didReceiveData(this, data, length); 170 } 171 172 void SubresourceLoader::didReceiveCachedMetadata(const char* data, int length) 173 { 174 // Reference the object in this method since the additional processing can do 175 // anything including removing the last reference to this object; one example of this is 3266216. 176 RefPtr<SubresourceLoader> protect(this); 177 178 if (m_client) 179 m_client->didReceiveCachedMetadata(this, data, length); 180 } 181 182 void SubresourceLoader::didFinishLoading(double finishTime) 183 { 184 if (cancelled()) 185 return; 186 ASSERT(!reachedTerminalState()); 187 188 // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves. 189 RefPtr<SubresourceLoader> protect(this); 190 191 if (m_client) 192 m_client->didFinishLoading(this, finishTime); 193 194 m_handle = 0; 195 196 if (cancelled()) 197 return; 198 m_documentLoader->removeSubresourceLoader(this); 199 ResourceLoader::didFinishLoading(finishTime); 200 } 201 202 void SubresourceLoader::didFail(const ResourceError& error) 203 { 204 if (cancelled()) 205 return; 206 ASSERT(!reachedTerminalState()); 207 208 // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves. 209 RefPtr<SubresourceLoader> protect(this); 210 211 if (m_client) 212 m_client->didFail(this, error); 213 214 m_handle = 0; 215 216 if (cancelled()) 217 return; 218 m_documentLoader->removeSubresourceLoader(this); 219 ResourceLoader::didFail(error); 220 } 221 222 void SubresourceLoader::didCancel(const ResourceError& error) 223 { 224 ASSERT(!reachedTerminalState()); 225 226 // Calling removeSubresourceLoader will likely result in a call to deref, so we must protect ourselves. 227 RefPtr<SubresourceLoader> protect(this); 228 229 if (m_client) 230 m_client->didFail(this, error); 231 232 if (cancelled()) 233 return; 234 235 // The only way the subresource loader can reach the terminal state here is if the run loop spins when calling 236 // m_client->didFail. This should in theory not happen which is why the assert is here. 237 ASSERT(!reachedTerminalState()); 238 if (reachedTerminalState()) 239 return; 240 241 m_documentLoader->removeSubresourceLoader(this); 242 ResourceLoader::didCancel(error); 243 } 244 245 bool SubresourceLoader::shouldUseCredentialStorage() 246 { 247 RefPtr<SubresourceLoader> protect(this); 248 249 bool shouldUse; 250 if (m_client && m_client->getShouldUseCredentialStorage(this, shouldUse)) 251 return shouldUse; 252 253 return ResourceLoader::shouldUseCredentialStorage(); 254 } 255 256 void SubresourceLoader::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge) 257 { 258 RefPtr<SubresourceLoader> protect(this); 259 260 ASSERT(handle()->hasAuthenticationChallenge()); 261 262 if (m_client) 263 m_client->didReceiveAuthenticationChallenge(this, challenge); 264 265 // The SubResourceLoaderClient may have cancelled this ResourceLoader in response to the challenge. 266 // If that's the case, don't call didReceiveAuthenticationChallenge. 267 if (reachedTerminalState()) 268 return; 269 270 // It may have also handled authentication on its own. 271 if (!handle()->hasAuthenticationChallenge()) 272 return; 273 274 ResourceLoader::didReceiveAuthenticationChallenge(challenge); 275 } 276 277 void SubresourceLoader::receivedCancellation(const AuthenticationChallenge& challenge) 278 { 279 ASSERT(!reachedTerminalState()); 280 281 RefPtr<SubresourceLoader> protect(this); 282 283 if (m_client) 284 m_client->receivedCancellation(this, challenge); 285 286 ResourceLoader::receivedCancellation(challenge); 287 } 288 289 290 } 291