Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add document fetcher #17259

Merged
merged 30 commits into from
Aug 7, 2018
Merged

Conversation

prateekbh
Copy link
Member

@prateekbh prateekbh commented Aug 2, 2018

  • adds document-fetcher.js
  • adds tests for it.
  • shifting each module will be a separate PR and will be reviewed with respective code owners

@codecov-io
Copy link

codecov-io commented Aug 2, 2018

Codecov Report

Merging #17259 into master will decrease coverage by 0.24%.
The diff coverage is 88%.

@@            Coverage Diff             @@
##           master   #17259      +/-   ##
==========================================
- Coverage   77.71%   77.46%   -0.25%     
==========================================
  Files         563      566       +3     
  Lines       41201    41491     +290     
==========================================
+ Hits        32018    32143     +125     
- Misses       9183     9348     +165
Flag Coverage Δ
#integration_tests 36.05% <ø> (-0.08%) ⬇️
#unit_tests 76.53% <88%> (-0.24%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 940f1d3...35c2f2f. Read the comment docs.

Copy link
Contributor

@jridgewell jridgewell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Much happier with this approach.

* @param {!./utils/xhr-utils.FetchInitDef} init
* @private
*/
function xhrRequest_(input, init) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: local names shouldn't end in _, only private property names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

init = setupAMPCors(win, input, init);
input = setupInput(win, input, init);
const ampdocService = Services.ampdocServiceFor(win);
const ampdocSingle_ =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: local names shouldn't end in _, only private property names.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

export function fetchDocument(win, input, opt_init) {
let init = setupInit(opt_init, 'text/html');
init = setupAMPCors(win, input, init);
input = setupInput(win, input, init);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these three always run like this? If so, probably means it should be joined into one function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not always

xhr.responseType = 'document';
// Incoming headers are in fetch format,
// so we need to convert them into xhr.
if (init.headers) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

init.headers is guaranteed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

};
const body = 'response' in xhr
? xhr.response : xhr.responseText;
const response = new Response(/** @type {string} */ (body || ''), /** @type {!ResponseInit} */ (options));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is all being done because verifyAmpCORSHeaders expects a response object with type signature { headers: { get() {} } }. We could slim all this down if it just pass in the header in question, or if it took just a headers object { get() {} }.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually this is done because at the end of all the change(including fetch polyfill), everything should talk in terms of native Response, Request. So we'd have to construct Response to talk to assertSuccess, verifyAmpCORSHeaders etc.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I disagree. Sure, we can make things that need a response to work (like, getting the response's body) use a Response. But verifyAmpCORSHeaders only needs a Headers (and only really needs { get() {} }. Simplifying the type requirements makes this code easier to reason about, because we're never going to use the response's body (xhr.reponseText) here, we aren't going to use status or statusText.

I really think we can simplify code by resolving with just the necessities here:

const makeshift = {
  xml: xhr.responseXML,
  // We can make this a wrapper class if we want to provide the full API
  headers: {
    get(header) {
      return xhr.getResponseHeader(header);
    },
  },
};
resolve(makeshift);

// back to https://github.com/ampproject/amphtml/pull/17259/files#diff-71317e0e89806231df17433535139205R45
// callback parameter is already a struct, not a Response
return xhrRequest(input, init).then(({xml, headers}) => {
  verifyAmpCORSHeaders(win, headers, init);
  return xml;
});

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woops, I actually noticed something.
Till this PR nobody has polyfilled Response for IE11 and other browsers so I am changing this to FetchResponse anyways.

But I will come back to this after doing the polyfill PR.
Note for then:
verifyAmpCORSHeaders requires the headers part
assertSuccess requires the .ok. So either we make both of them not take response arguments at all or we construct the Response once and use it everywhere.

response,
xhr,
});
}).catch(e => reject(e));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Just resolve with the promise, no need for another closure to handle reject:

const promise = assertSuccess(response).then(response => {
  return { response, xhr };
});
resolve(promise);

This is 99% equivalent (technically, yours would catch an error thrown by the resolve call, but that can't happen).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

* @return {JsonObject}
*/
function parseHeaders(rawHeaders) {
const headers = dict({});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was all done to satisfy Response's options { headers: !Object }, right?

Back to the type signature comment: If we change it to accept just a { get() {} } we could continue to use the old headers polyfill, which is much simpler/smaller. Or, if we pass the header directly into verifyAmpCORSHeaders, we don't need any of it.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see comment above

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My real hesitation here is creating a parser for something I don't know much about. And this implementation isn't really efficient...

@prateekbh
Copy link
Member Author

@jridgewell I moved from Response to FetchResponse since we have not poly-filled Response as of this point

@prateekbh prateekbh merged commit cba61ad into ampproject:master Aug 7, 2018
@prateekbh prateekbh deleted the add-document-fetcher branch August 7, 2018 23:46
kevinkassimo pushed a commit to kevinkassimo/amphtml that referenced this pull request Aug 9, 2018
* reverting skip

* splitting util functions

* bringing tests over

* fixing types

* fixing types

* fixing types

* fixing tests

* making setupAMPCors as a function

* resolving comments

* fixing bundle-size

* Update bundle-size.js

* fixing presubmit

* adding document fetcher

* resolving comments

* falling back to fetchResponse
Enriqe pushed a commit to Enriqe/amphtml that referenced this pull request Nov 28, 2018
* reverting skip

* splitting util functions

* bringing tests over

* fixing types

* fixing types

* fixing types

* fixing tests

* making setupAMPCors as a function

* resolving comments

* fixing bundle-size

* Update bundle-size.js

* fixing presubmit

* adding document fetcher

* resolving comments

* falling back to fetchResponse
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants