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
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.
32 #include "InspectorResource.h"
37 #include "CachedResource.h"
38 #include "DocLoader.h"
39 #include "DocumentLoader.h"
41 #include "InspectorFrontend.h"
42 #include "ResourceRequest.h"
43 #include "ResourceResponse.h"
44 #include "TextEncoding.h"
45 #include "ScriptObject.h"
49 InspectorResource::InspectorResource(long long identifier
, DocumentLoader
* loader
)
50 : m_identifier(identifier
)
52 , m_frame(loader
->frame())
53 , m_scriptObjectCreated(false)
54 , m_expectedContentLength(0)
59 , m_responseStatusCode(0)
61 , m_responseReceivedTime(-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();
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
))
142 m_scriptObjectCreated
= true;
143 m_changes
.clear(RequestChange
);
145 updateScriptObject(frontend
);
148 void InspectorResource::updateScriptObject(InspectorFrontend
* frontend
)
150 if (!m_scriptObjectCreated
)
153 if (m_changes
.hasChange(NoChange
))
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
)) {
201 jsonObject
.set("startTime", m_startTime
);
202 if (m_responseReceivedTime
> 0)
203 jsonObject
.set("responseReceivedTime", m_responseReceivedTime
);
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
))
214 m_changes
.clearAll();
217 void InspectorResource::releaseScriptObject(InspectorFrontend
* frontend
, bool callRemoveResource
)
219 if (!m_scriptObjectCreated
)
222 m_scriptObjectCreated
= false;
225 if (!callRemoveResource
)
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
);
239 cachedResource
= cache()->resourceForURL(url
);
240 return cachedResource
;
243 InspectorResource::Type
InspectorResource::cachedResourceType() const
245 CachedResource
* cachedResource
= this->cachedResource();
250 switch (cachedResource
->type()) {
251 case CachedResource::ImageResource
:
253 case CachedResource::FontResource
:
255 case CachedResource::CSSStyleSheet
:
257 case CachedResource::XSLStyleSheet
:
260 case CachedResource::Script
:
267 InspectorResource::Type
InspectorResource::type() const
269 if (!m_xmlHttpResponseText
.isNull())
272 if (m_requestURL
== m_loader
->requestURL()) {
273 InspectorResource::Type resourceType
= cachedResourceType();
274 if (resourceType
== Other
)
280 if (m_loader
->frameLoader() && m_requestURL
== m_loader
->frameLoader()->iconURL())
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
);
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();
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
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
327 if (!cachedResource
->makePurgeable(false))
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();
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()
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)