Repository: microsoft/playwright
File: packages/playwright-core/src/server/utils/network.ts (TypeScript)

Code before:

import http from 'http';
import http2 from 'http2';
import https from 'https';

import { HttpsProxyAgent, SocksProxyAgent, getProxyForUrl } from '../../utilsBundle';
import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from './happyEyeballs';
import { ManualPromise } from '../../utils/isomorphic/manualPromise';

import type net from 'net';
import type { ProxySettings } from '../types';
import type { Progress } from '../progress';

export type HTTPRequestParams = {
  url: string,
  method?: string,
  headers?: http.OutgoingHttpHeaders,
  data?: string | Buffer,
  rejectUnauthorized?: boolean,
  socketTimeout?: number,
};

export const NET_DEFAULT_TIMEOUT = 30_000;

export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.IncomingMessage) => void, onError: (error: Error) => void): { cancel(error: Error | undefined): void } {
  let parsedUrl = normalizeURL(params.url);
  const options: https.RequestOptions = {
    method: params.method || 'GET',
    headers: params.headers,
  };
  if (params.rejectUnauthorized !== undefined)
    options.rejectUnauthorized = params.rejectUnauthorized;

  const proxyURL = getProxyForUrl(params.url);
  if (proxyURL) {
    if (params.url.startsWith('http:')) {
      const parsedProxyURL = normalizeURL(proxyURL);
      parsedProxyURL.pathname = parsedUrl.toString();
      parsedUrl = parsedProxyURL;
    } else {
      options.agent = new HttpsProxyAgent(normalizeURL(proxyURL));
      options.rejectUnauthorized = false;
    }
  }

  options.agent ??= parsedUrl.protocol === 'https:' ? httpsHappyEyeballsAgent : httpHappyEyeballsAgent;

  let cancelRequest: (e: Error | undefined) => void;
  const requestCallback = (res: http.IncomingMessage) => {
    const statusCode = res.statusCode || 0;
    if (statusCode >= 300 && statusCode < 400 && res.headers.location) {

Review comment (suggestion):
I don't think `url.parse()` used to add `http://` scheme, but `normalizeURL` does.

Code after:

import http from 'http';
import http2 from 'http2';
import https from 'https';

import { HttpsProxyAgent, SocksProxyAgent, getProxyForUrl } from '../../utilsBundle';
import { httpHappyEyeballsAgent, httpsHappyEyeballsAgent } from './happyEyeballs';
import { ManualPromise } from '../../utils/isomorphic/manualPromise';

import type net from 'net';
import type { ProxySettings } from '../types';
import type { Progress } from '../progress';

export type HTTPRequestParams = {
  url: string,
  method?: string,
  headers?: http.OutgoingHttpHeaders,
  data?: string | Buffer,
  rejectUnauthorized?: boolean,
  socketTimeout?: number,
};

export const NET_DEFAULT_TIMEOUT = 30_000;

export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.IncomingMessage) => void, onError: (error: Error) => void): { cancel(error: Error | undefined): void } {
  let url = new URL(params.url);
  const options: https.RequestOptions = {
    method: params.method || 'GET',
    headers: params.headers,
  };
  if (params.rejectUnauthorized !== undefined)
    options.rejectUnauthorized = params.rejectUnauthorized;

  const proxyURL = getProxyForUrl(params.url);
  if (proxyURL) {
    const parsedProxyURL = normalizeProxyURL(proxyURL);
    if (params.url.startsWith('http:')) {
      parsedProxyURL.pathname = url.toString();
      url = parsedProxyURL;
    } else {
      options.agent = new HttpsProxyAgent(parsedProxyURL);
      options.rejectUnauthorized = false;
    }
  }

  options.agent ??= url.protocol === 'https:' ? httpsHappyEyeballsAgent : httpHappyEyeballsAgent;

  let cancelRequest: (e: Error | undefined) => void;
  const requestCallback = (res: http.IncomingMessage) => {
    const statusCode = res.statusCode || 0;
    if (statusCode >= 300 && statusCode < 400 && res.headers.location) {