xref: /aosp_15_r20/external/perfetto/ui/src/base/http_utils.ts (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2019 The Android Open Source Project
2*6dbdd20aSAndroid Build Coastguard Worker//
3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License");
4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License.
5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at
6*6dbdd20aSAndroid Build Coastguard Worker//
7*6dbdd20aSAndroid Build Coastguard Worker//      http://www.apache.org/licenses/LICENSE-2.0
8*6dbdd20aSAndroid Build Coastguard Worker//
9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software
10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS,
11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and
13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License.
14*6dbdd20aSAndroid Build Coastguard Worker
15*6dbdd20aSAndroid Build Coastguard Workerimport {assertTrue} from './logging';
16*6dbdd20aSAndroid Build Coastguard Worker
17*6dbdd20aSAndroid Build Coastguard Workerexport function fetchWithTimeout(
18*6dbdd20aSAndroid Build Coastguard Worker  input: RequestInfo,
19*6dbdd20aSAndroid Build Coastguard Worker  init: RequestInit,
20*6dbdd20aSAndroid Build Coastguard Worker  timeoutMs: number,
21*6dbdd20aSAndroid Build Coastguard Worker) {
22*6dbdd20aSAndroid Build Coastguard Worker  return new Promise<Response>((resolve, reject) => {
23*6dbdd20aSAndroid Build Coastguard Worker    const timer = setTimeout(
24*6dbdd20aSAndroid Build Coastguard Worker      () =>
25*6dbdd20aSAndroid Build Coastguard Worker        reject(new Error(`fetch(${input}) timed out after ${timeoutMs} ms`)),
26*6dbdd20aSAndroid Build Coastguard Worker      timeoutMs,
27*6dbdd20aSAndroid Build Coastguard Worker    );
28*6dbdd20aSAndroid Build Coastguard Worker    fetch(input, init)
29*6dbdd20aSAndroid Build Coastguard Worker      .then((response) => resolve(response))
30*6dbdd20aSAndroid Build Coastguard Worker      .catch((err) => reject(err))
31*6dbdd20aSAndroid Build Coastguard Worker      .finally(() => clearTimeout(timer));
32*6dbdd20aSAndroid Build Coastguard Worker  });
33*6dbdd20aSAndroid Build Coastguard Worker}
34*6dbdd20aSAndroid Build Coastguard Worker
35*6dbdd20aSAndroid Build Coastguard Workerexport function fetchWithProgress(
36*6dbdd20aSAndroid Build Coastguard Worker  url: string,
37*6dbdd20aSAndroid Build Coastguard Worker  onProgress?: (percentage: number) => void,
38*6dbdd20aSAndroid Build Coastguard Worker): Promise<Blob> {
39*6dbdd20aSAndroid Build Coastguard Worker  return new Promise((resolve, reject) => {
40*6dbdd20aSAndroid Build Coastguard Worker    const xhr = new XMLHttpRequest();
41*6dbdd20aSAndroid Build Coastguard Worker
42*6dbdd20aSAndroid Build Coastguard Worker    xhr.open('GET', url, /* async= */ true);
43*6dbdd20aSAndroid Build Coastguard Worker    xhr.responseType = 'blob';
44*6dbdd20aSAndroid Build Coastguard Worker
45*6dbdd20aSAndroid Build Coastguard Worker    xhr.onprogress = (event) => {
46*6dbdd20aSAndroid Build Coastguard Worker      if (event.lengthComputable) {
47*6dbdd20aSAndroid Build Coastguard Worker        const percentComplete = Math.round((event.loaded / event.total) * 100);
48*6dbdd20aSAndroid Build Coastguard Worker        onProgress?.(percentComplete);
49*6dbdd20aSAndroid Build Coastguard Worker      }
50*6dbdd20aSAndroid Build Coastguard Worker    };
51*6dbdd20aSAndroid Build Coastguard Worker
52*6dbdd20aSAndroid Build Coastguard Worker    xhr.onload = () => {
53*6dbdd20aSAndroid Build Coastguard Worker      if (xhr.status >= 200 && xhr.status < 300) {
54*6dbdd20aSAndroid Build Coastguard Worker        resolve(xhr.response); // Resolve with the Blob response
55*6dbdd20aSAndroid Build Coastguard Worker      } else {
56*6dbdd20aSAndroid Build Coastguard Worker        reject(
57*6dbdd20aSAndroid Build Coastguard Worker          new Error(`Failed to download: ${xhr.status} ${xhr.statusText}`),
58*6dbdd20aSAndroid Build Coastguard Worker        );
59*6dbdd20aSAndroid Build Coastguard Worker      }
60*6dbdd20aSAndroid Build Coastguard Worker    };
61*6dbdd20aSAndroid Build Coastguard Worker
62*6dbdd20aSAndroid Build Coastguard Worker    xhr.onerror = () => {
63*6dbdd20aSAndroid Build Coastguard Worker      reject(new Error(`Network error in fetchWithProgress(${url})`));
64*6dbdd20aSAndroid Build Coastguard Worker    };
65*6dbdd20aSAndroid Build Coastguard Worker
66*6dbdd20aSAndroid Build Coastguard Worker    xhr.send();
67*6dbdd20aSAndroid Build Coastguard Worker  });
68*6dbdd20aSAndroid Build Coastguard Worker}
69*6dbdd20aSAndroid Build Coastguard Worker
70*6dbdd20aSAndroid Build Coastguard Worker/**
71*6dbdd20aSAndroid Build Coastguard Worker * NOTE: this function can only be called from synchronous contexts. It will
72*6dbdd20aSAndroid Build Coastguard Worker * fail if called in timer handlers or async continuations (e.g. after an await)
73*6dbdd20aSAndroid Build Coastguard Worker * Use assetSrc(relPath) which caches it on startup.
74*6dbdd20aSAndroid Build Coastguard Worker * @returns the directory where the app is served from, e.g. 'v46.0-a2082649b'
75*6dbdd20aSAndroid Build Coastguard Worker */
76*6dbdd20aSAndroid Build Coastguard Workerexport function getServingRoot() {
77*6dbdd20aSAndroid Build Coastguard Worker  // Works out the root directory where the content should be served from
78*6dbdd20aSAndroid Build Coastguard Worker  // e.g. `http://origin/v1.2.3/`.
79*6dbdd20aSAndroid Build Coastguard Worker  const script = document.currentScript as HTMLScriptElement;
80*6dbdd20aSAndroid Build Coastguard Worker
81*6dbdd20aSAndroid Build Coastguard Worker  if (script === null) {
82*6dbdd20aSAndroid Build Coastguard Worker    // Can be null in tests.
83*6dbdd20aSAndroid Build Coastguard Worker    assertTrue(typeof jest !== 'undefined');
84*6dbdd20aSAndroid Build Coastguard Worker    return '';
85*6dbdd20aSAndroid Build Coastguard Worker  }
86*6dbdd20aSAndroid Build Coastguard Worker
87*6dbdd20aSAndroid Build Coastguard Worker  let root = script.src;
88*6dbdd20aSAndroid Build Coastguard Worker  root = root.substring(0, root.lastIndexOf('/') + 1);
89*6dbdd20aSAndroid Build Coastguard Worker  return root;
90*6dbdd20aSAndroid Build Coastguard Worker}
91