Remove unused methods of ResourceRequestBase
[WebKit-https.git] / Source / WebCore / inspector / InspectorNetworkAgent.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  * Copyright (C) 2015 Apple Inc. All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "InspectorNetworkAgent.h"
34
35 #include "CachedRawResource.h"
36 #include "CachedResource.h"
37 #include "CachedResourceLoader.h"
38 #include "CachedResourceRequestInitiators.h"
39 #include "Document.h"
40 #include "DocumentLoader.h"
41 #include "DocumentThreadableLoader.h"
42 #include "Frame.h"
43 #include "FrameLoader.h"
44 #include "HTTPHeaderMap.h"
45 #include "HTTPHeaderNames.h"
46 #include "IconController.h"
47 #include "InspectorPageAgent.h"
48 #include "InspectorTimelineAgent.h"
49 #include "InstrumentingAgents.h"
50 #include "JSMainThreadExecState.h"
51 #include "MemoryCache.h"
52 #include "NetworkResourcesData.h"
53 #include "Page.h"
54 #include "ProgressTracker.h"
55 #include "ResourceError.h"
56 #include "ResourceLoader.h"
57 #include "ResourceRequest.h"
58 #include "ResourceResponse.h"
59 #include "ScriptableDocumentParser.h"
60 #include "SubresourceLoader.h"
61 #include "ThreadableLoaderClient.h"
62 #include "URL.h"
63 #include "WebSocketFrame.h"
64 #include <inspector/ContentSearchUtilities.h>
65 #include <inspector/IdentifiersFactory.h>
66 #include <inspector/InspectorFrontendRouter.h>
67 #include <inspector/InspectorValues.h>
68 #include <inspector/ScriptCallStack.h>
69 #include <inspector/ScriptCallStackFactory.h>
70 #include <wtf/RefPtr.h>
71 #include <wtf/Stopwatch.h>
72 #include <wtf/text/StringBuilder.h>
73
74 using namespace Inspector;
75
76 typedef Inspector::NetworkBackendDispatcherHandler::LoadResourceCallback LoadResourceCallback;
77
78 namespace WebCore {
79
80 namespace {
81
82 class InspectorThreadableLoaderClient final : public ThreadableLoaderClient {
83     WTF_MAKE_NONCOPYABLE(InspectorThreadableLoaderClient);
84 public:
85     InspectorThreadableLoaderClient(RefPtr<LoadResourceCallback>&& callback)
86         : m_callback(WTFMove(callback)) { }
87
88     virtual ~InspectorThreadableLoaderClient() { }
89
90     void didReceiveResponse(unsigned long, const ResourceResponse& response) override
91     {
92         m_mimeType = response.mimeType();
93         m_statusCode = response.httpStatusCode();
94
95         // FIXME: This assumes text only responses. We should support non-text responses as well.
96         TextEncoding textEncoding(response.textEncodingName());
97         bool useDetector = false;
98         if (!textEncoding.isValid()) {
99             textEncoding = UTF8Encoding();
100             useDetector = true;
101         }
102
103         m_decoder = TextResourceDecoder::create(ASCIILiteral("text/plain"), textEncoding, useDetector);
104     }
105
106     void didReceiveData(const char* data, int dataLength) override
107     {
108         if (!dataLength)
109             return;
110
111         if (dataLength == -1)
112             dataLength = strlen(data);
113
114         m_responseText.append(m_decoder->decode(data, dataLength));
115     }
116
117     void didFinishLoading(unsigned long) override
118     {
119         if (m_decoder)
120             m_responseText.append(m_decoder->flush());
121
122         m_callback->sendSuccess(m_responseText.toString(), m_mimeType, m_statusCode);
123         dispose();
124     }
125
126     void didFail(const ResourceError& error) override
127     {
128         m_callback->sendFailure(error.isAccessControl() ? ASCIILiteral("Loading resource for inspector failed access control check") : ASCIILiteral("Loading resource for inspector failed"));
129         dispose();
130     }
131
132     void setLoader(RefPtr<ThreadableLoader>&& loader)
133     {
134         m_loader = WTFMove(loader);
135     }
136
137 private:
138     void dispose()
139     {
140         m_loader = nullptr;
141         delete this;
142     }
143
144     RefPtr<LoadResourceCallback> m_callback;
145     RefPtr<ThreadableLoader> m_loader;
146     RefPtr<TextResourceDecoder> m_decoder;
147     String m_mimeType;
148     StringBuilder m_responseText;
149     int m_statusCode;
150 };
151
152 } // namespace
153
154 InspectorNetworkAgent::InspectorNetworkAgent(WebAgentContext& context, InspectorPageAgent* pageAgent)
155     : InspectorAgentBase(ASCIILiteral("Network"), context)
156     , m_frontendDispatcher(std::make_unique<Inspector::NetworkFrontendDispatcher>(context.frontendRouter))
157     , m_backendDispatcher(Inspector::NetworkBackendDispatcher::create(context.backendDispatcher, this))
158     , m_pageAgent(pageAgent)
159     , m_resourcesData(std::make_unique<NetworkResourcesData>())
160 {
161 }
162
163 void InspectorNetworkAgent::didCreateFrontendAndBackend(Inspector::FrontendRouter*, Inspector::BackendDispatcher*)
164 {
165 }
166
167 void InspectorNetworkAgent::willDestroyFrontendAndBackend(Inspector::DisconnectReason)
168 {
169     ErrorString unused;
170     disable(unused);
171 }
172
173 static Ref<InspectorObject> buildObjectForHeaders(const HTTPHeaderMap& headers)
174 {
175     Ref<InspectorObject> headersObject = InspectorObject::create();
176     
177     for (const auto& header : headers)
178         headersObject->setString(header.key, header.value);
179     return headersObject;
180 }
181
182 Ref<Inspector::Protocol::Network::ResourceTiming> InspectorNetworkAgent::buildObjectForTiming(const NetworkLoadMetrics& timing, ResourceLoader& resourceLoader)
183 {
184     MonotonicTime startTime = resourceLoader.loadTiming().startTime();
185     double startTimeInInspector = m_environment.executionStopwatch()->elapsedTimeSince(startTime);
186
187     return Inspector::Protocol::Network::ResourceTiming::create()
188         .setStartTime(startTimeInInspector)
189         .setDomainLookupStart(timing.domainLookupStart.milliseconds())
190         .setDomainLookupEnd(timing.domainLookupEnd.milliseconds())
191         .setConnectStart(timing.connectStart.milliseconds())
192         .setConnectEnd(timing.connectEnd.milliseconds())
193         .setSecureConnectionStart(timing.secureConnectionStart.milliseconds())
194         .setRequestStart(timing.requestStart.milliseconds())
195         .setResponseStart(timing.responseStart.milliseconds())
196         .release();
197 }
198
199 static Inspector::Protocol::Network::Metrics::Priority toProtocol(NetworkLoadPriority priority)
200 {
201     switch (priority) {
202     case NetworkLoadPriority::Low:
203         return Inspector::Protocol::Network::Metrics::Priority::Low;
204     case NetworkLoadPriority::Medium:
205         return Inspector::Protocol::Network::Metrics::Priority::Medium;
206     case NetworkLoadPriority::High:
207         return Inspector::Protocol::Network::Metrics::Priority::High;
208     }
209
210     ASSERT_NOT_REACHED();
211     return Inspector::Protocol::Network::Metrics::Priority::Medium;
212 }
213
214 Ref<Inspector::Protocol::Network::Metrics> InspectorNetworkAgent::buildObjectForMetrics(const NetworkLoadMetrics& networkLoadMetrics)
215 {
216     auto metrics = Inspector::Protocol::Network::Metrics::create().release();
217
218     if (!networkLoadMetrics.protocol.isNull())
219         metrics->setProtocol(networkLoadMetrics.protocol);
220     if (networkLoadMetrics.priority)
221         metrics->setPriority(toProtocol(*networkLoadMetrics.priority));
222     if (networkLoadMetrics.remoteAddress)
223         metrics->setRemoteAddress(*networkLoadMetrics.remoteAddress);
224     if (networkLoadMetrics.connectionIdentifier)
225         metrics->setConnectionIdentifier(*networkLoadMetrics.connectionIdentifier);
226
227     return metrics;
228 }
229
230 static Ref<Inspector::Protocol::Network::Request> buildObjectForResourceRequest(const ResourceRequest& request)
231 {
232     auto requestObject = Inspector::Protocol::Network::Request::create()
233         .setUrl(request.url().string())
234         .setMethod(request.httpMethod())
235         .setHeaders(buildObjectForHeaders(request.httpHeaderFields()))
236         .release();
237     if (request.httpBody() && !request.httpBody()->isEmpty()) {
238         Vector<char> bytes;
239         request.httpBody()->flatten(bytes);
240         requestObject->setPostData(String::fromUTF8WithLatin1Fallback(bytes.data(), bytes.size()));
241     }
242     return requestObject;
243 }
244
245 static Inspector::Protocol::Network::Response::Source responseSource(ResourceResponse::Source source)
246 {
247     switch (source) {
248     case ResourceResponse::Source::Unknown:
249         return Inspector::Protocol::Network::Response::Source::Unknown;
250     case ResourceResponse::Source::Network:
251         return Inspector::Protocol::Network::Response::Source::Network;
252     case ResourceResponse::Source::MemoryCache:
253     case ResourceResponse::Source::MemoryCacheAfterValidation:
254         return Inspector::Protocol::Network::Response::Source::MemoryCache;
255     case ResourceResponse::Source::DiskCache:
256     case ResourceResponse::Source::DiskCacheAfterValidation:
257         return Inspector::Protocol::Network::Response::Source::DiskCache;
258     }
259
260     ASSERT_NOT_REACHED();
261     return Inspector::Protocol::Network::Response::Source::Unknown;
262 }
263
264 RefPtr<Inspector::Protocol::Network::Response> InspectorNetworkAgent::buildObjectForResourceResponse(const ResourceResponse& response, ResourceLoader* resourceLoader)
265 {
266     if (response.isNull())
267         return nullptr;
268
269     double status = response.httpStatusCode();
270     Ref<InspectorObject> headers = buildObjectForHeaders(response.httpHeaderFields());
271
272     auto responseObject = Inspector::Protocol::Network::Response::create()
273         .setUrl(response.url().string())
274         .setStatus(status)
275         .setStatusText(response.httpStatusText())
276         .setHeaders(WTFMove(headers))
277         .setMimeType(response.mimeType())
278         .setSource(responseSource(response.source()))
279         .release();
280
281     if (resourceLoader)
282         responseObject->setTiming(buildObjectForTiming(response.deprecatedNetworkLoadMetrics(), *resourceLoader));
283
284     return WTFMove(responseObject);
285 }
286
287 Ref<Inspector::Protocol::Network::CachedResource> InspectorNetworkAgent::buildObjectForCachedResource(CachedResource* cachedResource)
288 {
289     auto resourceObject = Inspector::Protocol::Network::CachedResource::create()
290         .setUrl(cachedResource->url())
291         .setType(InspectorPageAgent::cachedResourceTypeJson(*cachedResource))
292         .setBodySize(cachedResource->encodedSize())
293         .release();
294
295     auto resourceResponse = buildObjectForResourceResponse(cachedResource->response(), cachedResource->loader());
296     resourceObject->setResponse(WTFMove(resourceResponse));
297
298     String sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(cachedResource);
299     if (!sourceMappingURL.isEmpty())
300         resourceObject->setSourceMapURL(sourceMappingURL);
301
302     return resourceObject;
303 }
304
305 InspectorNetworkAgent::~InspectorNetworkAgent()
306 {
307     if (m_enabled) {
308         ErrorString unused;
309         disable(unused);
310     }
311     ASSERT(!m_instrumentingAgents.inspectorNetworkAgent());
312 }
313
314 double InspectorNetworkAgent::timestamp()
315 {
316     return m_environment.executionStopwatch()->elapsedTime();
317 }
318
319 void InspectorNetworkAgent::willSendRequest(unsigned long identifier, DocumentLoader& loader, ResourceRequest& request, const ResourceResponse& redirectResponse)
320 {
321     if (request.hiddenFromInspector()) {
322         m_hiddenRequestIdentifiers.add(identifier);
323         return;
324     }
325
326     String requestId = IdentifiersFactory::requestId(identifier);
327     m_resourcesData->resourceCreated(requestId, m_pageAgent->loaderId(&loader));
328
329     CachedResource* cachedResource = InspectorPageAgent::cachedResource(loader.frame(), request.url());
330     InspectorPageAgent::ResourceType type = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : m_resourcesData->resourceType(requestId);
331     if (type == InspectorPageAgent::OtherResource) {
332         if (m_loadingXHRSynchronously)
333             type = InspectorPageAgent::XHRResource;
334         else if (equalIgnoringFragmentIdentifier(request.url(), loader.frameLoader()->icon().url()))
335             type = InspectorPageAgent::ImageResource;
336         else if (equalIgnoringFragmentIdentifier(request.url(), loader.url()) && !loader.isCommitted())
337             type = InspectorPageAgent::DocumentResource;
338     }
339
340     m_resourcesData->setResourceType(requestId, type);
341
342     for (auto& entry : m_extraRequestHeaders)
343         request.setHTTPHeaderField(entry.key, entry.value);
344
345     if (m_cacheDisabled) {
346         request.setHTTPHeaderField(HTTPHeaderName::Pragma, "no-cache");
347         request.setCachePolicy(ReloadIgnoringCacheData);
348         request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "no-cache");
349     }
350
351     Inspector::Protocol::Page::ResourceType resourceType = InspectorPageAgent::resourceTypeJson(type);
352
353     RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader.frame() ? loader.frame()->document() : nullptr);
354     String targetId = request.initiatorIdentifier();
355
356     m_frontendDispatcher->requestWillBeSent(requestId, m_pageAgent->frameId(loader.frame()), m_pageAgent->loaderId(&loader), loader.url().string(), buildObjectForResourceRequest(request), timestamp(), initiatorObject, buildObjectForResourceResponse(redirectResponse, nullptr), type != InspectorPageAgent::OtherResource ? &resourceType : nullptr, targetId.isEmpty() ? nullptr : &targetId);
357 }
358
359 void InspectorNetworkAgent::didReceiveResponse(unsigned long identifier, DocumentLoader& loader, const ResourceResponse& response, ResourceLoader* resourceLoader)
360 {
361     if (m_hiddenRequestIdentifiers.contains(identifier))
362         return;
363
364     String requestId = IdentifiersFactory::requestId(identifier);
365     RefPtr<Inspector::Protocol::Network::Response> resourceResponse = buildObjectForResourceResponse(response, resourceLoader);
366
367     bool isNotModified = response.httpStatusCode() == 304;
368
369     CachedResource* cachedResource = nullptr;
370     if (resourceLoader && resourceLoader->isSubresourceLoader() && !isNotModified)
371         cachedResource = static_cast<SubresourceLoader*>(resourceLoader)->cachedResource();
372     if (!cachedResource)
373         cachedResource = InspectorPageAgent::cachedResource(loader.frame(), response.url());
374
375     if (cachedResource) {
376         // Use mime type from cached resource in case the one in response is empty.
377         if (resourceResponse && response.mimeType().isEmpty())
378             resourceResponse->setString(Inspector::Protocol::Network::Response::MimeType, cachedResource->response().mimeType());
379         m_resourcesData->addCachedResource(requestId, cachedResource);
380     }
381
382     InspectorPageAgent::ResourceType type = m_resourcesData->resourceType(requestId);
383     InspectorPageAgent::ResourceType newType = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : type;
384
385     // FIXME: XHRResource is returned for CachedResource::RawResource, it should be OtherResource unless it truly is an XHR.
386     // RawResource is used for loading worker scripts, and those should stay as ScriptResource and not change to XHRResource.
387     if (type != newType && newType != InspectorPageAgent::XHRResource && newType != InspectorPageAgent::OtherResource)
388         type = newType;
389
390     m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader.frame()), response);
391     m_resourcesData->setResourceType(requestId, type);
392
393     m_frontendDispatcher->responseReceived(requestId, m_pageAgent->frameId(loader.frame()), m_pageAgent->loaderId(&loader), timestamp(), InspectorPageAgent::resourceTypeJson(type), resourceResponse);
394
395     // If we revalidated the resource and got Not modified, send content length following didReceiveResponse
396     // as there will be no calls to didReceiveData from the network stack.
397     if (isNotModified && cachedResource && cachedResource->encodedSize())
398         didReceiveData(identifier, nullptr, cachedResource->encodedSize(), 0);
399 }
400
401 static bool isErrorStatusCode(int statusCode)
402 {
403     return statusCode >= 400;
404 }
405
406 void InspectorNetworkAgent::didReceiveData(unsigned long identifier, const char* data, int dataLength, int encodedDataLength)
407 {
408     if (m_hiddenRequestIdentifiers.contains(identifier))
409         return;
410
411     String requestId = IdentifiersFactory::requestId(identifier);
412
413     if (data) {
414         NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
415         if (resourceData && !m_loadingXHRSynchronously && (!resourceData->cachedResource() || resourceData->cachedResource()->dataBufferingPolicy() == DoNotBufferData || isErrorStatusCode(resourceData->httpStatusCode())))
416             m_resourcesData->maybeAddResourceData(requestId, data, dataLength);
417     }
418
419     m_frontendDispatcher->dataReceived(requestId, timestamp(), dataLength, encodedDataLength);
420 }
421
422 void InspectorNetworkAgent::didFinishLoading(unsigned long identifier, DocumentLoader& loader, const NetworkLoadMetrics& networkLoadMetrics)
423 {
424     if (m_hiddenRequestIdentifiers.remove(identifier))
425         return;
426
427     // FIXME: We should use the NetworkLoadMetrics's responseEnd to match ResourceTiming.
428     double elapsedFinishTime = timestamp();
429
430     String requestId = IdentifiersFactory::requestId(identifier);
431     if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource)
432         m_resourcesData->addResourceSharedBuffer(requestId, loader.frameLoader()->documentLoader()->mainResourceData(), loader.frame()->document()->encoding());
433
434     m_resourcesData->maybeDecodeDataToContent(requestId);
435
436     String sourceMappingURL;
437     NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
438     if (resourceData && resourceData->cachedResource())
439         sourceMappingURL = InspectorPageAgent::sourceMapURLForResource(resourceData->cachedResource());
440
441     RefPtr<Inspector::Protocol::Network::Metrics> metrics = buildObjectForMetrics(networkLoadMetrics);
442
443     m_frontendDispatcher->loadingFinished(requestId, elapsedFinishTime, !sourceMappingURL.isEmpty() ? &sourceMappingURL : nullptr, metrics);
444 }
445
446 void InspectorNetworkAgent::didFailLoading(unsigned long identifier, DocumentLoader& loader, const ResourceError& error)
447 {
448     if (m_hiddenRequestIdentifiers.remove(identifier))
449         return;
450
451     String requestId = IdentifiersFactory::requestId(identifier);
452
453     if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::DocumentResource) {
454         Frame* frame = loader.frame();
455         if (frame && frame->loader().documentLoader() && frame->document()) {
456             m_resourcesData->addResourceSharedBuffer(requestId,
457                 frame->loader().documentLoader()->mainResourceData(),
458                 frame->document()->encoding());
459         }
460     }
461
462     bool canceled = error.isCancellation();
463     m_frontendDispatcher->loadingFailed(requestId, timestamp(), error.localizedDescription(), canceled ? &canceled : nullptr);
464 }
465
466 void InspectorNetworkAgent::didLoadResourceFromMemoryCache(DocumentLoader& loader, CachedResource& resource)
467 {
468     String loaderId = m_pageAgent->loaderId(&loader);
469     String frameId = m_pageAgent->frameId(loader.frame());
470     unsigned long identifier = loader.frame()->page()->progress().createUniqueIdentifier();
471     String requestId = IdentifiersFactory::requestId(identifier);
472
473     m_resourcesData->resourceCreated(requestId, loaderId);
474     m_resourcesData->addCachedResource(requestId, &resource);
475
476     RefPtr<Inspector::Protocol::Network::Initiator> initiatorObject = buildInitiatorObject(loader.frame() ? loader.frame()->document() : nullptr);
477
478     // FIXME: It would be ideal to generate the Network.Response with the MemoryCache source
479     // instead of whatever ResourceResponse::Source the CachedResources's response has.
480     // The frontend already knows for certain that this was served from the memory cache.
481
482     m_frontendDispatcher->requestServedFromMemoryCache(requestId, frameId, loaderId, loader.url().string(), timestamp(), initiatorObject, buildObjectForCachedResource(&resource));
483 }
484
485 void InspectorNetworkAgent::setInitialScriptContent(unsigned long identifier, const String& sourceString)
486 {
487     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), sourceString);
488 }
489
490 void InspectorNetworkAgent::didReceiveScriptResponse(unsigned long identifier)
491 {
492     m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::ScriptResource);
493 }
494
495 void InspectorNetworkAgent::didReceiveThreadableLoaderResponse(unsigned long identifier, DocumentThreadableLoader& documentThreadableLoader)
496 {
497     String initiator = documentThreadableLoader.options().initiator;
498     if (initiator == cachedResourceRequestInitiators().fetch)
499         m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::FetchResource);
500     else if (initiator == cachedResourceRequestInitiators().xmlhttprequest)
501         m_resourcesData->setResourceType(IdentifiersFactory::requestId(identifier), InspectorPageAgent::XHRResource);
502 }
503
504 void InspectorNetworkAgent::didFinishXHRLoading(unsigned long identifier, const String& decodedText)
505 {
506     m_resourcesData->setResourceContent(IdentifiersFactory::requestId(identifier), decodedText);
507 }
508
509 void InspectorNetworkAgent::willLoadXHRSynchronously()
510 {
511     m_loadingXHRSynchronously = true;
512 }
513
514 void InspectorNetworkAgent::didLoadXHRSynchronously()
515 {
516     m_loadingXHRSynchronously = false;
517 }
518
519 void InspectorNetworkAgent::willDestroyCachedResource(CachedResource& cachedResource)
520 {
521     Vector<String> requestIds = m_resourcesData->removeCachedResource(&cachedResource);
522     if (!requestIds.size())
523         return;
524
525     String content;
526     bool base64Encoded;
527     if (!InspectorPageAgent::cachedResourceContent(&cachedResource, &content, &base64Encoded))
528         return;
529     for (auto& id : requestIds)
530         m_resourcesData->setResourceContent(id, content, base64Encoded);
531 }
532
533 void InspectorNetworkAgent::willRecalculateStyle()
534 {
535     m_isRecalculatingStyle = true;
536 }
537
538 void InspectorNetworkAgent::didRecalculateStyle()
539 {
540     m_isRecalculatingStyle = false;
541     m_styleRecalculationInitiator = nullptr;
542 }
543
544 void InspectorNetworkAgent::didScheduleStyleRecalculation(Document& document)
545 {
546     if (!m_styleRecalculationInitiator)
547         m_styleRecalculationInitiator = buildInitiatorObject(&document);
548 }
549
550 RefPtr<Inspector::Protocol::Network::Initiator> InspectorNetworkAgent::buildInitiatorObject(Document* document)
551 {
552     Ref<ScriptCallStack> stackTrace = createScriptCallStack(JSMainThreadExecState::currentState(), ScriptCallStack::maxCallStackSizeToCapture);
553     if (stackTrace->size() > 0) {
554         auto initiatorObject = Inspector::Protocol::Network::Initiator::create()
555             .setType(Inspector::Protocol::Network::Initiator::Type::Script)
556             .release();
557         initiatorObject->setStackTrace(stackTrace->buildInspectorArray());
558         return WTFMove(initiatorObject);
559     }
560
561     if (document && document->scriptableDocumentParser()) {
562         auto initiatorObject = Inspector::Protocol::Network::Initiator::create()
563             .setType(Inspector::Protocol::Network::Initiator::Type::Parser)
564             .release();
565         initiatorObject->setUrl(document->url().string());
566         initiatorObject->setLineNumber(document->scriptableDocumentParser()->textPosition().m_line.oneBasedInt());
567         return WTFMove(initiatorObject);
568     }
569
570     if (m_isRecalculatingStyle && m_styleRecalculationInitiator)
571         return m_styleRecalculationInitiator;
572
573     return Inspector::Protocol::Network::Initiator::create()
574         .setType(Inspector::Protocol::Network::Initiator::Type::Other)
575         .release();
576 }
577
578 #if ENABLE(WEB_SOCKETS)
579
580 void InspectorNetworkAgent::didCreateWebSocket(unsigned long identifier, const URL& requestURL)
581 {
582     m_frontendDispatcher->webSocketCreated(IdentifiersFactory::requestId(identifier), requestURL.string());
583 }
584
585 void InspectorNetworkAgent::willSendWebSocketHandshakeRequest(unsigned long identifier, const ResourceRequest& request)
586 {
587     auto requestObject = Inspector::Protocol::Network::WebSocketRequest::create()
588         .setHeaders(buildObjectForHeaders(request.httpHeaderFields()))
589         .release();
590     m_frontendDispatcher->webSocketWillSendHandshakeRequest(IdentifiersFactory::requestId(identifier), timestamp(), currentTime(), WTFMove(requestObject));
591 }
592
593 void InspectorNetworkAgent::didReceiveWebSocketHandshakeResponse(unsigned long identifier, const ResourceResponse& response)
594 {
595     auto responseObject = Inspector::Protocol::Network::WebSocketResponse::create()
596         .setStatus(response.httpStatusCode())
597         .setStatusText(response.httpStatusText())
598         .setHeaders(buildObjectForHeaders(response.httpHeaderFields()))
599         .release();
600     m_frontendDispatcher->webSocketHandshakeResponseReceived(IdentifiersFactory::requestId(identifier), timestamp(), WTFMove(responseObject));
601 }
602
603 void InspectorNetworkAgent::didCloseWebSocket(unsigned long identifier)
604 {
605     m_frontendDispatcher->webSocketClosed(IdentifiersFactory::requestId(identifier), timestamp());
606 }
607
608 void InspectorNetworkAgent::didReceiveWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
609 {
610     auto frameObject = Inspector::Protocol::Network::WebSocketFrame::create()
611         .setOpcode(frame.opCode)
612         .setMask(frame.masked)
613         .setPayloadData(String(frame.payload, frame.payloadLength))
614         .release();
615     m_frontendDispatcher->webSocketFrameReceived(IdentifiersFactory::requestId(identifier), timestamp(), WTFMove(frameObject));
616 }
617
618 void InspectorNetworkAgent::didSendWebSocketFrame(unsigned long identifier, const WebSocketFrame& frame)
619 {
620     auto frameObject = Inspector::Protocol::Network::WebSocketFrame::create()
621         .setOpcode(frame.opCode)
622         .setMask(frame.masked)
623         .setPayloadData(String(frame.payload, frame.payloadLength))
624         .release();
625     m_frontendDispatcher->webSocketFrameSent(IdentifiersFactory::requestId(identifier), timestamp(), WTFMove(frameObject));
626 }
627
628 void InspectorNetworkAgent::didReceiveWebSocketFrameError(unsigned long identifier, const String& errorMessage)
629 {
630     m_frontendDispatcher->webSocketFrameError(IdentifiersFactory::requestId(identifier), timestamp(), errorMessage);
631 }
632
633 #endif // ENABLE(WEB_SOCKETS)
634
635 void InspectorNetworkAgent::enable(ErrorString&)
636 {
637     enable();
638 }
639
640 void InspectorNetworkAgent::enable()
641 {
642     m_enabled = true;
643     m_instrumentingAgents.setInspectorNetworkAgent(this);
644 }
645
646 void InspectorNetworkAgent::disable(ErrorString&)
647 {
648     m_enabled = false;
649     m_instrumentingAgents.setInspectorNetworkAgent(nullptr);
650     m_resourcesData->clear();
651     m_extraRequestHeaders.clear();
652 }
653
654 void InspectorNetworkAgent::setExtraHTTPHeaders(ErrorString&, const InspectorObject& headers)
655 {
656     for (auto& entry : headers) {
657         String stringValue;
658         if (entry.value->asString(stringValue))
659             m_extraRequestHeaders.set(entry.key, stringValue);
660     }
661 }
662
663 void InspectorNetworkAgent::getResponseBody(ErrorString& errorString, const String& requestId, String* content, bool* base64Encoded)
664 {
665     NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
666     if (!resourceData) {
667         errorString = ASCIILiteral("No resource with given identifier found");
668         return;
669     }
670
671     if (resourceData->hasContent()) {
672         *base64Encoded = resourceData->base64Encoded();
673         *content = resourceData->content();
674         return;
675     }
676
677     if (resourceData->isContentEvicted()) {
678         errorString = ASCIILiteral("Request content was evicted from inspector cache");
679         return;
680     }
681
682     if (resourceData->buffer() && !resourceData->textEncodingName().isNull()) {
683         *base64Encoded = false;
684         if (InspectorPageAgent::sharedBufferContent(resourceData->buffer(), resourceData->textEncodingName(), *base64Encoded, content))
685             return;
686     }
687
688     if (resourceData->cachedResource()) {
689         if (InspectorPageAgent::cachedResourceContent(resourceData->cachedResource(), content, base64Encoded))
690             return;
691     }
692
693     errorString = ASCIILiteral("No data found for resource with given identifier");
694 }
695
696 void InspectorNetworkAgent::setCacheDisabled(ErrorString&, bool cacheDisabled)
697 {
698     m_cacheDisabled = cacheDisabled;
699     if (cacheDisabled)
700         MemoryCache::singleton().evictResources();
701 }
702
703 void InspectorNetworkAgent::loadResource(ErrorString& errorString, const String& frameId, const String& urlString, Ref<LoadResourceCallback>&& callback)
704 {
705     Frame* frame = m_pageAgent->assertFrame(errorString, frameId);
706     if (!frame)
707         return;
708
709     Document* document = frame->document();
710     if (!document) {
711         errorString = ASCIILiteral("No Document instance for the specified frame");
712         return;
713     }
714
715     URL url = document->completeURL(urlString);
716     ResourceRequest request(url);
717     request.setHTTPMethod(ASCIILiteral("GET"));
718     request.setHiddenFromInspector(true);
719
720     ThreadableLoaderOptions options;
721     options.sendLoadCallbacks = SendCallbacks; // So we remove this from m_hiddenRequestIdentifiers on completion.
722     options.defersLoadingPolicy = DefersLoadingPolicy::DisallowDefersLoading; // So the request is never deferred.
723     options.mode = FetchOptions::Mode::NoCors;
724     options.credentials = FetchOptions::Credentials::SameOrigin;
725     options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
726
727     // InspectorThreadableLoaderClient deletes itself when the load completes or fails.
728     InspectorThreadableLoaderClient* inspectorThreadableLoaderClient = new InspectorThreadableLoaderClient(callback.copyRef());
729     auto loader = DocumentThreadableLoader::create(*document, *inspectorThreadableLoaderClient, WTFMove(request), options);
730     if (!loader)
731         return;
732
733     // If the load already completed, inspectorThreadableLoaderClient will have been deleted and we will have already called the callback.
734     if (!callback->isActive())
735         return;
736
737     inspectorThreadableLoaderClient->setLoader(WTFMove(loader));
738 }
739
740 static Ref<Inspector::Protocol::Page::SearchResult> buildObjectForSearchResult(const String& requestId, const String& frameId, const String& url, int matchesCount)
741 {
742     auto searchResult = Inspector::Protocol::Page::SearchResult::create()
743         .setUrl(url)
744         .setFrameId(frameId)
745         .setMatchesCount(matchesCount)
746         .release();
747     searchResult->setRequestId(requestId);
748     return searchResult;
749 }
750
751 void InspectorNetworkAgent::searchOtherRequests(const JSC::Yarr::RegularExpression& regex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Page::SearchResult>>& result)
752 {
753     Vector<NetworkResourcesData::ResourceData*> resources = m_resourcesData->resources();
754     for (auto* resourceData : resources) {
755         if (resourceData->hasContent()) {
756             int matchesCount = ContentSearchUtilities::countRegularExpressionMatches(regex, resourceData->content());
757             if (matchesCount)
758                 result->addItem(buildObjectForSearchResult(resourceData->requestId(), resourceData->frameId(), resourceData->url(), matchesCount));
759         }
760     }
761 }
762
763 void InspectorNetworkAgent::searchInRequest(ErrorString& errorString, const String& requestId, const String& query, bool caseSensitive, bool isRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>>& results)
764 {
765     NetworkResourcesData::ResourceData const* resourceData = m_resourcesData->data(requestId);
766     if (!resourceData) {
767         errorString = ASCIILiteral("No resource with given identifier found");
768         return;
769     }
770
771     if (!resourceData->hasContent()) {
772         errorString = ASCIILiteral("No resource content");
773         return;
774     }
775
776     results = ContentSearchUtilities::searchInTextByLines(resourceData->content(), query, caseSensitive, isRegex);
777 }
778
779 void InspectorNetworkAgent::mainFrameNavigated(DocumentLoader& loader)
780 {
781     if (m_cacheDisabled)
782         MemoryCache::singleton().evictResources();
783
784     m_resourcesData->clear(m_pageAgent->loaderId(&loader));
785 }
786
787 } // namespace WebCore