1/* 2 * Copyright 2024, The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17import {assertDefined} from 'common/assert_utils'; 18 19export type HttpRequestHeaderType = Array<[string, string]>; 20 21export enum HttpRequestStatus { 22 UNSENT, 23 UNAUTH, 24 SUCCESS, 25 ERROR, 26} 27 28export interface HttpResponse { 29 status: HttpRequestStatus; 30 type: XMLHttpRequestResponseType; //eslint-disable-line no-undef 31 text: string; 32 body: any; 33 getHeader: (name: string) => string | undefined; 34} 35 36export class HttpRequest { 37 static async get( 38 path: string, 39 headers: HttpRequestHeaderType, 40 type?: XMLHttpRequest['responseType'], 41 ): Promise<HttpResponse> { 42 return await HttpRequest.call('GET', path, headers, type); 43 } 44 45 static async post( 46 path: string, 47 headers: HttpRequestHeaderType, 48 jsonRequest?: object, 49 ): Promise<HttpResponse> { 50 return await HttpRequest.call( 51 'POST', 52 path, 53 headers, 54 undefined, 55 jsonRequest, 56 ); 57 } 58 59 private static async call( 60 method: string, 61 path: string, 62 headers: HttpRequestHeaderType, 63 type?: XMLHttpRequest['responseType'], 64 jsonRequest?: object, 65 ): Promise<HttpResponse> { 66 const req = new XMLHttpRequest(); 67 let status: HttpRequestStatus | undefined; 68 69 await new Promise<void>((resolve) => { 70 req.onreadystatechange = async () => { 71 if (req.readyState !== XMLHttpRequest.DONE) { 72 return; 73 } 74 if (req.status === XMLHttpRequest.UNSENT) { 75 status = HttpRequestStatus.UNSENT; 76 } else if (req.status === 200) { 77 status = HttpRequestStatus.SUCCESS; 78 } else if (req.status === 403) { 79 status = HttpRequestStatus.UNAUTH; 80 } else { 81 status = HttpRequestStatus.ERROR; 82 } 83 resolve(); 84 }; 85 req.responseType = type || ''; 86 req.open(method, path); 87 headers.forEach(([header, value]) => { 88 req.setRequestHeader(header, value); 89 }); 90 91 if (jsonRequest) { 92 const json = JSON.stringify(jsonRequest); 93 req.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); 94 req.send(json); 95 } else { 96 req.send(); 97 } 98 }); 99 100 const hasResponseText = 101 req.responseType === '' || req.responseType === 'text'; 102 103 return { 104 status: assertDefined(status), 105 type: req.responseType, 106 text: hasResponseText ? req.responseText : '', 107 body: req.response, 108 getHeader: (name: string) => req.getResponseHeader(name) ?? undefined, 109 }; 110 } 111} 112