microsoft/vscode-react-native

Public

mirrored fromhttps://github.com/microsoft/vscode-react-nativeAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
1.5.1

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

src/extension/networkInspector/requestBodyFormatters/requestBodyFormatter.ts

143lines · modecode

1// Copyright (c) Microsoft Corporation. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for details.
3
4import { Request, Response, Header } from "../networkMessageData";
5import { Base64 } from "js-base64";
6import * as pako from "pako";
7import { JSONFormatter } from "./jsonFormatter";
8import { OutputChannelLogger } from "../../log/OutputChannelLogger";
9import { ImageFormatter } from "./imageFormatter";
10import { GraphQLFormatter } from "./graphQLFormatter";
11import { FormUrlencodedFormatter } from "./formUrlencodedFormatter";
12import { notNullOrUndefined } from "../../../common/utils";
13
14export type FormattedBody = string | Record<string, any> | Array<Record<string, any>>;
15
16export interface IFormatter {
17 formatRequest?: (request: Request, contentType: string) => FormattedBody | null;
18 formatResponse?: (response: Response, contentType: string) => FormattedBody | null;
19}
20
21export class RequestBodyFormatter {
22 protected logger: OutputChannelLogger;
23 private formatters: Array<IFormatter>;
24
25 constructor(logger: OutputChannelLogger) {
26 this.logger = logger;
27 this.formatters = [
28 new ImageFormatter(),
29 new GraphQLFormatter(this.logger),
30 new JSONFormatter(this.logger),
31 new FormUrlencodedFormatter(this.logger),
32 ];
33 }
34
35 public formatBody(container: Request | Response): FormattedBody {
36 const contentType = getHeaderValue(container.headers, "content-type");
37
38 for (let formatter of this.formatters) {
39 try {
40 let formattedRes = null;
41 // if container is a response
42 if ((<any>container).status) {
43 if (formatter.formatResponse) {
44 formattedRes = formatter.formatResponse(<Response>container, contentType);
45 }
46 } else if (formatter.formatRequest) {
47 formattedRes = formatter.formatRequest(<Request>container, contentType);
48 }
49
50 if (notNullOrUndefined(formattedRes)) {
51 return formattedRes;
52 }
53 } catch (err) {
54 this.logger.debug(
55 `RequestBodyFormatter exception from ${formatter.constructor.name} ${err.message}`,
56 );
57 }
58 }
59
60 return decodeBody(container, this.logger);
61 }
62}
63
64/**
65 * @preserve
66 * Start region: the code is borrowed from https://github.com/facebook/flipper/blob/v0.79.1/desktop/plugins/network/utils.tsx#L23-L60
67 *
68 * Copyright (c) Facebook, Inc. and its affiliates.
69 *
70 * This source code is licensed under the MIT license found in the
71 * LICENSE file in the root directory of this source tree.
72 *
73 * @format
74 */
75export function decodeBody(container: Request | Response, logger?: OutputChannelLogger): string {
76 if (!container.data) {
77 return "";
78 }
79
80 try {
81 const isGzip = getHeaderValue(container.headers, "Content-Encoding") === "gzip";
82 if (isGzip) {
83 try {
84 const binStr = Base64.atob(container.data);
85 const dataArr = new Uint8Array(binStr.length);
86 for (let i = 0; i < binStr.length; i++) {
87 dataArr[i] = binStr.charCodeAt(i);
88 }
89 // The request is gzipped, so convert the base64 back to the raw bytes first,
90 // then inflate. pako will detect the BOM headers and return a proper utf-8 string right away
91 return pako.inflate(dataArr, { to: "string" });
92 } catch (e) {
93 // on iOS, the stream send to flipper is already inflated, so the content-encoding will not
94 // match the actual data anymore, and we should skip inflating.
95 // In that case, we intentionally fall-through
96 if (!e.toString().includes("incorrect header check")) {
97 throw e;
98 }
99 }
100 }
101 // If this is not a gzipped request, assume we are interested in a proper utf-8 string.
102 // - If the raw binary data in is needed, in base64 form, use container.data directly
103 // - either directly use container.data (for example)
104 return Base64.decode(container.data);
105 } catch (err) {
106 logger?.debug(
107 `Network inspector failed to decode request/response body (size: ${
108 container.data.length
109 }): ${err.toString()}`,
110 );
111 return "";
112 }
113}
114
115/**
116 * @preserve
117 * End region: https://github.com/facebook/flipper/blob/v0.79.1/desktop/plugins/network/utils.tsx#L23-L60
118 */
119
120/**
121 * @preserve
122 * Start region: the code is borrowed from https://github.com/facebook/flipper/blob/v0.79.1/desktop/plugins/network/utils.tsx#L14-L21
123 *
124 * Copyright (c) Facebook, Inc. and its affiliates.
125 *
126 * This source code is licensed under the MIT license found in the
127 * LICENSE file in the root directory of this source tree.
128 *
129 * @format
130 */
131export function getHeaderValue(headers: Array<Header>, key: string): string {
132 for (const header of headers) {
133 if (header.key.toLowerCase() === key.toLowerCase()) {
134 return header.value;
135 }
136 }
137 return "";
138}
139
140/**
141 * @preserve
142 * End region: https://github.com/facebook/flipper/blob/v0.79.1/desktop/plugins/network/utils.tsx#L14-L21
143 */
144