1 /* 2 * Copyright (C) 2011 Google 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 are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "InspectorResourceAgent.h" 33 34 #if ENABLE(INSPECTOR) 35 36 #include "Base64.h" 37 #include "CachedResource.h" 38 #include "CachedResourceLoader.h" 39 #include "Document.h" 40 #include "DocumentLoader.h" 41 #include "EventsCollector.h" 42 #include "Frame.h" 43 #include "FrameLoader.h" 44 #include "HTMLFrameOwnerElement.h" 45 #include "HTMLNames.h" 46 #include "HTTPHeaderMap.h" 47 #include "InspectorFrontend.h" 48 #include "InspectorFrontendChannel.h" 49 #include "InspectorFrontendProxy.h" 50 #include "InspectorState.h" 51 #include "InspectorValues.h" 52 #include "InstrumentingAgents.h" 53 #include "KURL.h" 54 #include "MemoryCache.h" 55 #include "Page.h" 56 #include "ProgressTracker.h" 57 #include "ResourceError.h" 58 #include "ResourceRequest.h" 59 #include "ResourceResponse.h" 60 #include "ScriptCallStack.h" 61 #include "ScriptCallStackFactory.h" 62 #include "SharedBuffer.h" 63 #include "TextEncoding.h" 64 #include "WebSocketHandshakeRequest.h" 65 #include "WebSocketHandshakeResponse.h" 66 67 #include <wtf/CurrentTime.h> 68 #include <wtf/HexNumber.h> 69 #include <wtf/ListHashSet.h> 70 #include <wtf/RefPtr.h> 71 #include <wtf/text/StringBuilder.h> 72 73 namespace WebCore { 74 75 namespace ResourceAgentState { 76 static const char resourceAgentEnabled[] = "resourceAgentEnabled"; 77 static const char extraRequestHeaders[] = "extraRequestHeaders"; 78 } 79 80 namespace ResourceType { 81 static const char document[] = "Document"; 82 static const char stylesheet[] = "Stylesheet"; 83 static const char image[] = "Image"; 84 static const char font[] = "Font"; 85 static const char script[] = "Script"; 86 static const char xhr[] = "XHR"; 87 static const char websocket[] = "WebSocket"; 88 static const char other[] = "Other"; 89 } 90 91 void InspectorResourceAgent::setFrontend(InspectorFrontend* frontend) 92 { 93 m_frontend = frontend->network(); 94 if (backgroundEventsCollectionEnabled()) { 95 // Insert Message Proxy in receiver chain. 96 InspectorFrontendChannel* client = m_frontend->getInspectorFrontendChannel(); 97 m_inspectorFrontendProxy->setInspectorFrontendChannel(client); 98 m_frontend->setInspectorFrontendChannel(m_inspectorFrontendProxy.get()); 99 m_eventsCollector->sendCollectedEvents(client); 100 } 101 } 102 103 void InspectorResourceAgent::clearFrontend() 104 { 105 if (backgroundEventsCollectionEnabled()) { 106 m_inspectorFrontendProxy->setInspectorFrontendChannel(0); 107 m_frontend = m_mockFrontend.get(); 108 } else 109 m_frontend = 0; 110 disable(0); 111 } 112 113 void InspectorResourceAgent::restore() 114 { 115 if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled)) 116 enable(); 117 } 118 119 void InspectorResourceAgent::resourceContent(ErrorString* errorString, Frame* frame, const KURL& url, String* result) 120 { 121 if (!frame) { 122 *errorString = "No frame to get resource content for"; 123 return; 124 } 125 126 String textEncodingName; 127 RefPtr<SharedBuffer> buffer = InspectorResourceAgent::resourceData(frame, url, &textEncodingName); 128 129 if (buffer) { 130 TextEncoding encoding(textEncodingName); 131 if (!encoding.isValid()) 132 encoding = WindowsLatin1Encoding(); 133 *result = encoding.decode(buffer->data(), buffer->size()); 134 return; 135 } 136 *errorString = "No resource with given URL found"; 137 } 138 139 void InspectorResourceAgent::resourceContentBase64(ErrorString* errorString, Frame* frame, const KURL& url, String* result) 140 { 141 String textEncodingName; 142 RefPtr<SharedBuffer> data = InspectorResourceAgent::resourceData(frame, url, &textEncodingName); 143 if (!data) { 144 *result = String(); 145 *errorString = "No resource with given URL found"; 146 return; 147 } 148 149 *result = base64Encode(data->data(), data->size()); 150 } 151 152 PassRefPtr<SharedBuffer> InspectorResourceAgent::resourceData(Frame* frame, const KURL& url, String* textEncodingName) 153 { 154 FrameLoader* frameLoader = frame->loader(); 155 DocumentLoader* loader = frameLoader->documentLoader(); 156 if (equalIgnoringFragmentIdentifier(url, loader->url())) { 157 *textEncodingName = frame->document()->inputEncoding(); 158 return frameLoader->documentLoader()->mainResourceData(); 159 } 160 161 CachedResource* cachedResource = InspectorResourceAgent::cachedResource(frame, url); 162 if (!cachedResource) 163 return 0; 164 165 // Zero-sized resources don't have data at all -- so fake the empty buffer, insted of indicating error by returning 0. 166 if (!cachedResource->encodedSize()) 167 return SharedBuffer::create(); 168 169 if (cachedResource->isPurgeable()) { 170 // If the resource is purgeable then make it unpurgeable to get 171 // get its data. This might fail, in which case we return an 172 // empty String. 173 // FIXME: should we do something else in the case of a purged 174 // resource that informs the user why there is no data in the 175 // inspector? 176 if (!cachedResource->makePurgeable(false)) 177 return 0; 178 } 179 180 *textEncodingName = cachedResource->encoding(); 181 return cachedResource->data(); 182 } 183 184 CachedResource* InspectorResourceAgent::cachedResource(Frame* frame, const KURL& url) 185 { 186 CachedResource* cachedResource = frame->document()->cachedResourceLoader()->cachedResource(url); 187 if (!cachedResource) 188 cachedResource = memoryCache()->resourceForURL(url); 189 return cachedResource; 190 } 191 192 static PassRefPtr<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers) 193 { 194 RefPtr<InspectorObject> headersObject = InspectorObject::create(); 195 HTTPHeaderMap::const_iterator end = headers.end(); 196 for (HTTPHeaderMap::const_iterator it = headers.begin(); it != end; ++it) 197 headersObject->setString(it->first.string(), it->second); 198 return headersObject; 199 } 200 201 static PassRefPtr<InspectorObject> buildObjectForTiming(const ResourceLoadTiming& timing) 202 { 203 RefPtr<InspectorObject> timingObject = InspectorObject::create(); 204 timingObject->setNumber("requestTime", timing.requestTime); 205 timingObject->setNumber("proxyStart", timing.proxyStart); 206 timingObject->setNumber("proxyEnd", timing.proxyEnd); 207 timingObject->setNumber("dnsStart", timing.dnsStart); 208 timingObject->setNumber("dnsEnd", timing.dnsEnd); 209 timingObject->setNumber("connectStart", timing.connectStart); 210 timingObject->setNumber("connectEnd", timing.connectEnd); 211 timingObject->setNumber("sslStart", timing.sslStart); 212 timingObject->setNumber("sslEnd", timing.sslEnd); 213 timingObject->setNumber("sendStart", timing.sendStart); 214 timingObject->setNumber("sendEnd", timing.sendEnd); 215 timingObject->setNumber("receiveHeadersEnd", timing.receiveHeadersEnd); 216 return timingObject; 217 } 218 219 static PassRefPtr<InspectorObject> buildObjectForResourceRequest(const ResourceRequest& request) 220 { 221 RefPtr<InspectorObject> requestObject = InspectorObject::create(); 222 requestObject->setString("url", request.url().string()); 223 requestObject->setString("method", request.httpMethod()); 224 requestObject->setObject("headers", buildObjectForHeaders(request.httpHeaderFields())); 225 if (request.httpBody() && !request.httpBody()->isEmpty()) 226 requestObject->setString("postData", request.httpBody()->flattenToString()); 227 return requestObject; 228 } 229 230 static PassRefPtr<InspectorObject> buildObjectForResourceResponse(const ResourceResponse& response) 231 { 232 if (response.isNull()) 233 return 0; 234 235 RefPtr<InspectorObject> responseObject = InspectorObject::create(); 236 responseObject->setNumber("status", response.resourceLoadInfo() ? response.resourceLoadInfo()->httpStatusCode : response.httpStatusCode()); 237 responseObject->setString("statusText", response.resourceLoadInfo() ? response.resourceLoadInfo()->httpStatusText : response.httpStatusText()); 238 239 responseObject->setString("mimeType", response.mimeType()); 240 responseObject->setBoolean("connectionReused", response.connectionReused()); 241 responseObject->setNumber("connectionID", response.connectionID()); 242 responseObject->setBoolean("fromDiskCache", response.wasCached()); 243 if (response.resourceLoadTiming()) 244 responseObject->setObject("timing", buildObjectForTiming(*response.resourceLoadTiming())); 245 246 if (response.resourceLoadInfo()) { 247 responseObject->setObject("headers", buildObjectForHeaders(response.resourceLoadInfo()->responseHeaders)); 248 if (!response.resourceLoadInfo()->responseHeadersText.isEmpty()) 249 responseObject->setString("headersText", response.resourceLoadInfo()->responseHeadersText); 250 251 responseObject->setObject("requestHeaders", buildObjectForHeaders(response.resourceLoadInfo()->requestHeaders)); 252 if (!response.resourceLoadInfo()->requestHeadersText.isEmpty()) 253 responseObject->setString("requestHeadersText", response.resourceLoadInfo()->requestHeadersText); 254 } else 255 responseObject->setObject("headers", buildObjectForHeaders(response.httpHeaderFields())); 256 257 return responseObject; 258 } 259 260 static String pointerAsId(void* pointer) 261 { 262 unsigned long long address = reinterpret_cast<uintptr_t>(pointer); 263 // We want 0 to be "", so that JavaScript checks for if (frameId) worked. 264 return String::format("%.0llX", address); 265 } 266 267 static String cachedResourceTypeString(const CachedResource& cachedResource) 268 { 269 switch (cachedResource.type()) { 270 case CachedResource::ImageResource: 271 return ResourceType::image; 272 case CachedResource::FontResource: 273 return ResourceType::font; 274 case CachedResource::CSSStyleSheet: 275 // Fall through. 276 #if ENABLE(XSLT) 277 case CachedResource::XSLStyleSheet: 278 #endif 279 return ResourceType::stylesheet; 280 case CachedResource::Script: 281 return ResourceType::script; 282 default: 283 break; 284 } 285 return ResourceType::other; 286 } 287 288 static PassRefPtr<InspectorObject> buildObjectForCachedResource(const CachedResource& cachedResource) 289 { 290 RefPtr<InspectorObject> resourceObject = InspectorObject::create(); 291 resourceObject->setString("url", cachedResource.url()); 292 resourceObject->setString("type", cachedResourceTypeString(cachedResource)); 293 resourceObject->setNumber("bodySize", cachedResource.encodedSize()); 294 RefPtr<InspectorObject> resourceResponse = buildObjectForResourceResponse(cachedResource.response()); 295 if (resourceResponse) 296 resourceObject->setObject("response", resourceResponse); 297 return resourceObject; 298 } 299 300 InspectorResourceAgent::~InspectorResourceAgent() 301 { 302 if (m_state->getBoolean(ResourceAgentState::resourceAgentEnabled)) { 303 ErrorString error; 304 disable(&error); 305 } 306 ASSERT(!m_instrumentingAgents->inspectorResourceAgent()); 307 } 308 309 void InspectorResourceAgent::willSendRequest(unsigned long identifier, DocumentLoader* loader, ResourceRequest& request, const ResourceResponse& redirectResponse) 310 { 311 RefPtr<InspectorObject> headers = m_state->getObject(ResourceAgentState::extraRequestHeaders); 312 313 if (headers) { 314 InspectorObject::const_iterator end = headers->end(); 315 for (InspectorObject::const_iterator it = headers->begin(); it != end; ++it) { 316 String value; 317 if (it->second->asString(&value)) 318 request.setHTTPHeaderField(it->first, value); 319 } 320 } 321 322 request.setReportLoadTiming(true); 323 request.setReportRawHeaders(true); 324 325 RefPtr<ScriptCallStack> callStack = createScriptCallStack(ScriptCallStack::maxCallStackSizeToCapture, true); 326 RefPtr<InspectorArray> callStackValue; 327 if (callStack) 328 callStackValue = callStack->buildInspectorArray(); 329 else 330 callStackValue = InspectorArray::create(); 331 m_frontend->requestWillBeSent(static_cast<int>(identifier), pointerAsId(loader->frame()), pointerAsId(loader), loader->url().string(), buildObjectForResourceRequest(request), currentTime(), callStackValue, buildObjectForResourceResponse(redirectResponse)); 332 } 333 334 void InspectorResourceAgent::markResourceAsCached(unsigned long identifier) 335 { 336 m_frontend->resourceMarkedAsCached(static_cast<int>(identifier)); 337 } 338 339 void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response) 340 { 341 RefPtr<InspectorObject> resourceResponse = buildObjectForResourceResponse(response); 342 String type = "Other"; 343 long cachedResourceSize = 0; 344 345 if (loader) { 346 CachedResource* cachedResource = InspectorResourceAgent::cachedResource(loader->frame(), response.url()); 347 if (cachedResource) { 348 type = cachedResourceTypeString(*cachedResource); 349 cachedResourceSize = cachedResource->encodedSize(); 350 // Use mime type from cached resource in case the one in response is empty. 351 if (response.mimeType().isEmpty()) 352 resourceResponse->setString("mimeType", cachedResource->response().mimeType()); 353 } 354 if (equalIgnoringFragmentIdentifier(response.url(), loader->frameLoader()->iconURL())) 355 type = ResourceType::image; 356 else if (equalIgnoringFragmentIdentifier(response.url(), loader->url()) && type == "Other") 357 type = ResourceType::document; 358 } 359 m_frontend->responseReceived(static_cast<int>(identifier), currentTime(), type, resourceResponse); 360 // If we revalidated the resource and got Not modified, send content length following didReceiveResponse 361 // as there will be no calls to didReceiveContentLength from the network stack. 362 if (cachedResourceSize && response.httpStatusCode() == 304) 363 didReceiveContentLength(identifier, cachedResourceSize, 0); 364 } 365 366 void InspectorResourceAgent::didReceiveContentLength(unsigned long identifier, int dataLength, int encodedDataLength) 367 { 368 m_frontend->dataReceived(static_cast<int>(identifier), currentTime(), dataLength, encodedDataLength); 369 } 370 371 void InspectorResourceAgent::didFinishLoading(unsigned long identifier, double finishTime) 372 { 373 if (!finishTime) 374 finishTime = currentTime(); 375 376 m_frontend->loadingFinished(static_cast<int>(identifier), finishTime); 377 } 378 379 void InspectorResourceAgent::didFailLoading(unsigned long identifier, const ResourceError& error) 380 { 381 m_frontend->loadingFailed(static_cast<int>(identifier), currentTime(), error.localizedDescription(), error.isCancellation()); 382 } 383 384 void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader* loader, const CachedResource* resource) 385 { 386 m_frontend->resourceLoadedFromMemoryCache(pointerAsId(loader->frame()), pointerAsId(loader), loader->url().string(), currentTime(), buildObjectForCachedResource(*resource)); 387 } 388 389 void InspectorResourceAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString) 390 { 391 m_frontend->initialContentSet(static_cast<int>(identifier), sourceString, ResourceType::script); 392 } 393 394 void InspectorResourceAgent::setInitialXHRContent(unsigned long identifier, const String& sourceString) 395 { 396 m_frontend->initialContentSet(static_cast<int>(identifier), sourceString, ResourceType::xhr); 397 } 398 399 void InspectorResourceAgent::domContentEventFired() 400 { 401 m_frontend->domContentEventFired(currentTime()); 402 } 403 404 void InspectorResourceAgent::loadEventFired() 405 { 406 m_frontend->loadEventFired(currentTime()); 407 } 408 409 static PassRefPtr<InspectorObject> buildObjectForFrame(Frame* frame) 410 { 411 RefPtr<InspectorObject> frameObject = InspectorObject::create(); 412 frameObject->setString("id", pointerAsId(frame)); 413 frameObject->setString("parentId", pointerAsId(frame->tree()->parent())); 414 if (frame->ownerElement()) { 415 String name = frame->ownerElement()->getAttribute(HTMLNames::nameAttr); 416 if (name.isEmpty()) 417 name = frame->ownerElement()->getAttribute(HTMLNames::idAttr); 418 frameObject->setString("name", name); 419 } 420 frameObject->setString("url", frame->document()->url().string()); 421 frameObject->setString("loaderId", pointerAsId(frame->loader()->documentLoader())); 422 423 return frameObject; 424 } 425 426 static PassRefPtr<InspectorObject> buildObjectForFrameTree(Frame* frame) 427 { 428 RefPtr<InspectorObject> result = InspectorObject::create(); 429 RefPtr<InspectorObject> frameObject = buildObjectForFrame(frame); 430 result->setObject("frame", frameObject); 431 432 RefPtr<InspectorArray> subresources = InspectorArray::create(); 433 result->setArray("resources", subresources); 434 const CachedResourceLoader::DocumentResourceMap& allResources = frame->document()->cachedResourceLoader()->allCachedResources(); 435 CachedResourceLoader::DocumentResourceMap::const_iterator end = allResources.end(); 436 for (CachedResourceLoader::DocumentResourceMap::const_iterator it = allResources.begin(); it != end; ++it) { 437 CachedResource* cachedResource = it->second.get(); 438 RefPtr<InspectorObject> resourceObject = InspectorObject::create(); 439 resourceObject->setString("url", cachedResource->url()); 440 resourceObject->setString("type", cachedResourceTypeString(*cachedResource)); 441 subresources->pushValue(resourceObject); 442 } 443 444 RefPtr<InspectorArray> childrenArray; 445 for (Frame* child = frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) { 446 if (!childrenArray) { 447 childrenArray = InspectorArray::create(); 448 result->setArray("childFrames", childrenArray); 449 } 450 childrenArray->pushObject(buildObjectForFrameTree(child)); 451 } 452 return result; 453 } 454 455 void InspectorResourceAgent::didCommitLoad(DocumentLoader* loader) 456 { 457 m_frontend->frameNavigated(buildObjectForFrame(loader->frame()), pointerAsId(loader)); 458 } 459 460 void InspectorResourceAgent::frameDetachedFromParent(Frame* frame) 461 { 462 m_frontend->frameDetached(pointerAsId(frame)); 463 } 464 465 #if ENABLE(WEB_SOCKETS) 466 467 // FIXME: More this into the front-end? 468 // Create human-readable binary representation, like "01:23:45:67:89:AB:CD:EF". 469 static String createReadableStringFromBinary(const unsigned char* value, size_t length) 470 { 471 ASSERT(length > 0); 472 StringBuilder builder; 473 builder.reserveCapacity(length * 3 - 1); 474 for (size_t i = 0; i < length; ++i) { 475 if (i > 0) 476 builder.append(':'); 477 appendByteAsHex(value[i], builder); 478 } 479 return builder.toString(); 480 } 481 482 void InspectorResourceAgent::didCreateWebSocket(unsigned long identifier, const KURL& requestURL) 483 { 484 m_frontend->webSocketCreated(static_cast<int>(identifier), requestURL.string()); 485 } 486 487 void InspectorResourceAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const WebSocketHandshakeRequest& request) 488 { 489 RefPtr<InspectorObject> requestObject = InspectorObject::create(); 490 requestObject->setObject("headers", buildObjectForHeaders(request.headerFields())); 491 requestObject->setString("requestKey3", createReadableStringFromBinary(request.key3().value, sizeof(request.key3().value))); 492 m_frontend->webSocketWillSendHandshakeRequest(static_cast<int>(identifier), currentTime(), requestObject); 493 } 494 495 void InspectorResourceAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const WebSocketHandshakeResponse& response) 496 { 497 RefPtr<InspectorObject> responseObject = InspectorObject::create(); 498 responseObject->setNumber("status", response.statusCode()); 499 responseObject->setString("statusText", response.statusText()); 500 responseObject->setObject("headers", buildObjectForHeaders(response.headerFields())); 501 responseObject->setString("challengeResponse", createReadableStringFromBinary(response.challengeResponse().value, sizeof(response.challengeResponse().value))); 502 m_frontend->webSocketHandshakeResponseReceived(static_cast<int>(identifier), currentTime(), responseObject); 503 } 504 505 void InspectorResourceAgent::didCloseWebSocket(unsigned long identifier) 506 { 507 m_frontend->webSocketClosed(static_cast<int>(identifier), currentTime()); 508 } 509 #endif // ENABLE(WEB_SOCKETS) 510 511 Frame* InspectorResourceAgent::frameForId(const String& frameId) 512 { 513 Frame* mainFrame = m_page->mainFrame(); 514 for (Frame* frame = mainFrame; frame; frame = frame->tree()->traverseNext(mainFrame)) { 515 if (pointerAsId(frame) == frameId) 516 return frame; 517 } 518 return 0; 519 } 520 521 bool InspectorResourceAgent::backgroundEventsCollectionEnabled() 522 { 523 // FIXME (https://bugs.webkit.org/show_bug.cgi?id=58652) 524 // Add here condition to enable background events collection. 525 // Now this function is disable. 526 return false; 527 } 528 529 void InspectorResourceAgent::enable(ErrorString*) 530 { 531 enable(); 532 } 533 534 void InspectorResourceAgent::enable() 535 { 536 if (!m_frontend) 537 return; 538 m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, true); 539 m_instrumentingAgents->setInspectorResourceAgent(this); 540 } 541 542 void InspectorResourceAgent::disable(ErrorString*) 543 { 544 m_state->setBoolean(ResourceAgentState::resourceAgentEnabled, false); 545 m_instrumentingAgents->setInspectorResourceAgent(0); 546 } 547 548 void InspectorResourceAgent::getCachedResources(ErrorString*, RefPtr<InspectorObject>* object) 549 { 550 *object = buildObjectForFrameTree(m_page->mainFrame()); 551 } 552 553 void InspectorResourceAgent::getResourceContent(ErrorString* errorString, const String& frameId, const String& url, const bool* const optionalBase64Encode, String* content) 554 { 555 Frame* frame = frameForId(frameId); 556 if (!frame) { 557 *errorString = "No frame for given id found"; 558 return; 559 } 560 if (optionalBase64Encode ? *optionalBase64Encode : false) 561 InspectorResourceAgent::resourceContentBase64(errorString, frame, KURL(ParsedURLString, url), content); 562 else 563 InspectorResourceAgent::resourceContent(errorString, frame, KURL(ParsedURLString, url), content); 564 } 565 566 void InspectorResourceAgent::setExtraHeaders(ErrorString*, PassRefPtr<InspectorObject> headers) 567 { 568 m_state->setObject(ResourceAgentState::extraRequestHeaders, headers); 569 } 570 571 InspectorResourceAgent::InspectorResourceAgent(InstrumentingAgents* instrumentingAgents, Page* page, InspectorState* state) 572 : m_instrumentingAgents(instrumentingAgents) 573 , m_page(page) 574 , m_state(state) 575 { 576 if (backgroundEventsCollectionEnabled()) { 577 m_eventsCollector = new EventsCollector(); 578 m_inspectorFrontendProxy = new InspectorFrontendProxy(m_eventsCollector.get()); 579 // Create mock frontend, so we can collect network events. 580 m_mockFrontend = new InspectorFrontend::Network(m_inspectorFrontendProxy.get()); 581 m_frontend = m_mockFrontend.get(); 582 enable(); 583 } else 584 m_frontend = 0; 585 } 586 587 } // namespace WebCore 588 589 #endif // ENABLE(INSPECTOR) 590