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