docs: function sendRequest(options, onOk, onError, opt_data, opt_proxy, opt_retries) {
    var hostname = options.hostname;
    var port = options.port;
  
    if (opt_proxy) {
      let proxy = /** @type {RequestOptions} */(opt_proxy);
  
      // RFC 2616, section 5.1.2:
      // The absoluteURI form is REQUIRED when the request is being made to a
      // proxy.
      let absoluteUri = url.format(options);
  
      // RFC 2616, section 14.23:
      // An HTTP/1.1 proxy MUST ensure that any request message it forwards does
      // contain an appropriate Host header field that identifies the service
      // being requested by the proxy.
      let targetHost = options.hostname;
      if (options.port) {
        targetHost += ':' + options.port;
      }
  
      // Update the request options with our proxy info.
      options.headers['Host'] = targetHost;
      options.path = absoluteUri;
      options.host = proxy.host;
      options.hostname = proxy.hostname;
      options.port = proxy.port;
  
      if (proxy.auth) {
        options.headers['Proxy-Authorization'] =
            'Basic ' + new Buffer(proxy.auth).toString('base64');
      }
    }
  
    let requestFn = options.protocol === 'https:' ? https.request : http.request;
    var request = requestFn(options, function onResponse(response) {
      if (response.statusCode == 302 || response.statusCode == 303) {
        try {
          var location = url.parse(response.headers['location']);
        } catch (ex) {
          onError(Error(
              'Failed to parse "Location" header for server redirect: ' +
              ex.message + '\nResponse was: \n' +
              new httpLib.Response(response.statusCode, response.headers, '')));
          return;
        }
  
        if (!location.hostname) {
          location.hostname = hostname;
          location.port = port;
        }
  
        request.abort();
        sendRequest({
          method: 'GET',
          protocol: location.protocol || options.protocol,
          hostname: location.hostname,
          port: location.port,
          path: location.path,
          pathname: location.pathname,
          search: location.search,
          hash: location.hash,
          headers: {
            'Accept': 'application/json; charset=utf-8',
            'User-Agent': USER_AGENT,
          }
        }, onOk, onError, undefined, opt_proxy);
        return;
      }
  
      var body = [];
      response.on('data', body.push.bind(body));
      response.on('end', function() {
        var resp = new httpLib.Response(
            /** @type {number} */(response.statusCode),
            /** @type {!Object<string>} */(response.headers),
            body.join('').replace(/\0/g, ''));
        onOk(resp);
      });
    });
  
    request.on('error', function(e) {
      if (typeof opt_retries === 'undefined') {
        opt_retries = 0;
      }
  
      if (shouldRetryRequest(opt_retries, e)) {
        opt_retries += 1;
        setTimeout(function() {
          sendRequest(options, onOk, onError, opt_data, opt_proxy, opt_retries);
        }, 15);
      } else {
        var message = e.message;
        if (e.code) {
          message = e.code + ' ' + message;
        }
        onError(new Error(message));
      }
    });
  
    if (opt_data) {
      request.write(opt_data);
    }
  
    request.end();
  }