Skip to content
This repository has been archived by the owner on Aug 15, 2019. It is now read-only.

catch all unhandled promise rejection for http browser io handler #1455

Merged
merged 23 commits into from Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
ac52e66
add try catch to all await call
pyu10055 Dec 13, 2018
32a771e
added accept header for request and response header check
pyu10055 Dec 20, 2018
8a41afb
Merge branch 'master' into catch_promise_error
pyu10055 Dec 20, 2018
8b4b92a
fix error message
pyu10055 Dec 20, 2018
9c3a195
Merge branch 'catch_promise_error' of github.com:tensorflow/tfjs-core…
pyu10055 Dec 20, 2018
a094811
WIP wrap the fetch func with global catch
pyu10055 Dec 21, 2018
9422c57
fixed header being shared between requests
pyu10055 Dec 21, 2018
371981c
fix node.js missing Header class error
pyu10055 Dec 21, 2018
9b5339d
fix node.js error
pyu10055 Dec 21, 2018
7847656
remove use of Response
pyu10055 Dec 21, 2018
9f6ff2c
fixed weight load test failure
pyu10055 Dec 21, 2018
dbe8da2
Merge branch 'master' into catch_promise_error
pyu10055 Dec 26, 2018
ff05b09
Merge branch 'master' into catch_promise_error
pyu10055 Jan 4, 2019
96c063d
addressed comments
pyu10055 Jan 10, 2019
7a55301
Merge branches 'catch_promise_error' and 'catch_promise_error' of git…
pyu10055 Jan 10, 2019
e8e701f
more changes for comments
pyu10055 Jan 10, 2019
7ef2ede
add the any type back
pyu10055 Jan 10, 2019
e650dde
Merge branch 'master' into catch_promise_error
pyu10055 Jan 10, 2019
8c1458c
Merge branch 'master' into catch_promise_error
pyu10055 Jan 15, 2019
16de246
Merge branch 'master' into catch_promise_error
pyu10055 Jan 24, 2019
3e072f7
address comments
pyu10055 Jan 24, 2019
35258df
remove lint line
pyu10055 Jan 24, 2019
b5f8e7a
Merge branch 'master' into catch_promise_error
pyu10055 Jan 24, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
111 changes: 68 additions & 43 deletions src/io/browser_http.ts
Expand Up @@ -49,17 +49,22 @@ export class BrowserHTTPRequest implements IOHandler {
}
// Make sure fetch is always bound to window (the
// original object) when available.
this.fetchFunc =
fetch.bind(typeof window === 'undefined' ? null : window);
fetchFunc = fetch.bind(typeof window === 'undefined' ? null : window);
} else {
assert(
typeof fetchFunc === 'function',
'Must pass a function that matches the signature of ' +
'`fetch` (see ' +
'https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API)');
this.fetchFunc = fetchFunc;
}

this.fetchFunc = (path: string, requestInits: RequestInit) => {
// tslint:disable-next-line:no-any
return fetchFunc(path, requestInits).catch((error: any) => {
throw new Error(`Request for ${path} failed due to error: ${error}`);
});
};

assert(
path != null && path.length > 0,
'URL path for browserHTTPRequest must not be null, undefined or ' +
Expand Down Expand Up @@ -145,26 +150,44 @@ export class BrowserHTTPRequest implements IOHandler {
* Loads the model topology file and build the in memory graph of the model.
*/
private async loadBinaryTopology(): Promise<ArrayBuffer> {
try {
const response =
await this.getFetchFunc()(this.path[0], this.requestInit);
if (!response.ok) {
throw new Error(
`BrowserHTTPRequest.load() failed due to HTTP response: ${
response.statusText}`);
}
return await response.arrayBuffer();
} catch (error) {
throw new Error(`${this.path[0]} not found. ${error}`);
const response = await this.getFetchFunc()(
this.path[0], this.addAcceptHeader('application/octet-stream'));
this.verifyContentType(
response, 'model topology', 'application/octet-stream');

if (!response.ok) {
throw new Error(`Request to ${this.path[0]} failed with error: ${
response.statusText}`);
}
return await response.arrayBuffer();
}

private addAcceptHeader(mimeType: string): RequestInit {
const requestOptions = Object.assign({}, this.requestInit || {});
const headers = Object.assign({}, requestOptions.headers || {});
// tslint:disable-next-line:no-any
(headers as any)['Accept'] = mimeType;
requestOptions.headers = headers;
return requestOptions;
}

private verifyContentType(response: Response, target: string, type: string) {
const contentType = response.headers.get('content-type');
if (!contentType || contentType.indexOf(type) === -1) {
throw new Error(`Request to ${response.url} for ${
target} failed. Expected content type ${type} but got ${
contentType}.`);
}
}

protected async loadBinaryModel(): Promise<ModelArtifacts> {
const graphPromise = this.loadBinaryTopology();
const manifestPromise =
await this.getFetchFunc()(this.path[1], this.requestInit);
const manifestPromise = await this.getFetchFunc()(
this.path[1], this.addAcceptHeader('application/json'));
this.verifyContentType(
manifestPromise, 'weights manifest', 'application/json');
if (!manifestPromise.ok) {
throw new Error(`BrowserHTTPRequest.load() failed due to HTTP response: ${
throw new Error(`Request to ${this.path[1]} failed with error: ${
manifestPromise.statusText}`);
}

Expand All @@ -185,10 +208,13 @@ export class BrowserHTTPRequest implements IOHandler {
}

protected async loadJSONModel(): Promise<ModelArtifacts> {
const modelConfigRequest =
await this.getFetchFunc()(this.path as string, this.requestInit);
const modelConfigRequest = await this.getFetchFunc()(
this.path as string, this.addAcceptHeader('application/json'));
this.verifyContentType(
modelConfigRequest, 'model topology', 'application/json');

if (!modelConfigRequest.ok) {
throw new Error(`BrowserHTTPRequest.load() failed due to HTTP response: ${
throw new Error(`Request to ${this.path} failed with error: ${
modelConfigRequest.statusText}`);
}
const modelConfig = await modelConfigRequest.json();
Expand Down Expand Up @@ -231,12 +257,10 @@ export class BrowserHTTPRequest implements IOHandler {
fetchURLs.push(pathPrefix + path + suffix);
});
});

return [
weightSpecs,
concatenateArrayBuffers(await loadWeightsAsArrayBuffer(
fetchURLs, this.requestInit, this.getFetchFunc(),
this.onProgress))
fetchURLs, this.requestInit, this.getFetchFunc(), this.onProgress))
];
}

Expand Down Expand Up @@ -276,24 +300,25 @@ export function isHTTPScheme(url: string): boolean {
return url.match(BrowserHTTPRequest.URL_SCHEME_REGEX) != null;
}

export const httpRequestRouter: IORouter = (url: string|string[], onProgress?: Function) => {
if (typeof fetch === 'undefined') {
// browserHTTPRequest uses `fetch`, if one wants to use it in node.js
// they have to setup a global fetch polyfill.
return null;
} else {
let isHTTP = true;
if (Array.isArray(url)) {
isHTTP = url.every(urlItem => isHTTPScheme(urlItem));
} else {
isHTTP = isHTTPScheme(url);
}
if (isHTTP) {
return browserHTTPRequest(url, null, null, null, onProgress);
}
}
return null;
};
export const httpRequestRouter: IORouter =
(url: string|string[], onProgress?: Function) => {
if (typeof fetch === 'undefined') {
// browserHTTPRequest uses `fetch`, if one wants to use it in node.js
// they have to setup a global fetch polyfill.
return null;
} else {
let isHTTP = true;
if (Array.isArray(url)) {
isHTTP = url.every(urlItem => isHTTPScheme(urlItem));
} else {
isHTTP = isHTTPScheme(url);
}
if (isHTTP) {
return browserHTTPRequest(url, null, null, null, onProgress);
}
}
return null;
};
IORouterRegistry.registerSaveRouter(httpRequestRouter);
IORouterRegistry.registerLoadRouter(httpRequestRouter);

Expand Down Expand Up @@ -444,6 +469,6 @@ IORouterRegistry.registerLoadRouter(httpRequestRouter);
export function browserHTTPRequest(
path: string|string[], requestInit?: RequestInit, weightPathPrefix?: string,
fetchFunc?: Function, onProgress?: Function): IOHandler {
return new BrowserHTTPRequest(path, requestInit, weightPathPrefix, fetchFunc,
onProgress);
return new BrowserHTTPRequest(
path, requestInit, weightPathPrefix, fetchFunc, onProgress);
}