static impl_(url, init) {
    if (init['signal'] && init['signal']()) {
      // Throw an exception.
      return Promise.reject(jasmine.Fetch.makeAbortError_());
    }

    const headers = {};
    const initHeaders = new jasmine.Fetch.Headers(init.headers);
    initHeaders.forEach((value, key) => {
      headers[key] = value;
    });

    const newStub = /** @type {jasmine.Fetch.RequestStub} */({
      url: url,
      query: null,
      data: null,
      body: init.body,
      method: init.method,
      requestHeaders: headers,
      withCredentials: init.credentials == 'include',
      aborted: false,
    });
    jasmine.Fetch.container_.lastFetchRequestStub = newStub;

    const stubbed = jasmine.Fetch.container_.stubbedRequests[url];
    if (stubbed.callFunc) {
      const callFunc = stubbed.callFunc;
      stubbed.callFunc = undefined;
      callFunc(stubbed, self);
      // Call fetch again, in case callFunc changed the stub's action.
      return jasmine.Fetch.impl_(url, init);
    } else if (stubbed.response) {
      const responseHeaders = new jasmine.Fetch.Headers();
      for (const key in stubbed.response.responseHeaders) {
        responseHeaders.append(key, stubbed.response.responseHeaders[key]);
      }

      const body = {
        getReader: () => {
          const sequence = [{
            done: false, value: {byteLength: 100},
          }, {
            done: true, value: null,
          }];
          const read = () => {
            return Promise.resolve(sequence.shift());
          };
          return {read: read};
        },
      };

      // This creates an anonymous object instead of using the
      // built-in response constructor, because the fetch API
      // does not include a very good constructor for Response.
      const response = /** @type {!Response} */ ({
        status: stubbed.response.status,
        body: body,
        headers: responseHeaders,
        url: stubbed.response.responseURL || url,
        arrayBuffer: () => {
          return Promise.resolve(stubbed.response.response);
        },
        clone: () => response,
      });
      jasmine.Fetch.container_.latestResponse = response;
      return Promise.resolve(jasmine.Fetch.container_.latestResponse);
    } else if (stubbed.error) {
      return Promise.reject({message: 'fake error'});
    } else if (stubbed.timeout) {
      // Fetch does not time out yet, so just return a promise that rejects when
      // the user aborts.
      return new Promise(((resolve, reject) => {
        const interval = setInterval(() => {
          if (init['signal'] && init['signal']()) {
            // TODO: This assumes that this request is still the most recent.
            // If you have multiple requests at once, this could be incorrect.
            jasmine.Fetch.container_.lastFetchRequestStub.aborted = true;
            clearInterval(interval);
            reject(jasmine.Fetch.makeAbortError_());
          }
        }, 10);
      }));
    }
    throw new Error('no known action');
  }
@param {string} url
@param {RequestInit} init
@return {!Promise<!Response>}
@private