| OLD | NEW |
| (Empty) | |
| 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 "CachedResourceLoader.h" |
| 33 #include "Document.h" |
| 34 #include "DocumentLoader.h" |
| 35 #include "Frame.h" |
| 36 #include "FrameLoader.h" |
| 37 #include "Logging.h" |
| 38 #include "MemoryCache.h" |
| 39 #include "ResourceBuffer.h" |
| 40 #include "WebCoreMemoryInstrumentation.h" |
| 41 #include <wtf/RefCountedLeakCounter.h> |
| 42 #include <wtf/StdLibExtras.h> |
| 43 #include <wtf/text/CString.h> |
| 44 |
| 45 namespace WebCore { |
| 46 |
| 47 DEFINE_DEBUG_ONLY_GLOBAL(WTF::RefCountedLeakCounter, subresourceLoaderCounter, (
"SubresourceLoader")); |
| 48 |
| 49 SubresourceLoader::SubresourceLoader(Frame* frame, CachedResource* resource, con
st ResourceLoaderOptions& options) |
| 50 : ResourceLoader(frame, resource, options) |
| 51 { |
| 52 #ifndef NDEBUG |
| 53 subresourceLoaderCounter.increment(); |
| 54 #endif |
| 55 } |
| 56 |
| 57 SubresourceLoader::~SubresourceLoader() |
| 58 { |
| 59 ASSERT(m_state != Initialized); |
| 60 ASSERT(reachedTerminalState()); |
| 61 #ifndef NDEBUG |
| 62 subresourceLoaderCounter.decrement(); |
| 63 #endif |
| 64 } |
| 65 |
| 66 PassRefPtr<SubresourceLoader> SubresourceLoader::create(Frame* frame, CachedReso
urce* resource, const ResourceRequest& request, const ResourceLoaderOptions& opt
ions) |
| 67 { |
| 68 RefPtr<SubresourceLoader> subloader(adoptRef(new SubresourceLoader(frame, re
source, options))); |
| 69 if (!subloader->init(request)) |
| 70 return 0; |
| 71 return subloader.release(); |
| 72 } |
| 73 |
| 74 bool SubresourceLoader::init(const ResourceRequest& request) |
| 75 { |
| 76 if (!ResourceLoader::init(request)) |
| 77 return false; |
| 78 |
| 79 ASSERT(!reachedTerminalState()); |
| 80 m_state = Initialized; |
| 81 m_documentLoader->addSubresourceLoader(this); |
| 82 return true; |
| 83 } |
| 84 |
| 85 void SubresourceLoader::willSendRequest(ResourceRequest& newRequest, const Resou
rceResponse& redirectResponse) |
| 86 { |
| 87 // Store the previous URL because the call to ResourceLoader::willSendReques
t will modify it. |
| 88 KURL previousURL = request().url(); |
| 89 RefPtr<SubresourceLoader> protect(this); |
| 90 |
| 91 ASSERT(!newRequest.isNull()); |
| 92 if (!redirectResponse.isNull()) { |
| 93 if (!m_documentLoader->cachedResourceLoader()->canRequest(m_resource->ty
pe(), newRequest.url())) { |
| 94 cancel(); |
| 95 return; |
| 96 } |
| 97 if (m_resource->type() == CachedResource::ImageResource && m_documentLoa
der->cachedResourceLoader()->shouldDeferImageLoad(newRequest.url())) { |
| 98 cancel(); |
| 99 return; |
| 100 } |
| 101 m_resource->willSendRequest(newRequest, redirectResponse); |
| 102 } |
| 103 |
| 104 if (newRequest.isNull() || reachedTerminalState()) |
| 105 return; |
| 106 |
| 107 ResourceLoader::willSendRequest(newRequest, redirectResponse); |
| 108 if (newRequest.isNull()) |
| 109 cancel(); |
| 110 } |
| 111 |
| 112 void SubresourceLoader::didReceiveResponse(const ResourceResponse& response) |
| 113 { |
| 114 ASSERT(!response.isNull()); |
| 115 ASSERT(m_state == Initialized); |
| 116 |
| 117 // Reference the object in this method since the additional processing can d
o |
| 118 // anything including removing the last reference to this object; one exampl
e of this is 3266216. |
| 119 RefPtr<SubresourceLoader> protect(this); |
| 120 |
| 121 if (m_resource->resourceToRevalidate()) { |
| 122 if (response.httpStatusCode() == 304) { |
| 123 // 304 Not modified / Use local copy |
| 124 // Existing resource is ok, just use it updating the expiration time
. |
| 125 m_resource->setResponse(response); |
| 126 memoryCache()->revalidationSucceeded(m_resource, response); |
| 127 if (!reachedTerminalState()) |
| 128 ResourceLoader::didReceiveResponse(response); |
| 129 return; |
| 130 } |
| 131 // Did not get 304 response, continue as a regular resource load. |
| 132 memoryCache()->revalidationFailed(m_resource); |
| 133 } |
| 134 |
| 135 m_resource->responseReceived(response); |
| 136 if (reachedTerminalState()) |
| 137 return; |
| 138 ResourceLoader::didReceiveResponse(response); |
| 139 |
| 140 // FIXME: Main resources have a different set of rules for multipart than im
ages do. |
| 141 // Hopefully we can merge those 2 paths. |
| 142 if (response.isMultipart() && m_resource->type() != CachedResource::MainReso
urce) { |
| 143 m_loadingMultipartContent = true; |
| 144 |
| 145 // We don't count multiParts in a CachedResourceLoader's request count |
| 146 m_requestCountTracker.clear(); |
| 147 if (!m_resource->isImage()) { |
| 148 cancel(); |
| 149 return; |
| 150 } |
| 151 } |
| 152 |
| 153 RefPtr<ResourceBuffer> buffer = resourceData(); |
| 154 if (m_loadingMultipartContent && buffer && buffer->size()) { |
| 155 sendDataToResource(buffer->data(), buffer->size()); |
| 156 clearResourceData(); |
| 157 // Since a subresource loader does not load multipart sections progressi
vely, data was delivered to the loader all at once. |
| 158 // After the first multipart section is complete, signal to delegates th
at this load is "finished" |
| 159 m_documentLoader->subresourceLoaderFinishedLoadingOnePart(this); |
| 160 didFinishLoadingOnePart(0); |
| 161 } |
| 162 |
| 163 checkForHTTPStatusCodeError(); |
| 164 } |
| 165 |
| 166 bool SubresourceLoader::checkForHTTPStatusCodeError() |
| 167 { |
| 168 if (m_resource->response().httpStatusCode() < 400 || m_resource->shouldIgnor
eHTTPStatusCodeErrors()) |
| 169 return false; |
| 170 |
| 171 m_state = Finishing; |
| 172 m_resource->error(CachedResource::LoadError); |
| 173 cancel(); |
| 174 return true; |
| 175 } |
| 176 |
| 177 void SubresourceLoader::didReceiveCachedMetadata(const char* data, int length) |
| 178 { |
| 179 ASSERT(m_state == Initialized); |
| 180 ASSERT(!m_resource->resourceToRevalidate()); |
| 181 m_resource->setSerializedCachedMetadata(data, length); |
| 182 } |
| 183 |
| 184 void SubresourceLoader::didFinishLoading(double finishTime) |
| 185 { |
| 186 if (m_state != Initialized) |
| 187 return; |
| 188 ASSERT(!reachedTerminalState()); |
| 189 ASSERT(!m_resource->resourceToRevalidate()); |
| 190 ASSERT(!m_resource->errorOccurred()); |
| 191 LOG(ResourceLoading, "Received '%s'.", m_resource->url().string().latin1().d
ata()); |
| 192 |
| 193 RefPtr<SubresourceLoader> protect(this); |
| 194 CachedResourceHandle<CachedResource> protectResource(m_resource); |
| 195 m_state = Finishing; |
| 196 m_resource->setLoadFinishTime(finishTime); |
| 197 m_resource->data(resourceData(), true); |
| 198 m_resource->finish(); |
| 199 ResourceLoader::didFinishLoading(finishTime); |
| 200 } |
| 201 |
| 202 void SubresourceLoader::didFail(const ResourceError& error) |
| 203 { |
| 204 if (m_state != Initialized) |
| 205 return; |
| 206 ASSERT(!reachedTerminalState()); |
| 207 LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().string().la
tin1().data()); |
| 208 |
| 209 RefPtr<SubresourceLoader> protect(this); |
| 210 CachedResourceHandle<CachedResource> protectResource(m_resource); |
| 211 m_state = Finishing; |
| 212 if (m_resource->resourceToRevalidate()) |
| 213 memoryCache()->revalidationFailed(m_resource); |
| 214 m_resource->setResourceError(error); |
| 215 m_resource->error(CachedResource::LoadError); |
| 216 if (!m_resource->isPreloaded()) |
| 217 memoryCache()->remove(m_resource); |
| 218 ResourceLoader::didFail(error); |
| 219 } |
| 220 |
| 221 void SubresourceLoader::releaseResources() |
| 222 { |
| 223 ASSERT(!reachedTerminalState()); |
| 224 if (m_state != Uninitialized) { |
| 225 m_requestCountTracker.clear(); |
| 226 m_documentLoader->cachedResourceLoader()->loadDone(m_resource); |
| 227 if (reachedTerminalState()) |
| 228 return; |
| 229 m_resource->stopLoading(); |
| 230 m_documentLoader->removeSubresourceLoader(this); |
| 231 } |
| 232 ResourceLoader::releaseResources(); |
| 233 } |
| 234 |
| 235 } |
| OLD | NEW |