diff options
Diffstat (limited to '')
-rw-r--r-- | remote/test/puppeteer/utils/testserver/LICENSE | 202 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/README.md | 18 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/cert.pem | 20 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/key.pem | 28 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/lib/index.d.ts | 45 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/lib/index.d.ts.map | 1 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/lib/index.js | 261 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/lib/index.js.map | 1 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/package.json | 15 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/src/index.ts | 302 | ||||
-rw-r--r-- | remote/test/puppeteer/utils/testserver/tsconfig.json | 11 |
11 files changed, 904 insertions, 0 deletions
diff --git a/remote/test/puppeteer/utils/testserver/LICENSE b/remote/test/puppeteer/utils/testserver/LICENSE new file mode 100644 index 0000000000..afdfe50e72 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2017 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/remote/test/puppeteer/utils/testserver/README.md b/remote/test/puppeteer/utils/testserver/README.md new file mode 100644 index 0000000000..d22b2da449 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/README.md @@ -0,0 +1,18 @@ +# TestServer + +This test server is used internally by Puppeteer to test Puppeteer itself. + +### Example + +```ts +const {TestServer} = require('@pptr/testserver'); + +(async(() => { + const httpServer = await TestServer.create(__dirname, 8000), + const httpsServer = await TestServer.createHTTPS(__dirname, 8001) + httpServer.setRoute('/hello', (req, res) => { + res.end('Hello, world!'); + }); + console.log('HTTP and HTTPS servers are running!'); +})(); +``` diff --git a/remote/test/puppeteer/utils/testserver/cert.pem b/remote/test/puppeteer/utils/testserver/cert.pem new file mode 100644 index 0000000000..fd3838535a --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/cert.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDWDCCAkCgAwIBAgIUM8Tmw+D1j+eVz9x9So4zRVqFsKowDQYJKoZIhvcNAQEL +BQAwGjEYMBYGA1UEAwwPcHVwcGV0ZWVyLXRlc3RzMB4XDTIwMDUxMzA4MDQyOVoX +DTMwMDUxMTA4MDQyOVowGjEYMBYGA1UEAwwPcHVwcGV0ZWVyLXRlc3RzMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEApWbbhgc6CnWywd8xGETT1mfLi3wi +KIbpAUHghLF4sj0jXz8vLh/4oicpQ12d6bsz+IAi7qrdXNh11P5nEej6/Gx4fWzB +gGdrJFGPqsvXuhYdzZAmy6xOaWcLIJeQ543bXv3YeST7EGRXJBc/ocTo2jIGTGjq +hksFaid910VQlX3KGOLTDMUCk00TeEYBTTUx47PWoIsxVqbl2RzVXRSWL5hlPWlW +29/BQtBGmsXxZyWtqqHudiUulGBSr4LcPyicZLI8nqCqD0ioS0TEmGh61nRBuwBa +xmLCvPmpt0+sDuOU+1bme3w8juvTVToBIFxGB86rADd3ys+8NeZzXqi+bQIDAQAB +o4GVMIGSMB0GA1UdDgQWBBT/m3vdkZpQyVQFdYrKHVoAHXDFODAfBgNVHSMEGDAW +gBT/m3vdkZpQyVQFdYrKHVoAHXDFODAPBgNVHRMBAf8EBTADAQH/MD8GA1UdEQQ4 +MDaCGHd3dy5wdXBwZXRlZXItdGVzdHMudGVzdIIad3d3LnB1cHBldGVlci10ZXN0 +cy0xLnRlc3QwDQYJKoZIhvcNAQELBQADggEBAI1qp5ZppV1R3e8XxzwwkFDPFN8W +Pe3AoqhAKyJnJl1NUn9q3sroEeSQRhODWUHCd7lENzhsT+3mzonNNkN9B/hq0rpK +KHHczXILDqdyuxH3LxQ1VHGE8VN2NbdkfobtzAsA3woiJxOuGeusXJnKB4kJQeIP +V+BMEZWeaSDC2PREkG7GOezmE1/WDUCYaorPw2whdCA5wJvTW3zXpJjYhfsld+5z +KuErx4OCxRJij73/BD9SpLxDEY1cdl819F1IvxsRGhmTIaSly2hQLrhOgo1jgZtV +FGCa6DSlXnQGLaV+N+ssR0lkCksNrNBVDfA1bP5bT/4VCcwUWwm9TUeF0Qo= +-----END CERTIFICATE----- diff --git a/remote/test/puppeteer/utils/testserver/key.pem b/remote/test/puppeteer/utils/testserver/key.pem new file mode 100644 index 0000000000..cbc3acb229 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/key.pem @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQClZtuGBzoKdbLB +3zEYRNPWZ8uLfCIohukBQeCEsXiyPSNfPy8uH/iiJylDXZ3puzP4gCLuqt1c2HXU +/mcR6Pr8bHh9bMGAZ2skUY+qy9e6Fh3NkCbLrE5pZwsgl5Dnjdte/dh5JPsQZFck +Fz+hxOjaMgZMaOqGSwVqJ33XRVCVfcoY4tMMxQKTTRN4RgFNNTHjs9agizFWpuXZ +HNVdFJYvmGU9aVbb38FC0EaaxfFnJa2qoe52JS6UYFKvgtw/KJxksjyeoKoPSKhL +RMSYaHrWdEG7AFrGYsK8+am3T6wO45T7VuZ7fDyO69NVOgEgXEYHzqsAN3fKz7w1 +5nNeqL5tAgMBAAECggEAKPveo0xBHnxhidZzBM9xKixX7D0a/a3IKI6ZQmfzPz8U +97HhT+2OHyfS+qVEzribPRULEtZ1uV7Ne7R5958iKc/63yFGpTl6++nVzn1p++sl +AV2Zr1gHqehlgnLr7eRhmh0OOZ5nM32ZdhDorH3tMLu6gc5xZktKkS4t6Vx8hj3a +Docx+rbawp8GRd0p7I6vzIE3bsDab8hC+RTRO63q2G0BqgKwV9ZNtJxQgcDJ5L8N +6gtM2z5nKXAIOCbCQYa1PsrDh3IRA/ZNxEeA9G3YQjwlZYCWmdRRplgDraYxcTBO +oQGjaLwICNdcprMacPD6cCSgrI+PadzyMsAuk9SgpQKBgQDO9PT4gK40Pm+Damxv ++tWYBFmvn3vasmyolc1zVDltsxQbQTjKhVpTLXTTGmrIhDXEIIV9I4rg164WptQs +6Brp2EwYR7ZJIrjvXs/9i2QTW1ZXvhdiWpB3s+RXD5VHGovHUadcI6wOgw2Cl+Jk +zXjSIgyXKM99N1MAonuR7DyzTwKBgQDMmPX+9vWZMpS/gc6JLQiPPoGszE6tYjXg +W3LpRUNqmO0/bDDjslbebDgrGAmhlkJlxzH6gz96VmGm1evEGPEet3euy8S9zuM3 +LCgEM9Ulqa3JbInwtKupmKv76Im+XWLLSxAXbfiel1zFRRwxI99A3ad0QRZ6Bov5 +3cHJBwvzgwKBgAU5HW2gIcVjxgC1EOOKmxVpFrJd/gw48JEYpsTAXWqtWFaPwNUr +pGnw/b/OLN++pnS6tWPBH+Ioz1X3A+fWO8enE9SRCsKxw6UW6XzmpbHvXjB8ta5f +xsGeoqan2AahXuG659RlehQrro2bM7WDkgcLoPG3r/TjDo83ipLWOXn1AoGAKWiL +4R56dpcWI+xRsNG8ecFc3Ww8QDswTEg16aBrFJf+7GcpPexKSJn+hDpJOLsAlTjL +lLgbkNcKzIlfPkEOC/l175quJvxIYFI/hxo2eXjuA2ZERMNMOvb7V/CocC7WX+7B +Qvyu5OodjI+ANTHdbXNvAMhrlCbfDaMkJVuXv6ECgYBzvY4aYmVoFsr+72/EfLls +Dz9pi55tUUWc61w6ovd+iliawvXeGi4wibtTH4iGj/C2sJIaMmOD99NQ7Oi/x89D +oMgSUemkoFL8FGsZGyZ7szqxyON1jP42Bm2MQrW5kIf7Y4yaIGhoak5JNxn2JUyV +gupVbY1mQ1GTPByxHeLh1w== +-----END PRIVATE KEY----- diff --git a/remote/test/puppeteer/utils/testserver/lib/index.d.ts b/remote/test/puppeteer/utils/testserver/lib/index.d.ts new file mode 100644 index 0000000000..055c9863d7 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/lib/index.d.ts @@ -0,0 +1,45 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/// <reference types="node" /> +/// <reference types="node" /> +import { IncomingMessage, ServerResponse } from 'http'; +import { ServerOptions as HttpsServerOptions } from 'https'; +declare type TestIncomingMessage = IncomingMessage & { + postBody?: Promise<string>; +}; +export declare class TestServer { + #private; + PORT: number; + PREFIX: string; + CROSS_PROCESS_PREFIX: string; + EMPTY_PAGE: string; + static create(dirPath: string): Promise<TestServer>; + static createHTTPS(dirPath: string): Promise<TestServer>; + constructor(dirPath: string, sslOptions?: HttpsServerOptions); + get port(): number; + enableHTTPCache(pathPrefix: string): void; + setAuth(path: string, username: string, password: string): void; + enableGzip(path: string): void; + setCSP(path: string, csp: string): void; + stop(): Promise<void>; + setRoute(path: string, handler: (req: IncomingMessage, res: ServerResponse) => void): void; + setRedirect(from: string, to: string): void; + waitForRequest(path: string): Promise<TestIncomingMessage>; + reset(): void; + serveFile(request: IncomingMessage, response: ServerResponse, pathName: string): void; +} +export {}; +//# sourceMappingURL=index.d.ts.map
\ No newline at end of file diff --git a/remote/test/puppeteer/utils/testserver/lib/index.d.ts.map b/remote/test/puppeteer/utils/testserver/lib/index.d.ts.map new file mode 100644 index 0000000000..a2c07af2df --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/lib/index.d.ts.map @@ -0,0 +1 @@ +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;;;AAIH,OAAO,EAEL,eAAe,EAGf,cAAc,EACf,MAAM,MAAM,CAAC;AACd,OAAO,EAGL,aAAa,IAAI,kBAAkB,EACpC,MAAM,OAAO,CAAC;AAcf,aAAK,mBAAmB,GAAG,eAAe,GAAG;IAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,CAAA;CAAC,CAAC;AAE1E,qBAAa,UAAU;;IACrB,IAAI,EAAG,MAAM,CAAC;IACd,MAAM,EAAG,MAAM,CAAC;IAChB,oBAAoB,EAAG,MAAM,CAAC;IAC9B,UAAU,EAAG,MAAM,CAAC;WAmBP,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;WAY5C,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;gBAgBlD,OAAO,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,kBAAkB;IA2B5D,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAIzC,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,IAAI;IAI/D,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAI9B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,IAAI;IAIjC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B,QAAQ,CACN,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,KAAK,IAAI,GAC3D,IAAI;IAIP,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAO3C,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAe1D,KAAK,IAAI,IAAI;IA8Db,SAAS,CACP,OAAO,EAAE,eAAe,EACxB,QAAQ,EAAE,cAAc,EACxB,QAAQ,EAAE,MAAM,GACf,IAAI;CAoDR"}
\ No newline at end of file diff --git a/remote/test/puppeteer/utils/testserver/lib/index.js b/remote/test/puppeteer/utils/testserver/lib/index.js new file mode 100644 index 0000000000..8cfcc71139 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/lib/index.js @@ -0,0 +1,261 @@ +"use strict"; +/** + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { + if (kind === "m") throw new TypeError("Private method is not writable"); + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); + return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; +}; +var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +}; +var __importDefault = (this && this.__importDefault) || function (mod) { + return (mod && mod.__esModule) ? mod : { "default": mod }; +}; +var _TestServer_dirPath, _TestServer_server, _TestServer_wsServer, _TestServer_startTime, _TestServer_cachedPathPrefix, _TestServer_connections, _TestServer_routes, _TestServer_auths, _TestServer_csp, _TestServer_gzipRoutes, _TestServer_requestSubscribers, _TestServer_onServerConnection, _TestServer_onRequest, _TestServer_onWebSocketConnection; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.TestServer = void 0; +const assert_1 = __importDefault(require("assert")); +const fs_1 = require("fs"); +const http_1 = require("http"); +const https_1 = require("https"); +const mime_1 = require("mime"); +const path_1 = require("path"); +const ws_1 = require("ws"); +const zlib_1 = require("zlib"); +class TestServer { + constructor(dirPath, sslOptions) { + _TestServer_dirPath.set(this, void 0); + _TestServer_server.set(this, void 0); + _TestServer_wsServer.set(this, void 0); + _TestServer_startTime.set(this, new Date()); + _TestServer_cachedPathPrefix.set(this, void 0); + _TestServer_connections.set(this, new Set()); + _TestServer_routes.set(this, new Map()); + _TestServer_auths.set(this, new Map()); + _TestServer_csp.set(this, new Map()); + _TestServer_gzipRoutes.set(this, new Set()); + _TestServer_requestSubscribers.set(this, new Map()); + _TestServer_onServerConnection.set(this, (connection) => { + __classPrivateFieldGet(this, _TestServer_connections, "f").add(connection); + // ECONNRESET is a legit error given + // that tab closing simply kills process. + connection.on('error', error => { + if (error.code !== 'ECONNRESET') { + throw error; + } + }); + connection.once('close', () => { + return __classPrivateFieldGet(this, _TestServer_connections, "f").delete(connection); + }); + }); + _TestServer_onRequest.set(this, (request, response) => { + request.on('error', (error) => { + if (error.code === 'ECONNRESET') { + response.end(); + } + else { + throw error; + } + }); + request.postBody = new Promise(resolve => { + let body = ''; + request.on('data', (chunk) => { + return (body += chunk); + }); + request.on('end', () => { + return resolve(body); + }); + }); + (0, assert_1.default)(request.url); + const url = new URL(request.url, `https://${request.headers.host}`); + const path = url.pathname + url.search; + const auth = __classPrivateFieldGet(this, _TestServer_auths, "f").get(path); + if (auth) { + const credentials = Buffer.from((request.headers.authorization || '').split(' ')[1] || '', 'base64').toString(); + if (credentials !== `${auth.username}:${auth.password}`) { + response.writeHead(401, { + 'WWW-Authenticate': 'Basic realm="Secure Area"', + }); + response.end('HTTP Error 401 Unauthorized: Access is denied'); + return; + } + } + const subscriber = __classPrivateFieldGet(this, _TestServer_requestSubscribers, "f").get(path); + if (subscriber) { + subscriber.resolve.call(undefined, request); + __classPrivateFieldGet(this, _TestServer_requestSubscribers, "f").delete(path); + } + const handler = __classPrivateFieldGet(this, _TestServer_routes, "f").get(path); + if (handler) { + handler.call(undefined, request, response); + } + else { + this.serveFile(request, response, path); + } + }); + _TestServer_onWebSocketConnection.set(this, (socket) => { + socket.send('opened'); + }); + __classPrivateFieldSet(this, _TestServer_dirPath, dirPath, "f"); + if (sslOptions) { + __classPrivateFieldSet(this, _TestServer_server, (0, https_1.createServer)(sslOptions, __classPrivateFieldGet(this, _TestServer_onRequest, "f")), "f"); + } + else { + __classPrivateFieldSet(this, _TestServer_server, (0, http_1.createServer)(__classPrivateFieldGet(this, _TestServer_onRequest, "f")), "f"); + } + __classPrivateFieldGet(this, _TestServer_server, "f").on('connection', __classPrivateFieldGet(this, _TestServer_onServerConnection, "f")); + __classPrivateFieldSet(this, _TestServer_wsServer, new ws_1.Server({ server: __classPrivateFieldGet(this, _TestServer_server, "f") }), "f"); + __classPrivateFieldGet(this, _TestServer_wsServer, "f").on('connection', __classPrivateFieldGet(this, _TestServer_onWebSocketConnection, "f")); + } + static async create(dirPath) { + let res; + const promise = new Promise(resolve => { + res = resolve; + }); + const server = new TestServer(dirPath); + __classPrivateFieldGet(server, _TestServer_server, "f").once('listening', res); + __classPrivateFieldGet(server, _TestServer_server, "f").listen(0); + await promise; + return server; + } + static async createHTTPS(dirPath) { + let res; + const promise = new Promise(resolve => { + res = resolve; + }); + const server = new TestServer(dirPath, { + key: (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'key.pem')), + cert: (0, fs_1.readFileSync)((0, path_1.join)(__dirname, '..', 'cert.pem')), + passphrase: 'aaaa', + }); + __classPrivateFieldGet(server, _TestServer_server, "f").once('listening', res); + __classPrivateFieldGet(server, _TestServer_server, "f").listen(0); + await promise; + return server; + } + get port() { + return __classPrivateFieldGet(this, _TestServer_server, "f").address().port; + } + enableHTTPCache(pathPrefix) { + __classPrivateFieldSet(this, _TestServer_cachedPathPrefix, pathPrefix, "f"); + } + setAuth(path, username, password) { + __classPrivateFieldGet(this, _TestServer_auths, "f").set(path, { username, password }); + } + enableGzip(path) { + __classPrivateFieldGet(this, _TestServer_gzipRoutes, "f").add(path); + } + setCSP(path, csp) { + __classPrivateFieldGet(this, _TestServer_csp, "f").set(path, csp); + } + async stop() { + this.reset(); + for (const socket of __classPrivateFieldGet(this, _TestServer_connections, "f")) { + socket.destroy(); + } + __classPrivateFieldGet(this, _TestServer_connections, "f").clear(); + await new Promise(x => { + return __classPrivateFieldGet(this, _TestServer_server, "f").close(x); + }); + } + setRoute(path, handler) { + __classPrivateFieldGet(this, _TestServer_routes, "f").set(path, handler); + } + setRedirect(from, to) { + this.setRoute(from, (_, res) => { + res.writeHead(302, { location: to }); + res.end(); + }); + } + waitForRequest(path) { + const subscriber = __classPrivateFieldGet(this, _TestServer_requestSubscribers, "f").get(path); + if (subscriber) { + return subscriber.promise; + } + let resolve; + let reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + __classPrivateFieldGet(this, _TestServer_requestSubscribers, "f").set(path, { resolve, reject, promise }); + return promise; + } + reset() { + __classPrivateFieldGet(this, _TestServer_routes, "f").clear(); + __classPrivateFieldGet(this, _TestServer_auths, "f").clear(); + __classPrivateFieldGet(this, _TestServer_csp, "f").clear(); + __classPrivateFieldGet(this, _TestServer_gzipRoutes, "f").clear(); + const error = new Error('Static Server has been reset'); + for (const subscriber of __classPrivateFieldGet(this, _TestServer_requestSubscribers, "f").values()) { + subscriber.reject.call(undefined, error); + } + __classPrivateFieldGet(this, _TestServer_requestSubscribers, "f").clear(); + } + serveFile(request, response, pathName) { + if (pathName === '/') { + pathName = '/index.html'; + } + const filePath = (0, path_1.join)(__classPrivateFieldGet(this, _TestServer_dirPath, "f"), pathName.substring(1)); + if (__classPrivateFieldGet(this, _TestServer_cachedPathPrefix, "f") && filePath.startsWith(__classPrivateFieldGet(this, _TestServer_cachedPathPrefix, "f"))) { + if (request.headers['if-modified-since']) { + response.statusCode = 304; // not modified + response.end(); + return; + } + response.setHeader('Cache-Control', 'public, max-age=31536000'); + response.setHeader('Last-Modified', __classPrivateFieldGet(this, _TestServer_startTime, "f").toISOString()); + } + else { + response.setHeader('Cache-Control', 'no-cache, no-store'); + } + const csp = __classPrivateFieldGet(this, _TestServer_csp, "f").get(pathName); + if (csp) { + response.setHeader('Content-Security-Policy', csp); + } + (0, fs_1.readFile)(filePath, (err, data) => { + if (err) { + response.statusCode = 404; + response.end(`File not found: ${filePath}`); + return; + } + const mimeType = (0, mime_1.getType)(filePath); + if (mimeType) { + const isTextEncoding = /^text\/|^application\/(javascript|json)/.test(mimeType); + const contentType = isTextEncoding + ? `${mimeType}; charset=utf-8` + : mimeType; + response.setHeader('Content-Type', contentType); + } + if (__classPrivateFieldGet(this, _TestServer_gzipRoutes, "f").has(pathName)) { + response.setHeader('Content-Encoding', 'gzip'); + (0, zlib_1.gzip)(data, (_, result) => { + response.end(result); + }); + } + else { + response.end(data); + } + }); + } +} +exports.TestServer = TestServer; +_TestServer_dirPath = new WeakMap(), _TestServer_server = new WeakMap(), _TestServer_wsServer = new WeakMap(), _TestServer_startTime = new WeakMap(), _TestServer_cachedPathPrefix = new WeakMap(), _TestServer_connections = new WeakMap(), _TestServer_routes = new WeakMap(), _TestServer_auths = new WeakMap(), _TestServer_csp = new WeakMap(), _TestServer_gzipRoutes = new WeakMap(), _TestServer_requestSubscribers = new WeakMap(), _TestServer_onServerConnection = new WeakMap(), _TestServer_onRequest = new WeakMap(), _TestServer_onWebSocketConnection = new WeakMap(); +//# sourceMappingURL=index.js.map
\ No newline at end of file diff --git a/remote/test/puppeteer/utils/testserver/lib/index.js.map b/remote/test/puppeteer/utils/testserver/lib/index.js.map new file mode 100644 index 0000000000..2ab772d086 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/lib/index.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
\ No newline at end of file diff --git a/remote/test/puppeteer/utils/testserver/package.json b/remote/test/puppeteer/utils/testserver/package.json new file mode 100644 index 0000000000..1029f16d0a --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/package.json @@ -0,0 +1,15 @@ +{ + "name": "@pptr/testserver", + "version": "0.5.0", + "description": "testing server", + "main": "lib/index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/puppeteer/puppeteer/tree/main/utils/testserver" + }, + "author": "The Chromium Authors", + "license": "Apache-2.0" +} diff --git a/remote/test/puppeteer/utils/testserver/src/index.ts b/remote/test/puppeteer/utils/testserver/src/index.ts new file mode 100644 index 0000000000..c98ed9b4d0 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/src/index.ts @@ -0,0 +1,302 @@ +/** + * Copyright 2017 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import assert from 'assert'; +import {readFile, readFileSync} from 'fs'; +import { + createServer as createHttpServer, + IncomingMessage, + RequestListener, + Server as HttpServer, + ServerResponse, +} from 'http'; +import { + createServer as createHttpsServer, + Server as HttpsServer, + ServerOptions as HttpsServerOptions, +} from 'https'; +import {getType as getMimeType} from 'mime'; +import {AddressInfo} from 'net'; +import {join} from 'path'; +import {Duplex} from 'stream'; +import {Server as WebSocketServer, WebSocket} from 'ws'; +import {gzip} from 'zlib'; + +interface Subscriber { + resolve: (msg: IncomingMessage) => void; + reject: (err?: Error) => void; + promise: Promise<IncomingMessage>; +} + +type TestIncomingMessage = IncomingMessage & {postBody?: Promise<string>}; + +export class TestServer { + PORT!: number; + PREFIX!: string; + CROSS_PROCESS_PREFIX!: string; + EMPTY_PAGE!: string; + + #dirPath: string; + #server: HttpsServer | HttpServer; + #wsServer: WebSocketServer; + + #startTime = new Date(); + #cachedPathPrefix?: string; + + #connections = new Set<Duplex>(); + #routes = new Map< + string, + (msg: IncomingMessage, res: ServerResponse) => void + >(); + #auths = new Map<string, {username: string; password: string}>(); + #csp = new Map<string, string>(); + #gzipRoutes = new Set<string>(); + #requestSubscribers = new Map<string, Subscriber>(); + + static async create(dirPath: string): Promise<TestServer> { + let res!: (value: unknown) => void; + const promise = new Promise(resolve => { + res = resolve; + }); + const server = new TestServer(dirPath); + server.#server.once('listening', res); + server.#server.listen(0); + await promise; + return server; + } + + static async createHTTPS(dirPath: string): Promise<TestServer> { + let res!: (value: unknown) => void; + const promise = new Promise(resolve => { + res = resolve; + }); + const server = new TestServer(dirPath, { + key: readFileSync(join(__dirname, '..', 'key.pem')), + cert: readFileSync(join(__dirname, '..', 'cert.pem')), + passphrase: 'aaaa', + }); + server.#server.once('listening', res); + server.#server.listen(0); + await promise; + return server; + } + + constructor(dirPath: string, sslOptions?: HttpsServerOptions) { + this.#dirPath = dirPath; + + if (sslOptions) { + this.#server = createHttpsServer(sslOptions, this.#onRequest); + } else { + this.#server = createHttpServer(this.#onRequest); + } + this.#server.on('connection', this.#onServerConnection); + this.#wsServer = new WebSocketServer({server: this.#server}); + this.#wsServer.on('connection', this.#onWebSocketConnection); + } + + #onServerConnection = (connection: Duplex): void => { + this.#connections.add(connection); + // ECONNRESET is a legit error given + // that tab closing simply kills process. + connection.on('error', error => { + if ((error as NodeJS.ErrnoException).code !== 'ECONNRESET') { + throw error; + } + }); + connection.once('close', () => { + return this.#connections.delete(connection); + }); + }; + + get port(): number { + return (this.#server.address() as AddressInfo).port; + } + + enableHTTPCache(pathPrefix: string): void { + this.#cachedPathPrefix = pathPrefix; + } + + setAuth(path: string, username: string, password: string): void { + this.#auths.set(path, {username, password}); + } + + enableGzip(path: string): void { + this.#gzipRoutes.add(path); + } + + setCSP(path: string, csp: string): void { + this.#csp.set(path, csp); + } + + async stop(): Promise<void> { + this.reset(); + for (const socket of this.#connections) { + socket.destroy(); + } + this.#connections.clear(); + await new Promise(x => { + return this.#server.close(x); + }); + } + + setRoute( + path: string, + handler: (req: IncomingMessage, res: ServerResponse) => void + ): void { + this.#routes.set(path, handler); + } + + setRedirect(from: string, to: string): void { + this.setRoute(from, (_, res) => { + res.writeHead(302, {location: to}); + res.end(); + }); + } + + waitForRequest(path: string): Promise<TestIncomingMessage> { + const subscriber = this.#requestSubscribers.get(path); + if (subscriber) { + return subscriber.promise; + } + let resolve!: (value: IncomingMessage) => void; + let reject!: (reason?: Error) => void; + const promise = new Promise<IncomingMessage>((res, rej) => { + resolve = res; + reject = rej; + }); + this.#requestSubscribers.set(path, {resolve, reject, promise}); + return promise; + } + + reset(): void { + this.#routes.clear(); + this.#auths.clear(); + this.#csp.clear(); + this.#gzipRoutes.clear(); + const error = new Error('Static Server has been reset'); + for (const subscriber of this.#requestSubscribers.values()) { + subscriber.reject.call(undefined, error); + } + this.#requestSubscribers.clear(); + } + + #onRequest: RequestListener = ( + request: TestIncomingMessage, + response + ): void => { + request.on('error', (error: {code: string}) => { + if (error.code === 'ECONNRESET') { + response.end(); + } else { + throw error; + } + }); + request.postBody = new Promise(resolve => { + let body = ''; + request.on('data', (chunk: string) => { + return (body += chunk); + }); + request.on('end', () => { + return resolve(body); + }); + }); + assert(request.url); + const url = new URL(request.url, `https://${request.headers.host}`); + const path = url.pathname + url.search; + const auth = this.#auths.get(path); + if (auth) { + const credentials = Buffer.from( + (request.headers.authorization || '').split(' ')[1] || '', + 'base64' + ).toString(); + if (credentials !== `${auth.username}:${auth.password}`) { + response.writeHead(401, { + 'WWW-Authenticate': 'Basic realm="Secure Area"', + }); + response.end('HTTP Error 401 Unauthorized: Access is denied'); + return; + } + } + const subscriber = this.#requestSubscribers.get(path); + if (subscriber) { + subscriber.resolve.call(undefined, request); + this.#requestSubscribers.delete(path); + } + const handler = this.#routes.get(path); + if (handler) { + handler.call(undefined, request, response); + } else { + this.serveFile(request, response, path); + } + }; + + serveFile( + request: IncomingMessage, + response: ServerResponse, + pathName: string + ): void { + if (pathName === '/') { + pathName = '/index.html'; + } + const filePath = join(this.#dirPath, pathName.substring(1)); + + if (this.#cachedPathPrefix && filePath.startsWith(this.#cachedPathPrefix)) { + if (request.headers['if-modified-since']) { + response.statusCode = 304; // not modified + response.end(); + return; + } + response.setHeader('Cache-Control', 'public, max-age=31536000'); + response.setHeader('Last-Modified', this.#startTime.toISOString()); + } else { + response.setHeader('Cache-Control', 'no-cache, no-store'); + } + const csp = this.#csp.get(pathName); + if (csp) { + response.setHeader('Content-Security-Policy', csp); + } + + readFile(filePath, (err, data) => { + if (err) { + response.statusCode = 404; + response.end(`File not found: ${filePath}`); + return; + } + const mimeType = getMimeType(filePath); + if (mimeType) { + const isTextEncoding = /^text\/|^application\/(javascript|json)/.test( + mimeType + ); + const contentType = isTextEncoding + ? `${mimeType}; charset=utf-8` + : mimeType; + response.setHeader('Content-Type', contentType); + } + if (this.#gzipRoutes.has(pathName)) { + response.setHeader('Content-Encoding', 'gzip'); + gzip(data, (_, result) => { + response.end(result); + }); + } else { + response.end(data); + } + }); + } + + #onWebSocketConnection = (socket: WebSocket): void => { + socket.send('opened'); + }; +} diff --git a/remote/test/puppeteer/utils/testserver/tsconfig.json b/remote/test/puppeteer/utils/testserver/tsconfig.json new file mode 100644 index 0000000000..c2576c2564 --- /dev/null +++ b/remote/test/puppeteer/utils/testserver/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base.json", + "compilerOptions": { + "allowJs": true, + "composite": true, + "module": "CommonJS", + "outDir": "lib", + "rootDir": "src" + }, + "include": ["src"] +} |