• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
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.
18  *
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.
29  */
30 
31 #include "config.h"
32 #include "InspectorResource.h"
33 
34 #include "CachedResource.h"
35 #include "DocLoader.h"
36 #include "DocumentLoader.h"
37 #include "Frame.h"
38 #include "InspectorFrontend.h"
39 #include "ResourceRequest.h"
40 #include "ResourceResponse.h"
41 #include "TextEncoding.h"
42 #include "ScriptObject.h"
43 
44 namespace WebCore {
45 
InspectorResource(long long identifier,DocumentLoader * loader)46 InspectorResource::InspectorResource(long long identifier, DocumentLoader* loader)
47     : m_identifier(identifier)
48     , m_loader(loader)
49     , m_frame(loader->frame())
50     , m_scriptObjectCreated(false)
51     , m_expectedContentLength(0)
52     , m_cached(false)
53     , m_finished(false)
54     , m_failed(false)
55     , m_length(0)
56     , m_responseStatusCode(0)
57     , m_startTime(-1.0)
58     , m_responseReceivedTime(-1.0)
59     , m_endTime(-1.0)
60     , m_isMainResource(false)
61 {
62 }
63 
~InspectorResource()64 InspectorResource::~InspectorResource()
65 {
66 }
67 
createCached(long long identifier,DocumentLoader * loader,const CachedResource * cachedResource)68 PassRefPtr<InspectorResource> InspectorResource::createCached(long long identifier, DocumentLoader* loader, const CachedResource* cachedResource)
69 {
70     PassRefPtr<InspectorResource> resource = create(identifier, loader);
71 
72     resource->m_finished = true;
73 
74     resource->m_requestURL = KURL(cachedResource->url());
75     resource->updateResponse(cachedResource->response());
76 
77     resource->m_length = cachedResource->encodedSize();
78     resource->m_cached = true;
79     resource->m_startTime = currentTime();
80     resource->m_responseReceivedTime = resource->m_startTime;
81     resource->m_endTime = resource->m_startTime;
82 
83     resource->m_changes.setAll();
84 
85     return resource;
86 }
87 
updateRequest(const ResourceRequest & request)88 void InspectorResource::updateRequest(const ResourceRequest& request)
89 {
90     m_requestHeaderFields = request.httpHeaderFields();
91     m_requestURL = request.url();
92 
93     m_changes.set(RequestChange);
94 }
95 
updateResponse(const ResourceResponse & response)96 void InspectorResource::updateResponse(const ResourceResponse& response)
97 {
98     m_expectedContentLength = response.expectedContentLength();
99     m_mimeType = response.mimeType();
100     m_responseHeaderFields = response.httpHeaderFields();
101     m_responseStatusCode = response.httpStatusCode();
102     m_suggestedFilename = response.suggestedFilename();
103 
104     m_changes.set(ResponseChange);
105     m_changes.set(TypeChange);
106 }
107 
populateHeadersObject(ScriptObject * object,const HTTPHeaderMap & headers)108 static void populateHeadersObject(ScriptObject* object, const HTTPHeaderMap& headers)
109 {
110     HTTPHeaderMap::const_iterator end = headers.end();
111     for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) {
112         object->set(it->first.string(), it->second);
113     }
114 }
115 
createScriptObject(InspectorFrontend * frontend)116 void InspectorResource::createScriptObject(InspectorFrontend* frontend)
117 {
118     if (!m_scriptObjectCreated) {
119         ScriptObject jsonObject = frontend->newScriptObject();
120         ScriptObject requestHeaders = frontend->newScriptObject();
121         populateHeadersObject(&requestHeaders, m_requestHeaderFields);
122         jsonObject.set("requestHeaders", requestHeaders);
123         jsonObject.set("requestURL", requestURL());
124         jsonObject.set("host", m_requestURL.host());
125         jsonObject.set("path", m_requestURL.path());
126         jsonObject.set("lastPathComponent", m_requestURL.lastPathComponent());
127         jsonObject.set("isMainResource", m_isMainResource);
128         jsonObject.set("cached", m_cached);
129         if (!frontend->addResource(m_identifier, jsonObject))
130             return;
131 
132         m_scriptObjectCreated = true;
133         m_changes.clear(RequestChange);
134     }
135     updateScriptObject(frontend);
136 }
137 
updateScriptObject(InspectorFrontend * frontend)138 void InspectorResource::updateScriptObject(InspectorFrontend* frontend)
139 {
140     if (!m_scriptObjectCreated)
141         return;
142 
143     if (m_changes.hasChange(NoChange))
144         return;
145 
146     ScriptObject jsonObject = frontend->newScriptObject();
147     if (m_changes.hasChange(RequestChange)) {
148         jsonObject.set("url", requestURL());
149         jsonObject.set("domain", m_requestURL.host());
150         jsonObject.set("path", m_requestURL.path());
151         jsonObject.set("lastPathComponent", m_requestURL.lastPathComponent());
152         ScriptObject requestHeaders = frontend->newScriptObject();
153         populateHeadersObject(&requestHeaders, m_requestHeaderFields);
154         jsonObject.set("requestHeaders", requestHeaders);
155         jsonObject.set("mainResource", m_isMainResource);
156         jsonObject.set("didRequestChange", true);
157     }
158 
159     if (m_changes.hasChange(ResponseChange)) {
160         jsonObject.set("mimeType", m_mimeType);
161         jsonObject.set("suggestedFilename", m_suggestedFilename);
162         jsonObject.set("expectedContentLength", m_expectedContentLength);
163         jsonObject.set("statusCode", m_responseStatusCode);
164         jsonObject.set("suggestedFilename", m_suggestedFilename);
165         ScriptObject responseHeaders = frontend->newScriptObject();
166         populateHeadersObject(&responseHeaders, m_responseHeaderFields);
167         jsonObject.set("responseHeaders", responseHeaders);
168         jsonObject.set("didResponseChange", true);
169     }
170 
171     if (m_changes.hasChange(TypeChange)) {
172         jsonObject.set("type", static_cast<int>(type()));
173         jsonObject.set("didTypeChange", true);
174     }
175 
176     if (m_changes.hasChange(LengthChange)) {
177         jsonObject.set("contentLength", m_length);
178         jsonObject.set("didLengthChange", true);
179     }
180 
181     if (m_changes.hasChange(CompletionChange)) {
182         jsonObject.set("failed", m_failed);
183         jsonObject.set("finished", m_finished);
184         jsonObject.set("didCompletionChange", true);
185     }
186 
187     if (m_changes.hasChange(TimingChange)) {
188         if (m_startTime > 0)
189             jsonObject.set("startTime", m_startTime);
190         if (m_responseReceivedTime > 0)
191             jsonObject.set("responseReceivedTime", m_responseReceivedTime);
192         if (m_endTime > 0)
193             jsonObject.set("endTime", m_endTime);
194         jsonObject.set("didTimingChange", true);
195     }
196     if (!frontend->updateResource(m_identifier, jsonObject))
197         return;
198     m_changes.clearAll();
199 }
200 
releaseScriptObject(InspectorFrontend * frontend,bool callRemoveResource)201 void InspectorResource::releaseScriptObject(InspectorFrontend* frontend, bool callRemoveResource)
202 {
203     if (!m_scriptObjectCreated)
204         return;
205 
206     m_scriptObjectCreated = false;
207     m_changes.setAll();
208 
209     if (!callRemoveResource)
210         return;
211 
212     frontend->removeResource(m_identifier);
213 }
214 
type() const215 InspectorResource::Type InspectorResource::type() const
216 {
217     if (!m_xmlHttpResponseText.isNull())
218         return XHR;
219 
220     if (m_requestURL == m_loader->requestURL())
221         return Doc;
222 
223     if (m_loader->frameLoader() && m_requestURL == m_loader->frameLoader()->iconURL())
224         return Image;
225 
226     CachedResource* cachedResource = m_frame->document()->docLoader()->cachedResource(requestURL());
227     if (!cachedResource)
228         return Other;
229 
230     switch (cachedResource->type()) {
231         case CachedResource::ImageResource:
232             return Image;
233         case CachedResource::FontResource:
234             return Font;
235         case CachedResource::CSSStyleSheet:
236 #if ENABLE(XSLT)
237         case CachedResource::XSLStyleSheet:
238 #endif
239             return Stylesheet;
240         case CachedResource::Script:
241             return Script;
242         default:
243             return Other;
244     }
245 }
246 
setXMLHttpResponseText(const ScriptString & data)247 void InspectorResource::setXMLHttpResponseText(const ScriptString& data)
248 {
249     m_xmlHttpResponseText = data;
250     m_changes.set(TypeChange);
251 }
252 
sourceString() const253 String InspectorResource::sourceString() const
254 {
255     if (!m_xmlHttpResponseText.isNull())
256         return String(m_xmlHttpResponseText);
257 
258     RefPtr<SharedBuffer> buffer;
259     String textEncodingName;
260 
261     if (m_requestURL == m_loader->requestURL()) {
262         buffer = m_loader->mainResourceData();
263         textEncodingName = m_frame->document()->inputEncoding();
264     } else {
265         CachedResource* cachedResource = m_frame->document()->docLoader()->cachedResource(requestURL());
266         if (!cachedResource)
267             return String();
268 
269         if (cachedResource->isPurgeable()) {
270             // If the resource is purgeable then make it unpurgeable to get
271             // get its data. This might fail, in which case we return an
272             // empty String.
273             // FIXME: should we do something else in the case of a purged
274             // resource that informs the user why there is no data in the
275             // inspector?
276             if (!cachedResource->makePurgeable(false))
277                 return String();
278         }
279 
280         buffer = cachedResource->data();
281         textEncodingName = cachedResource->encoding();
282     }
283 
284     if (!buffer)
285         return String();
286 
287     TextEncoding encoding(textEncodingName);
288     if (!encoding.isValid())
289         encoding = WindowsLatin1Encoding();
290     return encoding.decode(buffer->data(), buffer->size());
291 }
292 
startTiming()293 void InspectorResource::startTiming()
294 {
295     m_startTime = currentTime();
296     m_changes.set(TimingChange);
297 }
298 
markResponseReceivedTime()299 void InspectorResource::markResponseReceivedTime()
300 {
301     m_responseReceivedTime = currentTime();
302     m_changes.set(TimingChange);
303 }
304 
endTiming()305 void InspectorResource::endTiming()
306 {
307     m_endTime = currentTime();
308     m_finished = true;
309     m_changes.set(TimingChange);
310     m_changes.set(CompletionChange);
311 }
312 
markFailed()313 void InspectorResource::markFailed()
314 {
315     m_failed = true;
316     m_changes.set(CompletionChange);
317 }
318 
addLength(int lengthReceived)319 void InspectorResource::addLength(int lengthReceived)
320 {
321     m_length += lengthReceived;
322     m_changes.set(LengthChange);
323 }
324 
325 } // namespace WebCore
326