Repository: puppeteer/puppeteer
File: packages/puppeteer-core/src/bidi/BrowserConnector.ts (TypeScript)

Code before:
  } = options;

  // Try pure BiDi first.
  if (browserWSEndpoint !== undefined) {
    const WebSocketClass = await getWebSocketTransportClass();
    const wsTransport: ConnectionTransport =
      await WebSocketClass.create(browserWSEndpoint);
    const BiDi = await import(/* webpackIgnore: true */ './bidi.js');
    const pureBidiConnection = new BiDi.BidiConnection(
      browserWSEndpoint,
      wsTransport,
      slowMo,
      protocolTimeout
    );
    try {
      const result = await pureBidiConnection.send('session.status', {});
      if ('type' in result && result.type === 'success') {
        // The `browserWSEndpoint` points to an endpoint supporting pure WebDriver BiDi.
        return pureBidiConnection;
      }
    } catch (e: any) {
      if (!('name' in e && e.name === 'ProtocolError')) {
        // Unexpected exception not related to BiDi / CDP. Rethrow.
        throw e;
      }
      wsTransport.close();
    }
  }

  // Fall back to CDP over BiDi.
  const cdpConnection = await _getCdpConnection(options);

  const version = await cdpConnection.send('Browser.getVersion');
  if (version.product.toLowerCase().includes('firefox')) {
    throw new UnsupportedOperation(
      'Firefox is not supported in BiDi over CDP mode.'
    );
  }

  // TODO: use other options too.
  const BiDi = await import(/* webpackIgnore: true */ './bidi.js');
  const bidiConnection = await BiDi.connectBidiOverCdp(cdpConnection, {
    acceptInsecureCerts: ignoreHTTPSErrors,
  });
  return bidiConnection;
}


Review comment (suggestion):
Currently this only closes the `wsTransport` if it's expected error. I think we need to close it if any error occurrences.

Code after:
  // Try pure BiDi first.
  const pureBidiConnection = new BiDi.BidiConnection(
    url,
    connectionTransport,
    slowMo,
    protocolTimeout
  );
  try {
    const result = await pureBidiConnection.send('session.status', {});
    if ('type' in result && result.type === 'success') {
      // The `browserWSEndpoint` points to an endpoint supporting pure WebDriver BiDi.
      return {
        bidiConnection: pureBidiConnection,
        closeCallback: async () => {
          await pureBidiConnection.send('browser.close', {}).catch(debugError);
        },
      };
    }
  } catch (e: any) {
    if (!('name' in e && e.name === 'ProtocolError')) {
      // Unexpected exception not related to BiDi / CDP. Rethrow.
      throw e;
    }
  }
  // Unbind the connection to avoid memory leaks.
  pureBidiConnection.unbind();

  // Fall back to CDP over BiDi reusing the WS connection.
  const cdpConnection = new Connection(
    url,
    connectionTransport,
    slowMo,
    protocolTimeout
  );

  const version = await cdpConnection.send('Browser.getVersion');
  if (version.product.toLowerCase().includes('firefox')) {
    throw new UnsupportedOperation(
      'Firefox is not supported in BiDi over CDP mode.'
    );
  }

  // TODO: use other options too.
  const bidiOverCdpConnection = await BiDi.connectBidiOverCdp(cdpConnection, {
    acceptInsecureCerts: ignoreHTTPSErrors,
  });
  return {
    bidiConnection: bidiOverCdpConnection,
    closeCallback: async () => {
      // In case of BiDi over CDP, we need to close browser via CDP.
      await cdpConnection.send('Browser.close').catch(debugError);