Socket
Socket
Sign inDemoInstall

puppeteer-core

Package Overview
Dependencies
Maintainers
1
Versions
239
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

puppeteer-core - npm Package Compare versions

Comparing version 1.14.0 to 1.15.0

.gitattributes

31

CONTRIBUTING.md

@@ -0,1 +1,19 @@

<!-- gen:toc -->
- [How to Contribute](#how-to-contribute)
* [Contributor License Agreement](#contributor-license-agreement)
* [Getting setup](#getting-setup)
* [Code reviews](#code-reviews)
* [Code Style](#code-style)
* [API guidelines](#api-guidelines)
* [Commit Messages](#commit-messages)
* [Writing Documentation](#writing-documentation)
* [Adding New Dependencies](#adding-new-dependencies)
* [Writing Tests](#writing-tests)
* [Public API Coverage](#public-api-coverage)
* [Debugging Puppeteer](#debugging-puppeteer)
- [For Project Maintainers](#for-project-maintainers)
* [Releasing to NPM](#releasing-to-npm)
* [Building Chromium Revisions](#building-chromium-revisions)
<!-- gen:stop -->
# How to Contribute

@@ -202,4 +220,6 @@

## [For Project Maintainers] Releasing to NPM
# For Project Maintainers
## Releasing to NPM
Releasing to NPM consists of 3 phases:

@@ -228,1 +248,10 @@ 1. Source Code: mark a release.

## Building Chromium Revisions
Project maintainers with explicit access can request Chromium builds.
1. Goto [rpc explorer](https://cr-buildbucket.appspot.com/rpcexplorer/services/buildbucket.v2.Builds/ScheduleBuild?request={%20%20%20%20%22builder%22:%20{%20%20%20%20%20%20%20%20%22project%22:%20%22chromium%22,%20%20%20%20%20%20%20%20%22bucket%22:%20%22ci%22,%20%20%20%20%20%20%20%20%22builder%22:%20%22mac-rel%22%20%20%20%20},%20%20%20%20%22gitilesCommit%22:%20{%20%20%20%20%20%20%20%20%22host%22:%20%22chromium.googlesource.com%22,%20%20%20%20%20%20%20%20%22project%22:%20%22chromium/src%22,%20%20%20%20%20%20%20%20%22id%22:%20%22f6d8f73b94d1715b64f621d2112fbcecd0fc860a%22,%20%20%20%20%20%20%20%20%22ref%22:%20%22refs/heads/master%22%20%20%20%20},%20%20%20%20%22requestId%22:%20%22random%20string%20i%20guess%22})
2. Login with Google account
3. Set "builder" to either "mac-rel", "linux-rel", "win32-rel" or "win-rel"
4. Set "id" to the full SHA of the commit to be built
5. Hit "Send"

822

DeviceDescriptors.js
/**
* Copyright 2017 Google Inc. All rights reserved.
* Copyright 2019 Google Inc. All rights reserved.
*

@@ -17,809 +17,13 @@ * Licensed under the Apache License, Version 2.0 (the "License");

module.exports = [
{
'name': 'Blackberry PlayBook',
'userAgent': 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+',
'viewport': {
'width': 600,
'height': 1024,
'deviceScaleFactor': 1,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Blackberry PlayBook landscape',
'userAgent': 'Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+',
'viewport': {
'width': 1024,
'height': 600,
'deviceScaleFactor': 1,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'BlackBerry Z30',
'userAgent': 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'BlackBerry Z30 landscape',
'userAgent': 'Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Galaxy Note 3',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Galaxy Note 3 landscape',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Galaxy Note II',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Galaxy Note II landscape',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Galaxy S III',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Galaxy S III landscape',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Galaxy S5',
'userAgent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Galaxy S5 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPad',
'userAgent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
'viewport': {
'width': 768,
'height': 1024,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPad landscape',
'userAgent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
'viewport': {
'width': 1024,
'height': 768,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPad Mini',
'userAgent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
'viewport': {
'width': 768,
'height': 1024,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPad Mini landscape',
'userAgent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
'viewport': {
'width': 1024,
'height': 768,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPad Pro',
'userAgent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
'viewport': {
'width': 1024,
'height': 1366,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPad Pro landscape',
'userAgent': 'Mozilla/5.0 (iPad; CPU OS 11_0 like Mac OS X) AppleWebKit/604.1.34 (KHTML, like Gecko) Version/11.0 Mobile/15A5341f Safari/604.1',
'viewport': {
'width': 1366,
'height': 1024,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 4',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53',
'viewport': {
'width': 320,
'height': 480,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 4 landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 7_1_2 like Mac OS X) AppleWebKit/537.51.2 (KHTML, like Gecko) Version/7.0 Mobile/11D257 Safari/9537.53',
'viewport': {
'width': 480,
'height': 320,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 5',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1',
'viewport': {
'width': 320,
'height': 568,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 5 landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1',
'viewport': {
'width': 568,
'height': 320,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 6',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 375,
'height': 667,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 6 landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 667,
'height': 375,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 6 Plus',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 414,
'height': 736,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 6 Plus landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 736,
'height': 414,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 7',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 375,
'height': 667,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 7 landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 667,
'height': 375,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 7 Plus',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 414,
'height': 736,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 7 Plus landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 736,
'height': 414,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 8',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 375,
'height': 667,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 8 landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 667,
'height': 375,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone 8 Plus',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 414,
'height': 736,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone 8 Plus landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 736,
'height': 414,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone SE',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1',
'viewport': {
'width': 320,
'height': 568,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone SE landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3_1 like Mac OS X) AppleWebKit/603.1.30 (KHTML, like Gecko) Version/10.0 Mobile/14E304 Safari/602.1',
'viewport': {
'width': 568,
'height': 320,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'iPhone X',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 375,
'height': 812,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'iPhone X landscape',
'userAgent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1',
'viewport': {
'width': 812,
'height': 375,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Kindle Fire HDX',
'userAgent': 'Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true',
'viewport': {
'width': 800,
'height': 1280,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Kindle Fire HDX landscape',
'userAgent': 'Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true',
'viewport': {
'width': 1280,
'height': 800,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'LG Optimus L70',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 384,
'height': 640,
'deviceScaleFactor': 1.25,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'LG Optimus L70 landscape',
'userAgent': 'Mozilla/5.0 (Linux; U; Android 4.4.2; en-us; LGMS323 Build/KOT49I.MS32310c) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 640,
'height': 384,
'deviceScaleFactor': 1.25,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Microsoft Lumia 550',
'userAgent': 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 550) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Microsoft Lumia 950',
'userAgent': 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 4,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Microsoft Lumia 950 landscape',
'userAgent': 'Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/14.14263',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 4,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 10',
'userAgent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Safari/537.36',
'viewport': {
'width': 800,
'height': 1280,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 10 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 10 Build/MOB31T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Safari/537.36',
'viewport': {
'width': 1280,
'height': 800,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 4',
'userAgent': 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 384,
'height': 640,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 4 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 640,
'height': 384,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 5',
'userAgent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 360,
'height': 640,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 5 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 640,
'height': 360,
'deviceScaleFactor': 3,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 5X',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 412,
'height': 732,
'deviceScaleFactor': 2.625,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 5X landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 5X Build/OPR4.170623.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 732,
'height': 412,
'deviceScaleFactor': 2.625,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 6',
'userAgent': 'Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 412,
'height': 732,
'deviceScaleFactor': 3.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 6 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 7.1.1; Nexus 6 Build/N6F26U) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 732,
'height': 412,
'deviceScaleFactor': 3.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 6P',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 412,
'height': 732,
'deviceScaleFactor': 3.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 6P landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0.0; Nexus 6P Build/OPP3.170518.006) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 732,
'height': 412,
'deviceScaleFactor': 3.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nexus 7',
'userAgent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Safari/537.36',
'viewport': {
'width': 600,
'height': 960,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nexus 7 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 6.0.1; Nexus 7 Build/MOB30X) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Safari/537.36',
'viewport': {
'width': 960,
'height': 600,
'deviceScaleFactor': 2,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nokia Lumia 520',
'userAgent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)',
'viewport': {
'width': 320,
'height': 533,
'deviceScaleFactor': 1.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nokia Lumia 520 landscape',
'userAgent': 'Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 520)',
'viewport': {
'width': 533,
'height': 320,
'deviceScaleFactor': 1.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Nokia N9',
'userAgent': 'Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13',
'viewport': {
'width': 480,
'height': 854,
'deviceScaleFactor': 1,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Nokia N9 landscape',
'userAgent': 'Mozilla/5.0 (MeeGo; NokiaN9) AppleWebKit/534.13 (KHTML, like Gecko) NokiaBrowser/8.5.0 Mobile Safari/534.13',
'viewport': {
'width': 854,
'height': 480,
'deviceScaleFactor': 1,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Pixel 2',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 411,
'height': 731,
'deviceScaleFactor': 2.625,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Pixel 2 landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0; Pixel 2 Build/OPD3.170816.012) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 731,
'height': 411,
'deviceScaleFactor': 2.625,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
},
{
'name': 'Pixel 2 XL',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 411,
'height': 823,
'deviceScaleFactor': 3.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': false
}
},
{
'name': 'Pixel 2 XL landscape',
'userAgent': 'Mozilla/5.0 (Linux; Android 8.0.0; Pixel 2 XL Build/OPD1.170816.004) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3679.0 Mobile Safari/537.36',
'viewport': {
'width': 823,
'height': 411,
'deviceScaleFactor': 3.5,
'isMobile': true,
'hasTouch': true,
'isLandscape': true
}
}
];
for (const device of module.exports)
module.exports[device.name] = device;
let asyncawait = true;
try {
new Function('async function test(){await 1}');
} catch (error) {
asyncawait = false;
}
// If node does not support async await, use the compiled version.
if (asyncawait)
module.exports = require('./lib/DeviceDescriptors');
else
module.exports = require('./node6/lib/DeviceDescriptors');

@@ -73,2 +73,9 @@ /**

/**
* @return {boolean}
*/
_hasContext() {
return !this._contextResolveCallback;
}
_detach() {

@@ -75,0 +82,0 @@ this._detached = true;

@@ -23,2 +23,3 @@ /**

const {DOMWorld} = require('./DOMWorld');
const {NetworkManager} = require('./NetworkManager');

@@ -30,12 +31,12 @@ const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';

* @param {!Puppeteer.CDPSession} client
* @param {!Protocol.Page.FrameTree} frameTree
* @param {!Puppeteer.Page} page
* @param {!Puppeteer.NetworkManager} networkManager
* @param {boolean} ignoreHTTPSErrors
* @param {!Puppeteer.TimeoutSettings} timeoutSettings
*/
constructor(client, frameTree, page, networkManager, timeoutSettings) {
constructor(client, page, ignoreHTTPSErrors, timeoutSettings) {
super();
this._client = client;
this._page = page;
this._networkManager = networkManager;
this._networkManager = new NetworkManager(client, ignoreHTTPSErrors);
this._networkManager.setFrameManager(this);
this._timeoutSettings = timeoutSettings;

@@ -58,6 +59,25 @@ /** @type {!Map<string, !Frame>} */

this._client.on('Page.lifecycleEvent', event => this._onLifecycleEvent(event));
}
async initialize() {
const [,{frameTree}] = await Promise.all([
this._client.send('Page.enable'),
this._client.send('Page.getFrameTree'),
]);
this._handleFrameTree(frameTree);
await Promise.all([
this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
this._client.send('Runtime.enable', {}).then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._networkManager.initialize(),
]);
}
/**
* @return {!NetworkManager}
*/
networkManager() {
return this._networkManager;
}
/**
* @param {!Puppeteer.Frame} frame

@@ -247,6 +267,2 @@ * @param {string} url

async ensureSecondaryDOMWorld() {
await this._ensureIsolatedWorld(UTILITY_WORLD_NAME);
}
/**

@@ -297,6 +313,10 @@ * @param {string} name

if (frame) {
if (contextPayload.auxData && !!contextPayload.auxData['isDefault'])
if (contextPayload.auxData && !!contextPayload.auxData['isDefault']) {
world = frame._mainWorld;
else if (contextPayload.name === UTILITY_WORLD_NAME)
} else if (contextPayload.name === UTILITY_WORLD_NAME && !frame._secondaryWorld._hasContext()) {
// In case of multiple sessions to the same target, there's a race between
// connections so we might end up creating multiple isolated worlds.
// We can use either.
world = frame._secondaryWorld;
}
}

@@ -303,0 +323,0 @@ if (contextPayload.auxData && contextPayload.auxData['type'] === 'isolated')

@@ -192,9 +192,13 @@ /**

async _clickablePoint() {
const result = await this._client.send('DOM.getContentQuads', {
objectId: this._remoteObject.objectId
}).catch(debugError);
const [result, layoutMetrics] = await Promise.all([
this._client.send('DOM.getContentQuads', {
objectId: this._remoteObject.objectId
}).catch(debugError),
this._client.send('Page.getLayoutMetrics'),
]);
if (!result || !result.quads.length)
throw new Error('Node is either not visible or not an HTMLElement');
// Filter out quads that have too small area to click into.
const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).filter(quad => computeQuadArea(quad) > 1);
const {clientWidth, clientHeight} = layoutMetrics.layoutViewport;
const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).map(quad => this._intersectQuadWithViewport(quad, clientWidth, clientHeight)).filter(quad => computeQuadArea(quad) > 1);
if (!quads.length)

@@ -238,2 +242,15 @@ throw new Error('Node is either not visible or not an HTMLElement');

/**
* @param {!Array<{x: number, y: number}>} quad
* @param {number} width
* @param {number} height
* @return {!Array<{x: number, y: number}>}
*/
_intersectQuadWithViewport(quad, width, height) {
return quad.map(point => ({
x: Math.min(Math.max(point.x, 0), width),
y: Math.min(Math.max(point.y, 0), height),
}));
}
async hover() {

@@ -240,0 +257,0 @@ await this._scrollIntoViewIfNeeded();

@@ -19,2 +19,3 @@ /**

const http = require('http');
const https = require('https');
const URL = require('url');

@@ -60,3 +61,2 @@ const removeFolder = require('rimraf');

'--no-first-run',
'--safebrowsing-disable-auto-update',
'--enable-automation',

@@ -302,3 +302,3 @@ '--password-store=basic',

if (!this._isPuppeteerCore) {
const executablePath = process.env['PUPPETEER_EXECUTABLE_PATH'];
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH || process.env.npm_config_puppeteer_executable_path || process.env.npm_package_config_puppeteer_executable_path;
if (executablePath) {

@@ -388,4 +388,5 @@ const missingText = !fs.existsSync(executablePath) ? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' + executablePath : null;

const endpointURL = URL.resolve(browserURL, '/json/version');
const protocol = endpointURL.startsWith('https') ? https : http;
const requestOptions = Object.assign(URL.parse(endpointURL), { method: 'GET' });
const request = http.request(requestOptions, res => {
const request = protocol.request(requestOptions, res => {
let data = '';

@@ -392,0 +393,0 @@ if (res.statusCode !== 200) {

@@ -40,3 +40,2 @@ /**

this._frameManager = frameManager;
this._networkManager = frameManager._networkManager;
this._frame = frame;

@@ -52,3 +51,3 @@ this._initialLoaderId = frame._loaderId;

helper.addEventListener(this._frameManager, Events.FrameManager.FrameDetached, this._onFrameDetached.bind(this)),
helper.addEventListener(this._networkManager, Events.NetworkManager.Request, this._onRequest.bind(this)),
helper.addEventListener(this._frameManager.networkManager(), Events.NetworkManager.Request, this._onRequest.bind(this)),
];

@@ -55,0 +54,0 @@

@@ -19,3 +19,2 @@ /**

const {Events} = require('./Events');
const Multimap = require('./Multimap');

@@ -26,5 +25,6 @@ class NetworkManager extends EventEmitter {

*/
constructor(client) {
constructor(client, ignoreHTTPSErrors) {
super();
this._client = client;
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
this._frameManager = null;

@@ -46,9 +46,9 @@ /** @type {!Map<string, !Request>} */

this._protocolRequestInterceptionEnabled = false;
/** @type {!Multimap<string, string>} */
this._requestHashToRequestIds = new Multimap();
/** @type {!Multimap<string, string>} */
this._requestHashToInterceptionIds = new Multimap();
this._userCacheDisabled = false;
/** @type {!Map<string, string>} */
this._requestIdToInterceptionId = new Map();
this._client.on('Fetch.requestPaused', this._onRequestPaused.bind(this));
this._client.on('Fetch.authRequired', this._onAuthRequired.bind(this));
this._client.on('Network.requestWillBeSent', this._onRequestWillBeSent.bind(this));
this._client.on('Network.requestIntercepted', this._onRequestIntercepted.bind(this));
this._client.on('Network.requestServedFromCache', this._onRequestServedFromCache.bind(this));

@@ -60,2 +60,8 @@ this._client.on('Network.responseReceived', this._onResponseReceived.bind(this));

async initialize() {
await this._client.send('Network.enable');
if (this._ignoreHTTPSErrors)
await this._client.send('Security.setIgnoreCertificateErrors', {ignore: true});
}
/**

@@ -120,2 +126,10 @@ * @param {!Puppeteer.FrameManager} frameManager

/**
* @param {boolean} enabled
*/
async setCacheEnabled(enabled) {
this._userCacheDisabled = !enabled;
await this._updateProtocolCacheDisabled();
}
/**
* @param {boolean} value

@@ -133,9 +147,24 @@ */

this._protocolRequestInterceptionEnabled = enabled;
const patterns = enabled ? [{urlPattern: '*'}] : [];
await Promise.all([
this._client.send('Network.setCacheDisabled', {cacheDisabled: enabled}),
this._client.send('Network.setRequestInterception', {patterns})
]);
if (enabled) {
await Promise.all([
this._updateProtocolCacheDisabled(),
this._client.send('Fetch.enable', {
handleAuthRequests: true,
patterns: [{urlPattern: '*'}],
}),
]);
} else {
await Promise.all([
this._updateProtocolCacheDisabled(),
this._client.send('Fetch.disable')
]);
}
}
async _updateProtocolCacheDisabled() {
await this._client.send('Network.setCacheDisabled', {
cacheDisabled: this._userCacheDisabled || this._protocolRequestInterceptionEnabled
});
}
/**

@@ -147,9 +176,8 @@ * @param {!Protocol.Network.requestWillBeSentPayload} event

if (this._protocolRequestInterceptionEnabled && !event.request.url.startsWith('data:')) {
const requestHash = generateRequestHash(event.request);
const interceptionId = this._requestHashToInterceptionIds.firstValue(requestHash);
const requestId = event.requestId;
const interceptionId = this._requestIdToInterceptionId.get(requestId);
if (interceptionId) {
this._onRequest(event, interceptionId);
this._requestHashToInterceptionIds.delete(requestHash, interceptionId);
this._requestIdToInterceptionId.delete(requestId);
} else {
this._requestHashToRequestIds.set(requestHash, event.requestId);
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);

@@ -163,36 +191,38 @@ }

/**
* @param {!Protocol.Network.requestInterceptedPayload} event
* @param {!Protocol.Fetch.authRequiredPayload} event
*/
_onRequestIntercepted(event) {
if (event.authChallenge) {
/** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */
let response = 'Default';
if (this._attemptedAuthentications.has(event.interceptionId)) {
response = 'CancelAuth';
} else if (this._credentials) {
response = 'ProvideCredentials';
this._attemptedAuthentications.add(event.interceptionId);
}
const {username, password} = this._credentials || {username: undefined, password: undefined};
this._client.send('Network.continueInterceptedRequest', {
interceptionId: event.interceptionId,
authChallengeResponse: { response, username, password }
}).catch(debugError);
return;
_onAuthRequired(event) {
/** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */
let response = 'Default';
if (this._attemptedAuthentications.has(event.requestId)) {
response = 'CancelAuth';
} else if (this._credentials) {
response = 'ProvideCredentials';
this._attemptedAuthentications.add(event.requestId);
}
const {username, password} = this._credentials || {username: undefined, password: undefined};
this._client.send('Fetch.continueWithAuth', {
requestId: event.requestId,
authChallengeResponse: { response, username, password },
}).catch(debugError);
}
/**
* @param {!Protocol.Fetch.requestPausedPayload} event
*/
_onRequestPaused(event) {
if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
this._client.send('Network.continueInterceptedRequest', {
interceptionId: event.interceptionId
this._client.send('Fetch.continueRequest', {
requestId: event.requestId
}).catch(debugError);
}
const requestHash = generateRequestHash(event.request);
const requestId = this._requestHashToRequestIds.firstValue(requestHash);
if (requestId) {
const requestId = event.networkId;
const interceptionId = event.requestId;
if (requestId && this._requestIdToRequestWillBeSentEvent.has(requestId)) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(requestId);
this._onRequest(requestWillBeSentEvent, event.interceptionId);
this._requestHashToRequestIds.delete(requestHash, requestId);
this._onRequest(requestWillBeSentEvent, interceptionId);
this._requestIdToRequestWillBeSentEvent.delete(requestId);
} else {
this._requestHashToInterceptionIds.set(requestHash, event.interceptionId);
this._requestIdToInterceptionId.set(requestId, interceptionId);
}

@@ -419,8 +449,8 @@ }

this._interceptionHandled = true;
await this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
await this._client.send('Fetch.continueRequest', {
requestId: this._interceptionId,
url,
method,
postData,
headers,
headers: headers ? headersArray(headers) : undefined,
}).catch(error => {

@@ -446,2 +476,3 @@ // In certain cases, protocol will return error if the request was already canceled

/** @type {!Object<string, string>} */
const responseHeaders = {};

@@ -455,20 +486,9 @@ if (response.headers) {

if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = Buffer.byteLength(responseBody);
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
const statusCode = response.status || 200;
const statusText = statusTexts[statusCode] || '';
const statusLine = `HTTP/1.1 ${statusCode} ${statusText}`;
const CRLF = '\r\n';
let text = statusLine + CRLF;
for (const header of Object.keys(responseHeaders))
text += header + ': ' + responseHeaders[header] + CRLF;
text += CRLF;
let responseBuffer = Buffer.from(text, 'utf8');
if (responseBody)
responseBuffer = Buffer.concat([responseBuffer, responseBody]);
await this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
rawResponse: responseBuffer.toString('base64')
await this._client.send('Fetch.fulfillRequest', {
requestId: this._interceptionId,
responseCode: response.status || 200,
responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined,
}).catch(error => {

@@ -493,4 +513,4 @@ // In certain cases, protocol will return error if the request was already canceled

this._interceptionHandled = true;
await this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
await this._client.send('Fetch.failRequest', {
requestId: this._interceptionId,
errorReason

@@ -663,38 +683,2 @@ }).catch(error => {

const IGNORED_HEADERS = new Set(['accept', 'referer', 'x-devtools-emulate-network-conditions-client-id', 'cookie', 'origin', 'content-type', 'intervention']);
/**
* @param {!Protocol.Network.Request} request
* @return {string}
*/
function generateRequestHash(request) {
let normalizedURL = request.url;
try {
// Decoding is necessary to normalize URLs. @see crbug.com/759388
// The method will throw if the URL is malformed. In this case,
// consider URL to be normalized as-is.
normalizedURL = decodeURI(request.url);
} catch (e) {
}
const hash = {
url: normalizedURL,
method: request.method,
postData: request.postData,
headers: {},
};
if (!normalizedURL.startsWith('data:')) {
const headers = Object.keys(request.headers);
headers.sort();
for (let header of headers) {
const headerValue = request.headers[header];
header = header.toLowerCase();
if (IGNORED_HEADERS.has(header))
continue;
hash.headers[header] = headerValue;
}
}
return JSON.stringify(hash);
}
class SecurityDetails {

@@ -748,65 +732,13 @@ /**

const statusTexts = {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'209': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'306': 'Switch Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': 'I\'m a teapot',
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'510': 'Not Extended',
'511': 'Network Authentication Required',
};
/**
* @param {Object<string, string>} headers
* @return {!Array<{name: string, value: string}>}
*/
function headersArray(headers) {
const result = [];
for (const name in headers)
result.push({name, value: headers[name]});
return result;
}
module.exports = {Request, Response, NetworkManager, SecurityDetails};

@@ -22,3 +22,2 @@ /**

const {Connection} = require('./Connection');
const {NetworkManager} = require('./NetworkManager');
const {Dialog} = require('./Dialog');

@@ -47,21 +46,11 @@ const {EmulationManager} = require('./EmulationManager');

static async create(client, target, ignoreHTTPSErrors, defaultViewport, screenshotTaskQueue) {
await client.send('Page.enable');
const {frameTree} = await client.send('Page.getFrameTree');
const page = new Page(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue);
const page = new Page(client, target, ignoreHTTPSErrors, screenshotTaskQueue);
await Promise.all([
page._frameManager.initialize(),
client.send('Target.setAutoAttach', {autoAttach: true, waitForDebuggerOnStart: false, flatten: true}),
client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
client.send('Network.enable', {}),
client.send('Runtime.enable', {}).then(() => page._frameManager.ensureSecondaryDOMWorld()),
client.send('Security.enable', {}),
client.send('Performance.enable', {}),
client.send('Log.enable', {}),
]);
if (ignoreHTTPSErrors)
await client.send('Security.setOverrideCertificateErrors', {override: true});
// Initialize default page size.
if (defaultViewport)
await page.setViewport(defaultViewport);
return page;

@@ -73,7 +62,6 @@ }

* @param {!Puppeteer.Target} target
* @param {!Protocol.Page.FrameTree} frameTree
* @param {boolean} ignoreHTTPSErrors
* @param {!Puppeteer.TaskQueue} screenshotTaskQueue
*/
constructor(client, target, frameTree, ignoreHTTPSErrors, screenshotTaskQueue) {
constructor(client, target, ignoreHTTPSErrors, screenshotTaskQueue) {
super();

@@ -88,6 +76,4 @@ this._closed = false;

this._accessibility = new Accessibility(client);
this._networkManager = new NetworkManager(client);
/** @type {!FrameManager} */
this._frameManager = new FrameManager(client, frameTree, this, this._networkManager, this._timeoutSettings);
this._networkManager.setFrameManager(this._frameManager);
this._frameManager = new FrameManager(client, this, ignoreHTTPSErrors, this._timeoutSettings);
this._emulationManager = new EmulationManager(client);

@@ -97,3 +83,2 @@ this._tracing = new Tracing(client);

this._pageBindings = new Map();
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
this._coverage = new Coverage(client);

@@ -133,6 +118,7 @@ this._javascriptEnabled = true;

this._networkManager.on(Events.NetworkManager.Request, event => this.emit(Events.Page.Request, event));
this._networkManager.on(Events.NetworkManager.Response, event => this.emit(Events.Page.Response, event));
this._networkManager.on(Events.NetworkManager.RequestFailed, event => this.emit(Events.Page.RequestFailed, event));
this._networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event));
const networkManager = this._frameManager.networkManager();
networkManager.on(Events.NetworkManager.Request, event => this.emit(Events.Page.Request, event));
networkManager.on(Events.NetworkManager.Response, event => this.emit(Events.Page.Response, event));
networkManager.on(Events.NetworkManager.RequestFailed, event => this.emit(Events.Page.RequestFailed, event));
networkManager.on(Events.NetworkManager.RequestFinished, event => this.emit(Events.Page.RequestFinished, event));

@@ -145,3 +131,2 @@ client.on('Page.domContentEventFired', event => this.emit(Events.Page.DOMContentLoaded));

client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
client.on('Security.certificateError', event => this._onCertificateError(event));
client.on('Inspector.targetCrashed', event => this._onTargetCrashed());

@@ -266,3 +251,3 @@ client.on('Performance.metrics', event => this._emitMetrics(event));

async setRequestInterception(value) {
return this._networkManager.setRequestInterception(value);
return this._frameManager.networkManager().setRequestInterception(value);
}

@@ -274,3 +259,3 @@

setOfflineMode(enabled) {
return this._networkManager.setOfflineMode(enabled);
return this._frameManager.networkManager().setOfflineMode(enabled);
}

@@ -293,14 +278,2 @@

/**
* @param {!Protocol.Security.certificateErrorPayload} event
*/
_onCertificateError(event) {
if (!this._ignoreHTTPSErrors)
return;
this._client.send('Security.handleCertificateError', {
eventId: event.eventId,
action: 'continue'
}).catch(debugError);
}
/**
* @param {string} selector

@@ -462,3 +435,3 @@ * @return {!Promise<?Puppeteer.ElementHandle>}

async authenticate(credentials) {
return this._networkManager.authenticate(credentials);
return this._frameManager.networkManager().authenticate(credentials);
}

@@ -470,3 +443,3 @@

async setExtraHTTPHeaders(headers) {
return this._networkManager.setExtraHTTPHeaders(headers);
return this._frameManager.networkManager().setExtraHTTPHeaders(headers);
}

@@ -478,3 +451,3 @@

async setUserAgent(userAgent) {
return this._networkManager.setUserAgent(userAgent);
return this._frameManager.networkManager().setUserAgent(userAgent);
}

@@ -701,3 +674,3 @@

} = options;
return helper.waitForEvent(this._networkManager, Events.NetworkManager.Request, request => {
return helper.waitForEvent(this._frameManager.networkManager(), Events.NetworkManager.Request, request => {
if (helper.isString(urlOrPredicate))

@@ -720,3 +693,3 @@ return (urlOrPredicate === request.url());

} = options;
return helper.waitForEvent(this._networkManager, Events.NetworkManager.Response, response => {
return helper.waitForEvent(this._frameManager.networkManager(), Events.NetworkManager.Response, response => {
if (helper.isString(urlOrPredicate))

@@ -840,3 +813,3 @@ return (urlOrPredicate === response.url());

async setCacheEnabled(enabled = true) {
await this._client.send('Network.setCacheDisabled', {cacheDisabled: !enabled});
await this._frameManager.networkManager().setCacheEnabled(enabled);
}

@@ -843,0 +816,0 @@

@@ -18,2 +18,4 @@ /**

const BrowserFetcher = require('./BrowserFetcher');
const Errors = require('./Errors');
const DeviceDescriptors = require('./DeviceDescriptors');

@@ -55,2 +57,16 @@ module.exports = class {

/**
* @return {Object}
*/
get devices() {
return DeviceDescriptors;
}
/**
* @return {Object}
*/
get errors() {
return Errors;
}
/**
* @param {!Launcher.ChromeArgOptions=} options

@@ -57,0 +73,0 @@ * @return {!Array<string>}

@@ -73,2 +73,9 @@ /**

/**
* @return {boolean}
*/
_hasContext() {
return !this._contextResolveCallback;
}
_detach() {

@@ -75,0 +82,0 @@ this._detached = true;

@@ -23,2 +23,3 @@ /**

const {DOMWorld} = require('./DOMWorld');
const {NetworkManager} = require('./NetworkManager');

@@ -30,12 +31,12 @@ const UTILITY_WORLD_NAME = '__puppeteer_utility_world__';

* @param {!Puppeteer.CDPSession} client
* @param {!Protocol.Page.FrameTree} frameTree
* @param {!Puppeteer.Page} page
* @param {!Puppeteer.NetworkManager} networkManager
* @param {boolean} ignoreHTTPSErrors
* @param {!Puppeteer.TimeoutSettings} timeoutSettings
*/
constructor(client, frameTree, page, networkManager, timeoutSettings) {
constructor(client, page, ignoreHTTPSErrors, timeoutSettings) {
super();
this._client = client;
this._page = page;
this._networkManager = networkManager;
this._networkManager = new NetworkManager(client, ignoreHTTPSErrors);
this._networkManager.setFrameManager(this);
this._timeoutSettings = timeoutSettings;

@@ -58,3 +59,48 @@ /** @type {!Map<string, !Frame>} */

this._client.on('Page.lifecycleEvent', event => this._onLifecycleEvent(event));
}
/* async */ initialize() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
const [,{frameTree}] = (yield Promise.all([
this._client.send('Page.enable'),
this._client.send('Page.getFrameTree'),
]));
this._handleFrameTree(frameTree);
(yield Promise.all([
this._client.send('Page.setLifecycleEventsEnabled', { enabled: true }),
this._client.send('Runtime.enable', {}).then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
this._networkManager.initialize(),
]));
});}
/**
* @return {!NetworkManager}
*/
networkManager() {
return this._networkManager;
}

@@ -325,32 +371,2 @@

/* async */ ensureSecondaryDOMWorld() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._ensureIsolatedWorld(UTILITY_WORLD_NAME));
});}
/**

@@ -427,6 +443,10 @@ * @param {string} name

if (frame) {
if (contextPayload.auxData && !!contextPayload.auxData['isDefault'])
if (contextPayload.auxData && !!contextPayload.auxData['isDefault']) {
world = frame._mainWorld;
else if (contextPayload.name === UTILITY_WORLD_NAME)
} else if (contextPayload.name === UTILITY_WORLD_NAME && !frame._secondaryWorld._hasContext()) {
// In case of multiple sessions to the same target, there's a race between
// connections so we might end up creating multiple isolated worlds.
// We can use either.
world = frame._secondaryWorld;
}
}

@@ -433,0 +453,0 @@ if (contextPayload.auxData && contextPayload.auxData['type'] === 'isolated')

@@ -400,9 +400,13 @@ /**

})(function*(){
const result = (yield this._client.send('DOM.getContentQuads', {
objectId: this._remoteObject.objectId
}).catch(debugError));
const [result, layoutMetrics] = (yield Promise.all([
this._client.send('DOM.getContentQuads', {
objectId: this._remoteObject.objectId
}).catch(debugError),
this._client.send('Page.getLayoutMetrics'),
]));
if (!result || !result.quads.length)
throw new Error('Node is either not visible or not an HTMLElement');
// Filter out quads that have too small area to click into.
const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).filter(quad => computeQuadArea(quad) > 1);
const {clientWidth, clientHeight} = layoutMetrics.layoutViewport;
const quads = result.quads.map(quad => this._fromProtocolQuad(quad)).map(quad => this._intersectQuadWithViewport(quad, clientWidth, clientHeight)).filter(quad => computeQuadArea(quad) > 1);
if (!quads.length)

@@ -446,2 +450,15 @@ throw new Error('Node is either not visible or not an HTMLElement');

/**
* @param {!Array<{x: number, y: number}>} quad
* @param {number} width
* @param {number} height
* @return {!Array<{x: number, y: number}>}
*/
_intersectQuadWithViewport(quad, width, height) {
return quad.map(point => ({
x: Math.min(Math.max(point.x, 0), width),
y: Math.min(Math.max(point.y, 0), height),
}));
}
/* async */ hover() {return (fn => {

@@ -448,0 +465,0 @@ const gen = fn.call(this);

@@ -19,2 +19,3 @@ /**

const http = require('http');
const https = require('https');
const URL = require('url');

@@ -60,3 +61,2 @@ const removeFolder = require('rimraf');

'--no-first-run',
'--safebrowsing-disable-auto-update',
'--enable-automation',

@@ -354,3 +354,3 @@ '--password-store=basic',

if (!this._isPuppeteerCore) {
const executablePath = process.env['PUPPETEER_EXECUTABLE_PATH'];
const executablePath = process.env.PUPPETEER_EXECUTABLE_PATH || process.env.npm_config_puppeteer_executable_path || process.env.npm_package_config_puppeteer_executable_path;
if (executablePath) {

@@ -440,4 +440,5 @@ const missingText = !fs.existsSync(executablePath) ? 'Tried to use PUPPETEER_EXECUTABLE_PATH env variable to launch browser but did not find any executable at: ' + executablePath : null;

const endpointURL = URL.resolve(browserURL, '/json/version');
const protocol = endpointURL.startsWith('https') ? https : http;
const requestOptions = Object.assign(URL.parse(endpointURL), { method: 'GET' });
const request = http.request(requestOptions, res => {
const request = protocol.request(requestOptions, res => {
let data = '';

@@ -444,0 +445,0 @@ if (res.statusCode !== 200) {

@@ -40,3 +40,2 @@ /**

this._frameManager = frameManager;
this._networkManager = frameManager._networkManager;
this._frame = frame;

@@ -52,3 +51,3 @@ this._initialLoaderId = frame._loaderId;

helper.addEventListener(this._frameManager, Events.FrameManager.FrameDetached, this._onFrameDetached.bind(this)),
helper.addEventListener(this._networkManager, Events.NetworkManager.Request, this._onRequest.bind(this)),
helper.addEventListener(this._frameManager.networkManager(), Events.NetworkManager.Request, this._onRequest.bind(this)),
];

@@ -55,0 +54,0 @@

@@ -19,3 +19,2 @@ /**

const {Events} = require('./Events');
const Multimap = require('./Multimap');

@@ -26,5 +25,6 @@ class NetworkManager extends EventEmitter {

*/
constructor(client) {
constructor(client, ignoreHTTPSErrors) {
super();
this._client = client;
this._ignoreHTTPSErrors = ignoreHTTPSErrors;
this._frameManager = null;

@@ -46,9 +46,9 @@ /** @type {!Map<string, !Request>} */

this._protocolRequestInterceptionEnabled = false;
/** @type {!Multimap<string, string>} */
this._requestHashToRequestIds = new Multimap();
/** @type {!Multimap<string, string>} */
this._requestHashToInterceptionIds = new Multimap();
this._userCacheDisabled = false;
/** @type {!Map<string, string>} */
this._requestIdToInterceptionId = new Map();
this._client.on('Fetch.requestPaused', this._onRequestPaused.bind(this));
this._client.on('Fetch.authRequired', this._onAuthRequired.bind(this));
this._client.on('Network.requestWillBeSent', this._onRequestWillBeSent.bind(this));
this._client.on('Network.requestIntercepted', this._onRequestIntercepted.bind(this));
this._client.on('Network.requestServedFromCache', this._onRequestServedFromCache.bind(this));

@@ -60,2 +60,34 @@ this._client.on('Network.responseReceived', this._onResponseReceived.bind(this));

/* async */ initialize() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._client.send('Network.enable'));
if (this._ignoreHTTPSErrors)
(yield this._client.send('Security.setIgnoreCertificateErrors', {ignore: true}));
});}
/**

@@ -224,2 +256,36 @@ * @param {!Puppeteer.FrameManager} frameManager

/**
* @param {boolean} enabled
*/
/* async */ setCacheEnabled(enabled) {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
this._userCacheDisabled = !enabled;
(yield this._updateProtocolCacheDisabled());
});}
/**
* @param {boolean} value

@@ -289,9 +355,50 @@ */

this._protocolRequestInterceptionEnabled = enabled;
const patterns = enabled ? [{urlPattern: '*'}] : [];
(yield Promise.all([
this._client.send('Network.setCacheDisabled', {cacheDisabled: enabled}),
this._client.send('Network.setRequestInterception', {patterns})
]));
if (enabled) {
(yield Promise.all([
this._updateProtocolCacheDisabled(),
this._client.send('Fetch.enable', {
handleAuthRequests: true,
patterns: [{urlPattern: '*'}],
}),
]));
} else {
(yield Promise.all([
this._updateProtocolCacheDisabled(),
this._client.send('Fetch.disable')
]));
}
});}
/* async */ _updateProtocolCacheDisabled() {return (fn => {
const gen = fn.call(this);
return new Promise((resolve, reject) => {
function step(key, arg) {
let info, value;
try {
info = gen[key](arg);
value = info.value;
} catch (error) {
reject(error);
return;
}
if (info.done) {
resolve(value);
} else {
return Promise.resolve(value).then(
value => {
step('next', value);
},
err => {
step('throw', err);
});
}
}
return step('next');
});
})(function*(){
(yield this._client.send('Network.setCacheDisabled', {
cacheDisabled: this._userCacheDisabled || this._protocolRequestInterceptionEnabled
}));
});}
/**

@@ -303,9 +410,8 @@ * @param {!Protocol.Network.requestWillBeSentPayload} event

if (this._protocolRequestInterceptionEnabled && !event.request.url.startsWith('data:')) {
const requestHash = generateRequestHash(event.request);
const interceptionId = this._requestHashToInterceptionIds.firstValue(requestHash);
const requestId = event.requestId;
const interceptionId = this._requestIdToInterceptionId.get(requestId);
if (interceptionId) {
this._onRequest(event, interceptionId);
this._requestHashToInterceptionIds.delete(requestHash, interceptionId);
this._requestIdToInterceptionId.delete(requestId);
} else {
this._requestHashToRequestIds.set(requestHash, event.requestId);
this._requestIdToRequestWillBeSentEvent.set(event.requestId, event);

@@ -319,36 +425,38 @@ }

/**
* @param {!Protocol.Network.requestInterceptedPayload} event
* @param {!Protocol.Fetch.authRequiredPayload} event
*/
_onRequestIntercepted(event) {
if (event.authChallenge) {
/** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */
let response = 'Default';
if (this._attemptedAuthentications.has(event.interceptionId)) {
response = 'CancelAuth';
} else if (this._credentials) {
response = 'ProvideCredentials';
this._attemptedAuthentications.add(event.interceptionId);
}
const {username, password} = this._credentials || {username: undefined, password: undefined};
this._client.send('Network.continueInterceptedRequest', {
interceptionId: event.interceptionId,
authChallengeResponse: { response, username, password }
}).catch(debugError);
return;
_onAuthRequired(event) {
/** @type {"Default"|"CancelAuth"|"ProvideCredentials"} */
let response = 'Default';
if (this._attemptedAuthentications.has(event.requestId)) {
response = 'CancelAuth';
} else if (this._credentials) {
response = 'ProvideCredentials';
this._attemptedAuthentications.add(event.requestId);
}
const {username, password} = this._credentials || {username: undefined, password: undefined};
this._client.send('Fetch.continueWithAuth', {
requestId: event.requestId,
authChallengeResponse: { response, username, password },
}).catch(debugError);
}
/**
* @param {!Protocol.Fetch.requestPausedPayload} event
*/
_onRequestPaused(event) {
if (!this._userRequestInterceptionEnabled && this._protocolRequestInterceptionEnabled) {
this._client.send('Network.continueInterceptedRequest', {
interceptionId: event.interceptionId
this._client.send('Fetch.continueRequest', {
requestId: event.requestId
}).catch(debugError);
}
const requestHash = generateRequestHash(event.request);
const requestId = this._requestHashToRequestIds.firstValue(requestHash);
if (requestId) {
const requestId = event.networkId;
const interceptionId = event.requestId;
if (requestId && this._requestIdToRequestWillBeSentEvent.has(requestId)) {
const requestWillBeSentEvent = this._requestIdToRequestWillBeSentEvent.get(requestId);
this._onRequest(requestWillBeSentEvent, event.interceptionId);
this._requestHashToRequestIds.delete(requestHash, requestId);
this._onRequest(requestWillBeSentEvent, interceptionId);
this._requestIdToRequestWillBeSentEvent.delete(requestId);
} else {
this._requestHashToInterceptionIds.set(requestHash, event.interceptionId);
this._requestIdToInterceptionId.set(requestId, interceptionId);
}

@@ -601,8 +709,8 @@ }

this._interceptionHandled = true;
(yield this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
(yield this._client.send('Fetch.continueRequest', {
requestId: this._interceptionId,
url,
method,
postData,
headers,
headers: headers ? headersArray(headers) : undefined,
}).catch(error => {

@@ -654,2 +762,3 @@ // In certain cases, protocol will return error if the request was already canceled

/** @type {!Object<string, string>} */
const responseHeaders = {};

@@ -663,20 +772,9 @@ if (response.headers) {

if (responseBody && !('content-length' in responseHeaders))
responseHeaders['content-length'] = Buffer.byteLength(responseBody);
responseHeaders['content-length'] = String(Buffer.byteLength(responseBody));
const statusCode = response.status || 200;
const statusText = statusTexts[statusCode] || '';
const statusLine = `HTTP/1.1 ${statusCode} ${statusText}`;
const CRLF = '\r\n';
let text = statusLine + CRLF;
for (const header of Object.keys(responseHeaders))
text += header + ': ' + responseHeaders[header] + CRLF;
text += CRLF;
let responseBuffer = Buffer.from(text, 'utf8');
if (responseBody)
responseBuffer = Buffer.concat([responseBuffer, responseBody]);
(yield this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
rawResponse: responseBuffer.toString('base64')
(yield this._client.send('Fetch.fulfillRequest', {
requestId: this._interceptionId,
responseCode: response.status || 200,
responseHeaders: headersArray(responseHeaders),
body: responseBody ? responseBody.toString('base64') : undefined,
}).catch(error => {

@@ -727,4 +825,4 @@ // In certain cases, protocol will return error if the request was already canceled

this._interceptionHandled = true;
(yield this._client.send('Network.continueInterceptedRequest', {
interceptionId: this._interceptionId,
(yield this._client.send('Fetch.failRequest', {
requestId: this._interceptionId,
errorReason

@@ -975,38 +1073,2 @@ }).catch(error => {

const IGNORED_HEADERS = new Set(['accept', 'referer', 'x-devtools-emulate-network-conditions-client-id', 'cookie', 'origin', 'content-type', 'intervention']);
/**
* @param {!Protocol.Network.Request} request
* @return {string}
*/
function generateRequestHash(request) {
let normalizedURL = request.url;
try {
// Decoding is necessary to normalize URLs. @see crbug.com/759388
// The method will throw if the URL is malformed. In this case,
// consider URL to be normalized as-is.
normalizedURL = decodeURI(request.url);
} catch (e) {
}
const hash = {
url: normalizedURL,
method: request.method,
postData: request.postData,
headers: {},
};
if (!normalizedURL.startsWith('data:')) {
const headers = Object.keys(request.headers);
headers.sort();
for (let header of headers) {
const headerValue = request.headers[header];
header = header.toLowerCase();
if (IGNORED_HEADERS.has(header))
continue;
hash.headers[header] = headerValue;
}
}
return JSON.stringify(hash);
}
class SecurityDetails {

@@ -1060,65 +1122,13 @@ /**

const statusTexts = {
'100': 'Continue',
'101': 'Switching Protocols',
'102': 'Processing',
'200': 'OK',
'201': 'Created',
'202': 'Accepted',
'203': 'Non-Authoritative Information',
'204': 'No Content',
'206': 'Partial Content',
'207': 'Multi-Status',
'208': 'Already Reported',
'209': 'IM Used',
'300': 'Multiple Choices',
'301': 'Moved Permanently',
'302': 'Found',
'303': 'See Other',
'304': 'Not Modified',
'305': 'Use Proxy',
'306': 'Switch Proxy',
'307': 'Temporary Redirect',
'308': 'Permanent Redirect',
'400': 'Bad Request',
'401': 'Unauthorized',
'402': 'Payment Required',
'403': 'Forbidden',
'404': 'Not Found',
'405': 'Method Not Allowed',
'406': 'Not Acceptable',
'407': 'Proxy Authentication Required',
'408': 'Request Timeout',
'409': 'Conflict',
'410': 'Gone',
'411': 'Length Required',
'412': 'Precondition Failed',
'413': 'Payload Too Large',
'414': 'URI Too Long',
'415': 'Unsupported Media Type',
'416': 'Range Not Satisfiable',
'417': 'Expectation Failed',
'418': 'I\'m a teapot',
'421': 'Misdirected Request',
'422': 'Unprocessable Entity',
'423': 'Locked',
'424': 'Failed Dependency',
'426': 'Upgrade Required',
'428': 'Precondition Required',
'429': 'Too Many Requests',
'431': 'Request Header Fields Too Large',
'451': 'Unavailable For Legal Reasons',
'500': 'Internal Server Error',
'501': 'Not Implemented',
'502': 'Bad Gateway',
'503': 'Service Unavailable',
'504': 'Gateway Timeout',
'505': 'HTTP Version Not Supported',
'506': 'Variant Also Negotiates',
'507': 'Insufficient Storage',
'508': 'Loop Detected',
'510': 'Not Extended',
'511': 'Network Authentication Required',
};
/**
* @param {Object<string, string>} headers
* @return {!Array<{name: string, value: string}>}
*/
function headersArray(headers) {
const result = [];
for (const name in headers)
result.push({name, value: headers[name]});
return result;
}
module.exports = {Request, Response, NetworkManager, SecurityDetails};

@@ -18,2 +18,4 @@ /**

const BrowserFetcher = require('./BrowserFetcher');
const Errors = require('./Errors');
const DeviceDescriptors = require('./DeviceDescriptors');

@@ -55,2 +57,16 @@ module.exports = class {

/**
* @return {Object}
*/
get devices() {
return DeviceDescriptors;
}
/**
* @return {Object}
*/
get errors() {
return Errors;
}
/**
* @param {!Launcher.ChromeArgOptions=} options

@@ -57,0 +73,0 @@ * @return {!Array<string>}

{
"name": "puppeteer-core",
"version": "1.14.0",
"version": "1.15.0",
"description": "A high-level API to control headless Chrome over the DevTools Protocol",

@@ -11,3 +11,3 @@ "main": "index.js",

"puppeteer": {
"chromium_revision": "641577"
"chromium_revision": "650583"
},

@@ -14,0 +14,0 @@ "scripts": {

@@ -9,3 +9,3 @@ # Puppeteer

###### [API](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/GoogleChrome/puppeteer/blob/master/CONTRIBUTING.md) | [Troubleshooting](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md)
###### [API](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md) | [FAQ](#faq) | [Contributing](https://github.com/GoogleChrome/puppeteer/blob/master/CONTRIBUTING.md) | [Troubleshooting](https://github.com/GoogleChrome/puppeteer/blob/master/docs/troubleshooting.md)

@@ -41,3 +41,3 @@ > Puppeteer is a Node library which provides a high-level API to control Chrome or Chromium over the [DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). Puppeteer runs [headless](https://developers.google.com/web/updates/2017/04/headless-chrome) by default, but can be configured to run full (non-headless) Chrome or Chromium.

Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, see [Environment variables](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#environment-variables).
Note: When you install Puppeteer, it downloads a recent version of Chromium (~170MB Mac, ~282MB Linux, ~280MB Win) that is guaranteed to work with the API. To skip the download, see [Environment variables](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#environment-variables).

@@ -65,3 +65,3 @@

Puppeteer will be familiar to people using other browser testing frameworks. You create an instance
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#).
of `Browser`, open pages, and then manipulate them with [Puppeteer's API](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#).

@@ -91,3 +91,3 @@ **Example** - navigating to https://example.com and saving a screenshot as *example.png*:

Puppeteer sets an initial page size to 800px x 600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#pagesetviewportviewport).
Puppeteer sets an initial page size to 800px x 600px, which defines the screenshot size. The page size can be customized with [`Page.setViewport()`](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#pagesetviewportviewport).

@@ -117,3 +117,3 @@ **Example** - create a PDF.

See [`Page.pdf()`](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.
See [`Page.pdf()`](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#pagepdfoptions) for more information about creating pdfs.

@@ -153,3 +153,3 @@ **Example** - evaluate script in the context of the page

See [`Page.evaluate()`](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.
See [`Page.evaluate()`](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#pageevaluatepagefunction-args) for more information on `evaluate` and related methods like `evaluateOnNewDocument` and `exposeFunction`.

@@ -163,3 +163,3 @@ <!-- [END getstarted] -->

Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the ['headless' option](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#puppeteerlaunchoptions) when launching a browser:
Puppeteer launches Chromium in [headless mode](https://developers.google.com/web/updates/2017/04/headless-chrome). To launch a full version of Chromium, set the ['headless' option](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#puppeteerlaunchoptions) when launching a browser:

@@ -180,3 +180,3 @@ ```js

See [`Puppeteer.launch()`](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#puppeteerlaunchoptions) for more information.
See [`Puppeteer.launch()`](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#puppeteerlaunchoptions) for more information.

@@ -193,3 +193,3 @@ See [`this article`](https://www.howtogeek.com/202825/what%E2%80%99s-the-difference-between-chromium-and-chrome/) for a description of the differences between Chromium and Chrome. [`This article`](https://chromium.googlesource.com/chromium/src/+/master/docs/chromium_browser_vs_google_chrome.md) describes some differences for Linux users.

- [API Documentation](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md)
- [API Documentation](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md)
- [Examples](https://github.com/GoogleChrome/puppeteer/tree/master/examples/)

@@ -250,8 +250,4 @@ - [Community list of Puppeteer resources](https://github.com/transitive-bullshit/awesome-puppeteer)

# Debug output can be enabled/disabled by namespace
env DEBUG="puppeteer:protocol" node script.js # protocol connection messages
env DEBUG="puppeteer:session" node script.js # protocol session messages (protocol messages to targets)
# Protocol traffic can be rather noisy. This example filters out all Network domain messages
env DEBUG="puppeteer:session" env DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'
env DEBUG="puppeteer:*" env DEBUG_COLORS=true node script.js 2>&1 | grep -v '"Network'

@@ -365,3 +361,3 @@ 6. Debug your Puppeteer (node) code easily, using [ndb](https://github.com/GoogleChromeLabs/ndb)

* Puppeteer is bundled with Chromium--not Chrome--and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/GoogleChrome/puppeteer/blob/v1.14.0/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
* Puppeteer is bundled with Chromium--not Chrome--and so by default, it inherits all of [Chromium's media-related limitations](https://www.chromium.org/audio-video). This means that Puppeteer does not support licensed formats such as AAC or H.264. (However, it is possible to force Puppeteer to use a separately-installed version Chrome instead of Chromium via the [`executablePath` option to `puppeteer.launch`](https://github.com/GoogleChrome/puppeteer/blob/v1.15.0/docs/api.md#puppeteerlaunchoptions). You should only use this configuration if you need an official release of Chrome that supports these media formats.)
* Since Puppeteer (in all configurations) controls a desktop version of Chromium/Chrome, features that are only supported by the mobile version of Chrome are not supported. This means that Puppeteer [does not support HTTP Live Streaming (HLS)](https://caniuse.com/#feat=http-live-streaming).

@@ -368,0 +364,0 @@

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc