OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011 Google Inc. All rights reserved. | 2 * Copyright (C) 2011 Google Inc. All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
570 return false; | 570 return false; |
571 } | 571 } |
572 | 572 |
573 void InspectorNetworkAgent::didBlockRequest( | 573 void InspectorNetworkAgent::didBlockRequest( |
574 LocalFrame* frame, | 574 LocalFrame* frame, |
575 const ResourceRequest& request, | 575 const ResourceRequest& request, |
576 DocumentLoader* loader, | 576 DocumentLoader* loader, |
577 const FetchInitiatorInfo& initiatorInfo, | 577 const FetchInitiatorInfo& initiatorInfo, |
578 ResourceRequestBlockedReason reason) { | 578 ResourceRequestBlockedReason reason) { |
579 unsigned long identifier = createUniqueIdentifier(); | 579 unsigned long identifier = createUniqueIdentifier(); |
580 willSendRequestInternal(frame, identifier, loader, request, | 580 willSendRequestInternal(identifier, loader, request, ResourceResponse(), |
581 ResourceResponse(), initiatorInfo); | 581 initiatorInfo); |
582 | 582 |
583 String requestId = IdentifiersFactory::requestId(identifier); | 583 String requestId = IdentifiersFactory::requestId(identifier); |
584 String protocolReason = buildBlockedReason(reason); | 584 String protocolReason = buildBlockedReason(reason); |
585 frontend()->loadingFailed(requestId, monotonicallyIncreasingTime(), | 585 frontend()->loadingFailed(requestId, monotonicallyIncreasingTime(), |
586 InspectorPageAgent::resourceTypeJson( | 586 InspectorPageAgent::resourceTypeJson( |
587 m_resourcesData->resourceType(requestId)), | 587 m_resourcesData->resourceType(requestId)), |
588 String(), false, protocolReason); | 588 String(), false, protocolReason); |
589 } | 589 } |
590 | 590 |
591 void InspectorNetworkAgent::didChangeResourcePriority( | 591 void InspectorNetworkAgent::didChangeResourcePriority( |
592 unsigned long identifier, | 592 unsigned long identifier, |
593 ResourceLoadPriority loadPriority) { | 593 ResourceLoadPriority loadPriority) { |
594 String requestId = IdentifiersFactory::requestId(identifier); | 594 String requestId = IdentifiersFactory::requestId(identifier); |
595 frontend()->resourceChangedPriority(requestId, | 595 frontend()->resourceChangedPriority(requestId, |
596 resourcePriorityJSON(loadPriority), | 596 resourcePriorityJSON(loadPriority), |
597 monotonicallyIncreasingTime()); | 597 monotonicallyIncreasingTime()); |
598 } | 598 } |
599 | 599 |
600 void InspectorNetworkAgent::willSendRequestInternal( | 600 void InspectorNetworkAgent::willSendRequestInternal( |
601 LocalFrame* frame, | |
602 unsigned long identifier, | 601 unsigned long identifier, |
603 DocumentLoader* loader, | 602 DocumentLoader* loader, |
604 const ResourceRequest& request, | 603 const ResourceRequest& request, |
605 const ResourceResponse& redirectResponse, | 604 const ResourceResponse& redirectResponse, |
606 const FetchInitiatorInfo& initiatorInfo) { | 605 const FetchInitiatorInfo& initiatorInfo) { |
607 String requestId = IdentifiersFactory::requestId(identifier); | 606 String requestId = IdentifiersFactory::requestId(identifier); |
608 String loaderId = IdentifiersFactory::loaderId(loader); | 607 String loaderId = loader ? IdentifiersFactory::loaderId(loader) : ""; |
609 m_resourcesData->resourceCreated(requestId, loaderId, request.url()); | 608 m_resourcesData->resourceCreated(requestId, loaderId, request.url()); |
610 | 609 |
611 InspectorPageAgent::ResourceType type = InspectorPageAgent::OtherResource; | 610 InspectorPageAgent::ResourceType type = InspectorPageAgent::OtherResource; |
612 if (initiatorInfo.name == FetchInitiatorTypeNames::xmlhttprequest) { | 611 if (initiatorInfo.name == FetchInitiatorTypeNames::xmlhttprequest) { |
613 type = InspectorPageAgent::XHRResource; | 612 type = InspectorPageAgent::XHRResource; |
614 m_resourcesData->setResourceType(requestId, type); | 613 m_resourcesData->setResourceType(requestId, type); |
615 } else if (initiatorInfo.name == FetchInitiatorTypeNames::document) { | 614 } else if (initiatorInfo.name == FetchInitiatorTypeNames::document) { |
616 type = InspectorPageAgent::DocumentResource; | 615 type = InspectorPageAgent::DocumentResource; |
617 m_resourcesData->setResourceType(requestId, type); | 616 m_resourcesData->setResourceType(requestId, type); |
618 } | 617 } |
619 | 618 |
620 String frameId = | 619 String frameId = loader && loader->frame() |
621 loader->frame() ? IdentifiersFactory::frameId(loader->frame()) : ""; | 620 ? IdentifiersFactory::frameId(loader->frame()) |
622 std::unique_ptr<protocol::Network::Initiator> initiatorObject = | 621 : ""; |
623 buildInitiatorObject(loader->frame() ? loader->frame()->document() : 0, | 622 std::unique_ptr<protocol::Network::Initiator> initiatorObject; |
624 initiatorInfo); | 623 if (loader) { |
| 624 initiatorObject = buildInitiatorObject( |
| 625 loader->frame() ? loader->frame()->document() : 0, initiatorInfo); |
| 626 } else { |
| 627 initiatorObject = |
| 628 protocol::Network::Initiator::create() |
| 629 .setType(protocol::Network::Initiator::TypeEnum::Preload) |
| 630 .build(); |
| 631 } |
| 632 |
625 if (initiatorInfo.name == FetchInitiatorTypeNames::document) { | 633 if (initiatorInfo.name == FetchInitiatorTypeNames::document) { |
626 FrameNavigationInitiatorMap::iterator it = | 634 FrameNavigationInitiatorMap::iterator it = |
627 m_frameNavigationInitiatorMap.find(frameId); | 635 m_frameNavigationInitiatorMap.find(frameId); |
628 if (it != m_frameNavigationInitiatorMap.end()) | 636 if (it != m_frameNavigationInitiatorMap.end()) |
629 initiatorObject = it->value->clone(); | 637 initiatorObject = it->value->clone(); |
630 } | 638 } |
631 | 639 |
632 std::unique_ptr<protocol::Network::Request> requestInfo( | 640 std::unique_ptr<protocol::Network::Request> requestInfo( |
633 buildObjectForResourceRequest(request)); | 641 buildObjectForResourceRequest(request)); |
634 | 642 |
635 requestInfo->setMixedContentType(mixedContentTypeForContextType( | 643 if (loader) { |
636 MixedContentChecker::contextTypeForInspector(frame, request))); | 644 requestInfo->setMixedContentType(mixedContentTypeForContextType( |
| 645 MixedContentChecker::contextTypeForInspector(loader->frame(), |
| 646 request))); |
| 647 } |
637 | 648 |
638 requestInfo->setReferrerPolicy(referrerPolicy(request.getReferrerPolicy())); | 649 requestInfo->setReferrerPolicy(referrerPolicy(request.getReferrerPolicy())); |
639 | 650 |
640 String resourceType = InspectorPageAgent::resourceTypeJson(type); | 651 String resourceType = InspectorPageAgent::resourceTypeJson(type); |
641 frontend()->requestWillBeSent( | 652 frontend()->requestWillBeSent( |
642 requestId, frameId, loaderId, | 653 requestId, frameId, loaderId, |
643 urlWithoutFragment(loader->url()).getString(), std::move(requestInfo), | 654 loader ? urlWithoutFragment(loader->url()).getString() : "", |
644 monotonicallyIncreasingTime(), currentTime(), std::move(initiatorObject), | 655 std::move(requestInfo), monotonicallyIncreasingTime(), currentTime(), |
| 656 std::move(initiatorObject), |
645 buildObjectForResourceResponse(redirectResponse), resourceType); | 657 buildObjectForResourceResponse(redirectResponse), resourceType); |
646 if (m_pendingXHRReplayData && !m_pendingXHRReplayData->async()) | 658 if (m_pendingXHRReplayData && !m_pendingXHRReplayData->async()) |
647 frontend()->flush(); | 659 frontend()->flush(); |
648 } | 660 } |
649 | 661 |
650 void InspectorNetworkAgent::willSendRequest( | 662 void InspectorNetworkAgent::willSendRequest( |
651 LocalFrame* frame, | |
652 unsigned long identifier, | 663 unsigned long identifier, |
653 DocumentLoader* loader, | 664 DocumentLoader* loader, |
654 ResourceRequest& request, | 665 ResourceRequest& request, |
655 const ResourceResponse& redirectResponse, | 666 const ResourceResponse& redirectResponse, |
656 const FetchInitiatorInfo& initiatorInfo) { | 667 const FetchInitiatorInfo& initiatorInfo) { |
657 // Ignore the request initiated internally. | 668 // Ignore the request initiated internally. |
658 if (initiatorInfo.name == FetchInitiatorTypeNames::internal) | 669 if (initiatorInfo.name == FetchInitiatorTypeNames::internal) |
659 return; | 670 return; |
660 | 671 |
661 if (initiatorInfo.name == FetchInitiatorTypeNames::document && | 672 if (initiatorInfo.name == FetchInitiatorTypeNames::document && |
(...skipping 19 matching lines...) Expand all Loading... |
681 request.requestContext() != WebURLRequest::RequestContextInternal) { | 692 request.requestContext() != WebURLRequest::RequestContextInternal) { |
682 request.setCachePolicy(WebCachePolicy::BypassCacheLoadOnlyFromCache); | 693 request.setCachePolicy(WebCachePolicy::BypassCacheLoadOnlyFromCache); |
683 } else { | 694 } else { |
684 request.setCachePolicy(WebCachePolicy::BypassingCache); | 695 request.setCachePolicy(WebCachePolicy::BypassingCache); |
685 } | 696 } |
686 request.setShouldResetAppCache(true); | 697 request.setShouldResetAppCache(true); |
687 } | 698 } |
688 if (m_state->booleanProperty(NetworkAgentState::bypassServiceWorker, false)) | 699 if (m_state->booleanProperty(NetworkAgentState::bypassServiceWorker, false)) |
689 request.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); | 700 request.setSkipServiceWorker(WebURLRequest::SkipServiceWorker::All); |
690 | 701 |
691 willSendRequestInternal(frame, identifier, loader, request, redirectResponse, | 702 willSendRequestInternal(identifier, loader, request, redirectResponse, |
692 initiatorInfo); | 703 initiatorInfo); |
693 | 704 |
694 if (!m_hostId.isEmpty()) | 705 if (!m_hostId.isEmpty()) |
695 request.addHTTPHeaderField( | 706 request.addHTTPHeaderField( |
696 HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id, | 707 HTTPNames::X_DevTools_Emulate_Network_Conditions_Client_Id, |
697 AtomicString(m_hostId)); | 708 AtomicString(m_hostId)); |
698 } | 709 } |
699 | 710 |
700 void InspectorNetworkAgent::markResourceAsCached(unsigned long identifier) { | 711 void InspectorNetworkAgent::markResourceAsCached(unsigned long identifier) { |
701 frontend()->requestServedFromCache(IdentifiersFactory::requestId(identifier)); | 712 frontend()->requestServedFromCache(IdentifiersFactory::requestId(identifier)); |
702 } | 713 } |
703 | 714 |
704 void InspectorNetworkAgent::didReceiveResourceResponse( | 715 void InspectorNetworkAgent::didReceiveResourceResponse( |
705 LocalFrame* frame, | 716 ExecutionContext* context, |
706 unsigned long identifier, | 717 unsigned long identifier, |
707 DocumentLoader* loader, | 718 DocumentLoader* loader, |
708 const ResourceResponse& response, | 719 const ResourceResponse& response, |
709 Resource* cachedResource) { | 720 Resource* cachedResource) { |
710 String requestId = IdentifiersFactory::requestId(identifier); | 721 String requestId = IdentifiersFactory::requestId(identifier); |
711 bool isNotModified = response.httpStatusCode() == 304; | 722 bool isNotModified = response.httpStatusCode() == 304; |
712 | 723 |
713 bool resourceIsEmpty = true; | 724 bool resourceIsEmpty = true; |
714 std::unique_ptr<protocol::Network::Response> resourceResponse = | 725 std::unique_ptr<protocol::Network::Response> resourceResponse = |
715 buildObjectForResourceResponse(response, cachedResource, | 726 buildObjectForResourceResponse(response, cachedResource, |
(...skipping 15 matching lines...) Expand all Loading... |
731 if (type == InspectorPageAgent::DocumentResource && loader && | 742 if (type == InspectorPageAgent::DocumentResource && loader && |
732 loader->substituteData().isValid()) | 743 loader->substituteData().isValid()) |
733 return; | 744 return; |
734 | 745 |
735 // Resources are added to NetworkResourcesData as a WeakMember here and | 746 // Resources are added to NetworkResourcesData as a WeakMember here and |
736 // removed in willDestroyResource() called in the prefinalizer of Resource. | 747 // removed in willDestroyResource() called in the prefinalizer of Resource. |
737 // Because NetworkResourceData retains weak references only, it | 748 // Because NetworkResourceData retains weak references only, it |
738 // doesn't affect Resource lifetime. | 749 // doesn't affect Resource lifetime. |
739 if (cachedResource) | 750 if (cachedResource) |
740 m_resourcesData->addResource(requestId, cachedResource); | 751 m_resourcesData->addResource(requestId, cachedResource); |
741 String frameId = IdentifiersFactory::frameId(frame); | 752 String frameId = |
| 753 context->isDocument() |
| 754 ? IdentifiersFactory::frameId(toDocument(context)->frame()) |
| 755 : ""; |
742 String loaderId = loader ? IdentifiersFactory::loaderId(loader) : ""; | 756 String loaderId = loader ? IdentifiersFactory::loaderId(loader) : ""; |
743 m_resourcesData->responseReceived(requestId, frameId, response); | 757 m_resourcesData->responseReceived(requestId, frameId, response); |
744 m_resourcesData->setResourceType(requestId, type); | 758 m_resourcesData->setResourceType(requestId, type); |
745 | 759 |
746 if (response.getSecurityStyle() != ResourceResponse::SecurityStyleUnknown && | 760 if (response.getSecurityStyle() != ResourceResponse::SecurityStyleUnknown && |
747 response.getSecurityStyle() != | 761 response.getSecurityStyle() != |
748 ResourceResponse::SecurityStyleUnauthenticated) { | 762 ResourceResponse::SecurityStyleUnauthenticated) { |
749 const ResourceResponse::SecurityDetails* responseSecurityDetails = | 763 const ResourceResponse::SecurityDetails* responseSecurityDetails = |
750 response.getSecurityDetails(); | 764 response.getSecurityDetails(); |
751 m_resourcesData->setCertificate(requestId, | 765 m_resourcesData->setCertificate(requestId, |
752 responseSecurityDetails->certificate); | 766 responseSecurityDetails->certificate); |
753 } | 767 } |
754 | 768 |
755 if (resourceResponse && !resourceIsEmpty) | 769 if (resourceResponse && !resourceIsEmpty) |
756 frontend()->responseReceived(requestId, frameId, loaderId, | 770 frontend()->responseReceived(requestId, frameId, loaderId, |
757 monotonicallyIncreasingTime(), | 771 monotonicallyIncreasingTime(), |
758 InspectorPageAgent::resourceTypeJson(type), | 772 InspectorPageAgent::resourceTypeJson(type), |
759 std::move(resourceResponse)); | 773 std::move(resourceResponse)); |
760 // If we revalidated the resource and got Not modified, send content length | 774 // If we revalidated the resource and got Not modified, send content length |
761 // following didReceiveResponse as there will be no calls to didReceiveData | 775 // following didReceiveResponse as there will be no calls to didReceiveData |
762 // from the network stack. | 776 // from the network stack. |
763 if (isNotModified && cachedResource && cachedResource->encodedSize()) | 777 if (isNotModified && cachedResource && cachedResource->encodedSize()) |
764 didReceiveData(frame, identifier, 0, cachedResource->encodedSize()); | 778 didReceiveData(identifier, 0, cachedResource->encodedSize()); |
765 } | 779 } |
766 | 780 |
767 static bool isErrorStatusCode(int statusCode) { | 781 static bool isErrorStatusCode(int statusCode) { |
768 return statusCode >= 400; | 782 return statusCode >= 400; |
769 } | 783 } |
770 | 784 |
771 void InspectorNetworkAgent::didReceiveData(LocalFrame*, | 785 void InspectorNetworkAgent::didReceiveData(unsigned long identifier, |
772 unsigned long identifier, | |
773 const char* data, | 786 const char* data, |
774 int dataLength) { | 787 int dataLength) { |
775 String requestId = IdentifiersFactory::requestId(identifier); | 788 String requestId = IdentifiersFactory::requestId(identifier); |
776 | 789 |
777 if (data) { | 790 if (data) { |
778 NetworkResourcesData::ResourceData const* resourceData = | 791 NetworkResourcesData::ResourceData const* resourceData = |
779 m_resourcesData->data(requestId); | 792 m_resourcesData->data(requestId); |
780 if (resourceData && | 793 if (resourceData && |
781 (!resourceData->cachedResource() || | 794 (!resourceData->cachedResource() || |
782 resourceData->cachedResource()->getDataBufferingPolicy() == | 795 resourceData->cachedResource()->getDataBufferingPolicy() == |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
827 encodedDataLength); | 840 encodedDataLength); |
828 } | 841 } |
829 | 842 |
830 void InspectorNetworkAgent::didReceiveCORSRedirectResponse( | 843 void InspectorNetworkAgent::didReceiveCORSRedirectResponse( |
831 LocalFrame* frame, | 844 LocalFrame* frame, |
832 unsigned long identifier, | 845 unsigned long identifier, |
833 DocumentLoader* loader, | 846 DocumentLoader* loader, |
834 const ResourceResponse& response, | 847 const ResourceResponse& response, |
835 Resource* resource) { | 848 Resource* resource) { |
836 // Update the response and finish loading | 849 // Update the response and finish loading |
837 didReceiveResourceResponse(frame, identifier, loader, response, resource); | 850 didReceiveResourceResponse(frame->document(), identifier, loader, response, |
| 851 resource); |
838 didFinishLoading(identifier, 0, | 852 didFinishLoading(identifier, 0, |
839 WebURLLoaderClient::kUnknownEncodedDataLength); | 853 WebURLLoaderClient::kUnknownEncodedDataLength); |
840 } | 854 } |
841 | 855 |
842 void InspectorNetworkAgent::didFailLoading(unsigned long identifier, | 856 void InspectorNetworkAgent::didFailLoading(unsigned long identifier, |
843 const ResourceError& error) { | 857 const ResourceError& error) { |
844 String requestId = IdentifiersFactory::requestId(identifier); | 858 String requestId = IdentifiersFactory::requestId(identifier); |
845 bool canceled = error.isCancellation(); | 859 bool canceled = error.isCancellation(); |
846 frontend()->loadingFailed(requestId, monotonicallyIncreasingTime(), | 860 frontend()->loadingFailed(requestId, monotonicallyIncreasingTime(), |
847 InspectorPageAgent::resourceTypeJson( | 861 InspectorPageAgent::resourceTypeJson( |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
914 m_pendingXHRReplayData = XHRReplayData::create( | 928 m_pendingXHRReplayData = XHRReplayData::create( |
915 xhr->getExecutionContext(), method, urlWithoutFragment(url), async, | 929 xhr->getExecutionContext(), method, urlWithoutFragment(url), async, |
916 formData.get(), includeCredentials); | 930 formData.get(), includeCredentials); |
917 for (const auto& header : headers) | 931 for (const auto& header : headers) |
918 m_pendingXHRReplayData->addHeader(header.key, header.value); | 932 m_pendingXHRReplayData->addHeader(header.key, header.value); |
919 } | 933 } |
920 | 934 |
921 void InspectorNetworkAgent::delayedRemoveReplayXHR(XMLHttpRequest* xhr) { | 935 void InspectorNetworkAgent::delayedRemoveReplayXHR(XMLHttpRequest* xhr) { |
922 if (!m_replayXHRs.contains(xhr)) | 936 if (!m_replayXHRs.contains(xhr)) |
923 return; | 937 return; |
924 | 938 DCHECK(m_removeFinishedReplayXHRTimer); |
925 m_replayXHRsToBeDeleted.add(xhr); | 939 m_replayXHRsToBeDeleted.add(xhr); |
926 m_replayXHRs.remove(xhr); | 940 m_replayXHRs.remove(xhr); |
927 m_removeFinishedReplayXHRTimer.startOneShot(0, BLINK_FROM_HERE); | 941 m_removeFinishedReplayXHRTimer->startOneShot(0, BLINK_FROM_HERE); |
928 } | 942 } |
929 | 943 |
930 void InspectorNetworkAgent::didFailXHRLoading(ExecutionContext* context, | 944 void InspectorNetworkAgent::didFailXHRLoading(ExecutionContext* context, |
931 XMLHttpRequest* xhr, | 945 XMLHttpRequest* xhr, |
932 ThreadableLoaderClient* client, | 946 ThreadableLoaderClient* client, |
933 const AtomicString& method, | 947 const AtomicString& method, |
934 const String& url) { | 948 const String& url) { |
935 didFinishXHRInternal(context, xhr, client, method, url, false); | 949 didFinishXHRInternal(context, xhr, client, method, url, false); |
936 } | 950 } |
937 | 951 |
(...skipping 587 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1525 m_replayXHRsToBeDeleted.clear(); | 1539 m_replayXHRsToBeDeleted.clear(); |
1526 } | 1540 } |
1527 | 1541 |
1528 InspectorNetworkAgent::InspectorNetworkAgent(InspectedFrames* inspectedFrames) | 1542 InspectorNetworkAgent::InspectorNetworkAgent(InspectedFrames* inspectedFrames) |
1529 : m_inspectedFrames(inspectedFrames), | 1543 : m_inspectedFrames(inspectedFrames), |
1530 m_resourcesData(NetworkResourcesData::create(maximumTotalBufferSize, | 1544 m_resourcesData(NetworkResourcesData::create(maximumTotalBufferSize, |
1531 maximumResourceBufferSize)), | 1545 maximumResourceBufferSize)), |
1532 m_pendingRequest(nullptr), | 1546 m_pendingRequest(nullptr), |
1533 m_isRecalculatingStyle(false), | 1547 m_isRecalculatingStyle(false), |
1534 m_removeFinishedReplayXHRTimer( | 1548 m_removeFinishedReplayXHRTimer( |
1535 TaskRunnerHelper::get(TaskType::UnspecedLoading, | 1549 inspectedFrames |
1536 inspectedFrames->root()), | 1550 ? new TaskRunnerTimer<InspectorNetworkAgent>( |
1537 this, | 1551 TaskRunnerHelper::get(TaskType::UnspecedLoading, |
1538 &InspectorNetworkAgent::removeFinishedReplayXHRFired) {} | 1552 inspectedFrames->root()), |
| 1553 this, |
| 1554 &InspectorNetworkAgent::removeFinishedReplayXHRFired) |
| 1555 : nullptr) {} |
1539 | 1556 |
1540 bool InspectorNetworkAgent::shouldForceCORSPreflight() { | 1557 bool InspectorNetworkAgent::shouldForceCORSPreflight() { |
1541 return m_state->booleanProperty(NetworkAgentState::cacheDisabled, false); | 1558 return m_state->booleanProperty(NetworkAgentState::cacheDisabled, false); |
1542 } | 1559 } |
1543 | 1560 |
1544 } // namespace blink | 1561 } // namespace blink |
OLD | NEW |