diff --git a/packages/react-native/Libraries/Network/XMLHttpRequest_new.js b/packages/react-native/Libraries/Network/XMLHttpRequest_new.js index 1eec800735d..ff590d9a971 100644 --- a/packages/react-native/Libraries/Network/XMLHttpRequest_new.js +++ b/packages/react-native/Libraries/Network/XMLHttpRequest_new.js @@ -45,6 +45,19 @@ export type ResponseType = | 'text'; export type Response = ?Object | string; +type XHRInterceptor = interface { + requestSent(id: number, url: string, method: string, headers: Object): void, + responseReceived( + id: number, + url: string, + status: number, + headers: Object, + ): void, + dataReceived(id: number, data: string): void, + loadingFinished(id: number, encodedDataLength: number): void, + loadingFailed(id: number, error: string): void, +}; + // The native blob module is optional so inject it here if available. if (BlobManager.isAvailable) { BlobManager.addNetworkingHandler(); @@ -120,6 +133,7 @@ class XMLHttpRequest extends EventTarget { static LOADING: number = LOADING; static DONE: number = DONE; + static _interceptor: ?XHRInterceptor = null; static _profiling: boolean = false; UNSENT: number = UNSENT; @@ -157,6 +171,10 @@ class XMLHttpRequest extends EventTarget { _startTime: ?number = null; _performanceLogger: IPerformanceLogger = GlobalPerformanceLogger; + static __setInterceptor_DO_NOT_USE(interceptor: ?XHRInterceptor) { + XMLHttpRequest._interceptor = interceptor; + } + static enableProfiling(enableProfiling: boolean): void { XMLHttpRequest._profiling = enableProfiling; } @@ -286,6 +304,14 @@ class XMLHttpRequest extends EventTarget { // exposed for testing __didCreateRequest(requestId: number): void { this._requestId = requestId; + + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.requestSent( + requestId, + this._url || '', + this._method || 'GET', + this._headers, + ); } // exposed for testing @@ -323,6 +349,14 @@ class XMLHttpRequest extends EventTarget { } else { delete this.responseURL; } + + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.responseReceived( + requestId, + responseURL || this._url || '', + status, + responseHeaders || {}, + ); } } @@ -333,6 +367,9 @@ class XMLHttpRequest extends EventTarget { this._response = response; this._cachedResponse = undefined; // force lazy recomputation this.setReadyState(this.LOADING); + + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.dataReceived(requestId, response); } __didReceiveIncrementalData( @@ -355,6 +392,8 @@ class XMLHttpRequest extends EventTarget { 'Track:XMLHttpRequest:Incremental Data: ' + this._getMeasureURL(), ); } + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.dataReceived(requestId, responseText); this.setReadyState(this.LOADING); this.__didReceiveDataProgress(requestId, progress, total); @@ -404,6 +443,16 @@ class XMLHttpRequest extends EventTarget { end: performance.now(), }); } + if (error) { + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.loadingFailed(requestId, error); + } else { + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.loadingFinished( + requestId, + this._response.length, + ); + } } } diff --git a/packages/react-native/Libraries/Network/XMLHttpRequest_old.js b/packages/react-native/Libraries/Network/XMLHttpRequest_old.js index 8797ccb8937..cdf67009995 100644 --- a/packages/react-native/Libraries/Network/XMLHttpRequest_old.js +++ b/packages/react-native/Libraries/Network/XMLHttpRequest_old.js @@ -34,6 +34,19 @@ export type ResponseType = | 'text'; export type Response = ?Object | string; +type XHRInterceptor = interface { + requestSent(id: number, url: string, method: string, headers: Object): void, + responseReceived( + id: number, + url: string, + status: number, + headers: Object, + ): void, + dataReceived(id: number, data: string): void, + loadingFinished(id: number, encodedDataLength: number): void, + loadingFailed(id: number, error: string): void, +}; + // The native blob module is optional so inject it here if available. if (BlobManager.isAvailable) { BlobManager.addNetworkingHandler(); @@ -88,6 +101,7 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { static LOADING: number = LOADING; static DONE: number = DONE; + static _interceptor: ?XHRInterceptor = null; static _profiling: boolean = false; UNSENT: number = UNSENT; @@ -135,6 +149,10 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { _startTime: ?number = null; _performanceLogger: IPerformanceLogger = GlobalPerformanceLogger; + static __setInterceptor_DO_NOT_USE(interceptor: ?XHRInterceptor) { + XMLHttpRequest._interceptor = interceptor; + } + static enableProfiling(enableProfiling: boolean): void { XMLHttpRequest._profiling = enableProfiling; } @@ -264,6 +282,14 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { // exposed for testing __didCreateRequest(requestId: number): void { this._requestId = requestId; + + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.requestSent( + requestId, + this._url || '', + this._method || 'GET', + this._headers, + ); } // exposed for testing @@ -299,6 +325,14 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { } else { delete this.responseURL; } + + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.responseReceived( + requestId, + responseURL || this._url || '', + status, + responseHeaders || {}, + ); } } @@ -309,6 +343,9 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { this._response = response; this._cachedResponse = undefined; // force lazy recomputation this.setReadyState(this.LOADING); + + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.dataReceived(requestId, response); } __didReceiveIncrementalData( @@ -331,6 +368,8 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { 'Track:XMLHttpRequest:Incremental Data: ' + this._getMeasureURL(), ); } + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.dataReceived(requestId, responseText); this.setReadyState(this.LOADING); this.__didReceiveDataProgress(requestId, progress, total); @@ -378,6 +417,16 @@ class XMLHttpRequest extends (EventTarget(...XHR_EVENTS): typeof EventTarget) { end: performance.now(), }); } + if (error) { + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.loadingFailed(requestId, error); + } else { + XMLHttpRequest._interceptor && + XMLHttpRequest._interceptor.loadingFinished( + requestId, + this._response.length, + ); + } } } diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 61311a5d579..7cffbf84cab 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -6039,6 +6039,18 @@ export type ResponseType = | \\"json\\" | \\"text\\"; export type Response = ?Object | string; +type XHRInterceptor = interface { + requestSent(id: number, url: string, method: string, headers: Object): void, + responseReceived( + id: number, + url: string, + status: number, + headers: Object + ): void, + dataReceived(id: number, data: string): void, + loadingFinished(id: number, encodedDataLength: number): void, + loadingFailed(id: number, error: string): void, +}; declare class XMLHttpRequestEventTarget extends EventTarget { get onload(): EventCallback | null; set onload(listener: ?EventCallback): void; @@ -6121,6 +6133,18 @@ export type ResponseType = | \\"json\\" | \\"text\\"; export type Response = ?Object | string; +type XHRInterceptor = interface { + requestSent(id: number, url: string, method: string, headers: Object): void, + responseReceived( + id: number, + url: string, + status: number, + headers: Object + ): void, + dataReceived(id: number, data: string): void, + loadingFinished(id: number, encodedDataLength: number): void, + loadingFailed(id: number, error: string): void, +}; declare class XMLHttpRequestEventTarget extends EventTarget { onload: ?Function; onloadstart: ?Function;