Fixes <http://webkit.org/b/31260>.
[webbrowser.git] / WebCore / inspector / InspectorResource.cpp
blobfe1522e3c43b753ead2fb9035951168d4046576d
1 /*
2 * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4 * Copyright (C) 2009 Google Inc. All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
16 * its contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
20 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "config.h"
32 #include "InspectorResource.h"
34 #if ENABLE(INSPECTOR)
36 #include "Cache.h"
37 #include "CachedResource.h"
38 #include "DocLoader.h"
39 #include "DocumentLoader.h"
40 #include "Frame.h"
41 #include "InspectorFrontend.h"
42 #include "ResourceRequest.h"
43 #include "ResourceResponse.h"
44 #include "TextEncoding.h"
45 #include "ScriptObject.h"
47 namespace WebCore {
49 InspectorResource::InspectorResource(long long identifier, DocumentLoader* loader)
50 : m_identifier(identifier)
51 , m_loader(loader)
52 , m_frame(loader->frame())
53 , m_scriptObjectCreated(false)
54 , m_expectedContentLength(0)
55 , m_cached(false)
56 , m_finished(false)
57 , m_failed(false)
58 , m_length(0)
59 , m_responseStatusCode(0)
60 , m_startTime(-1.0)
61 , m_responseReceivedTime(-1.0)
62 , m_endTime(-1.0)
63 , m_loadEventTime(-1.0)
64 , m_domContentEventTime(-1.0)
65 , m_isMainResource(false)
69 InspectorResource::~InspectorResource()
73 PassRefPtr<InspectorResource> InspectorResource::createCached(long long identifier, DocumentLoader* loader, const CachedResource* cachedResource)
75 PassRefPtr<InspectorResource> resource = create(identifier, loader);
77 resource->m_finished = true;
79 resource->m_requestURL = KURL(ParsedURLString, cachedResource->url());
80 resource->updateResponse(cachedResource->response());
82 resource->m_length = cachedResource->encodedSize();
83 resource->m_cached = true;
84 resource->m_startTime = currentTime();
85 resource->m_responseReceivedTime = resource->m_startTime;
86 resource->m_endTime = resource->m_startTime;
88 resource->m_changes.setAll();
90 return resource;
93 void InspectorResource::updateRequest(const ResourceRequest& request)
95 m_requestHeaderFields = request.httpHeaderFields();
96 m_requestURL = request.url();
97 m_requestMethod = request.httpMethod();
98 if (request.httpBody() && !request.httpBody()->isEmpty())
99 m_requestFormData = request.httpBody()->flattenToString();
101 m_changes.set(RequestChange);
104 void InspectorResource::updateResponse(const ResourceResponse& response)
106 m_expectedContentLength = response.expectedContentLength();
107 m_mimeType = response.mimeType();
108 m_responseHeaderFields = response.httpHeaderFields();
109 m_responseStatusCode = response.httpStatusCode();
110 m_suggestedFilename = response.suggestedFilename();
112 m_changes.set(ResponseChange);
113 m_changes.set(TypeChange);
116 static void populateHeadersObject(ScriptObject* object, const HTTPHeaderMap& headers)
118 HTTPHeaderMap::const_iterator end = headers.end();
119 for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
120 object->set(it->first.string(), it->second);
124 void InspectorResource::createScriptObject(InspectorFrontend* frontend)
126 if (!m_scriptObjectCreated) {
127 ScriptObject jsonObject = frontend->newScriptObject();
128 ScriptObject requestHeaders = frontend->newScriptObject();
129 populateHeadersObject(&requestHeaders, m_requestHeaderFields);
130 jsonObject.set("requestHeaders", requestHeaders);
131 jsonObject.set("requestURL", requestURL());
132 jsonObject.set("host", m_requestURL.host());
133 jsonObject.set("path", m_requestURL.path());
134 jsonObject.set("lastPathComponent", m_requestURL.lastPathComponent());
135 jsonObject.set("isMainResource", m_isMainResource);
136 jsonObject.set("cached", m_cached);
137 jsonObject.set("requestMethod", m_requestMethod);
138 jsonObject.set("requestFormData", m_requestFormData);
139 if (!frontend->addResource(m_identifier, jsonObject))
140 return;
142 m_scriptObjectCreated = true;
143 m_changes.clear(RequestChange);
145 updateScriptObject(frontend);
148 void InspectorResource::updateScriptObject(InspectorFrontend* frontend)
150 if (!m_scriptObjectCreated)
151 return;
153 if (m_changes.hasChange(NoChange))
154 return;
156 ScriptObject jsonObject = frontend->newScriptObject();
157 if (m_changes.hasChange(RequestChange)) {
158 jsonObject.set("url", requestURL());
159 jsonObject.set("domain", m_requestURL.host());
160 jsonObject.set("path", m_requestURL.path());
161 jsonObject.set("lastPathComponent", m_requestURL.lastPathComponent());
162 ScriptObject requestHeaders = frontend->newScriptObject();
163 populateHeadersObject(&requestHeaders, m_requestHeaderFields);
164 jsonObject.set("requestHeaders", requestHeaders);
165 jsonObject.set("mainResource", m_isMainResource);
166 jsonObject.set("requestMethod", m_requestMethod);
167 jsonObject.set("requestFormData", m_requestFormData);
168 jsonObject.set("didRequestChange", true);
171 if (m_changes.hasChange(ResponseChange)) {
172 jsonObject.set("mimeType", m_mimeType);
173 jsonObject.set("suggestedFilename", m_suggestedFilename);
174 jsonObject.set("expectedContentLength", m_expectedContentLength);
175 jsonObject.set("statusCode", m_responseStatusCode);
176 jsonObject.set("suggestedFilename", m_suggestedFilename);
177 ScriptObject responseHeaders = frontend->newScriptObject();
178 populateHeadersObject(&responseHeaders, m_responseHeaderFields);
179 jsonObject.set("responseHeaders", responseHeaders);
180 jsonObject.set("didResponseChange", true);
183 if (m_changes.hasChange(TypeChange)) {
184 jsonObject.set("type", static_cast<int>(type()));
185 jsonObject.set("didTypeChange", true);
188 if (m_changes.hasChange(LengthChange)) {
189 jsonObject.set("contentLength", m_length);
190 jsonObject.set("didLengthChange", true);
193 if (m_changes.hasChange(CompletionChange)) {
194 jsonObject.set("failed", m_failed);
195 jsonObject.set("finished", m_finished);
196 jsonObject.set("didCompletionChange", true);
199 if (m_changes.hasChange(TimingChange)) {
200 if (m_startTime > 0)
201 jsonObject.set("startTime", m_startTime);
202 if (m_responseReceivedTime > 0)
203 jsonObject.set("responseReceivedTime", m_responseReceivedTime);
204 if (m_endTime > 0)
205 jsonObject.set("endTime", m_endTime);
206 if (m_loadEventTime > 0)
207 jsonObject.set("loadEventTime", m_loadEventTime);
208 if (m_domContentEventTime > 0)
209 jsonObject.set("domContentEventTime", m_domContentEventTime);
210 jsonObject.set("didTimingChange", true);
212 if (!frontend->updateResource(m_identifier, jsonObject))
213 return;
214 m_changes.clearAll();
217 void InspectorResource::releaseScriptObject(InspectorFrontend* frontend, bool callRemoveResource)
219 if (!m_scriptObjectCreated)
220 return;
222 m_scriptObjectCreated = false;
223 m_changes.setAll();
225 if (!callRemoveResource)
226 return;
228 frontend->removeResource(m_identifier);
231 CachedResource* InspectorResource::cachedResource() const
233 // Try hard to find a corresponding CachedResource. During preloading, DocLoader may not have the resource in document resources set yet,
234 // but Inspector will already try to fetch data that is only available via CachedResource (and it won't update once the resource is added,
235 // because m_changes will not have the appropriate bits set).
236 const String& url = requestURL();
237 CachedResource* cachedResource = m_frame->document()->docLoader()->cachedResource(url);
238 if (!cachedResource)
239 cachedResource = cache()->resourceForURL(url);
240 return cachedResource;
243 InspectorResource::Type InspectorResource::cachedResourceType() const
245 CachedResource* cachedResource = this->cachedResource();
247 if (!cachedResource)
248 return Other;
250 switch (cachedResource->type()) {
251 case CachedResource::ImageResource:
252 return Image;
253 case CachedResource::FontResource:
254 return Font;
255 case CachedResource::CSSStyleSheet:
256 #if ENABLE(XSLT)
257 case CachedResource::XSLStyleSheet:
258 #endif
259 return Stylesheet;
260 case CachedResource::Script:
261 return Script;
262 default:
263 return Other;
267 InspectorResource::Type InspectorResource::type() const
269 if (!m_xmlHttpResponseText.isNull())
270 return XHR;
272 if (m_requestURL == m_loader->requestURL()) {
273 InspectorResource::Type resourceType = cachedResourceType();
274 if (resourceType == Other)
275 return Doc;
277 return resourceType;
280 if (m_loader->frameLoader() && m_requestURL == m_loader->frameLoader()->iconURL())
281 return Image;
283 return cachedResourceType();
287 void InspectorResource::setXMLHttpResponseText(const ScriptString& data)
289 m_xmlHttpResponseText = data;
290 m_changes.set(TypeChange);
293 String InspectorResource::sourceString() const
295 if (!m_xmlHttpResponseText.isNull())
296 return String(m_xmlHttpResponseText);
298 String textEncodingName;
299 RefPtr<SharedBuffer> buffer = resourceData(&textEncodingName);
300 if (!buffer)
301 return String();
303 TextEncoding encoding(textEncodingName);
304 if (!encoding.isValid())
305 encoding = WindowsLatin1Encoding();
306 return encoding.decode(buffer->data(), buffer->size());
309 PassRefPtr<SharedBuffer> InspectorResource::resourceData(String* textEncodingName) const
311 if (m_requestURL == m_loader->requestURL()) {
312 *textEncodingName = m_frame->document()->inputEncoding();
313 return m_loader->mainResourceData();
316 CachedResource* cachedResource = this->cachedResource();
317 if (!cachedResource)
318 return 0;
320 if (cachedResource->isPurgeable()) {
321 // If the resource is purgeable then make it unpurgeable to get
322 // get its data. This might fail, in which case we return an
323 // empty String.
324 // FIXME: should we do something else in the case of a purged
325 // resource that informs the user why there is no data in the
326 // inspector?
327 if (!cachedResource->makePurgeable(false))
328 return 0;
331 *textEncodingName = cachedResource->encoding();
332 return cachedResource->data();
335 void InspectorResource::startTiming()
337 m_startTime = currentTime();
338 m_changes.set(TimingChange);
341 void InspectorResource::markResponseReceivedTime()
343 m_responseReceivedTime = currentTime();
344 m_changes.set(TimingChange);
347 void InspectorResource::endTiming()
349 m_endTime = currentTime();
350 m_finished = true;
351 m_changes.set(TimingChange);
352 m_changes.set(CompletionChange);
355 void InspectorResource::markDOMContentEventTime()
357 m_domContentEventTime = currentTime();
358 m_changes.set(TimingChange);
361 void InspectorResource::markLoadEventTime()
363 m_loadEventTime = currentTime();
364 m_changes.set(TimingChange);
367 void InspectorResource::markFailed()
369 m_failed = true;
370 m_changes.set(CompletionChange);
373 void InspectorResource::addLength(int lengthReceived)
375 m_length += lengthReceived;
376 m_changes.set(LengthChange);
379 } // namespace WebCore
381 #endif // ENABLE(INSPECTOR)