123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- /**
- * Copyright (c) Facebook, Inc. and its affiliates.
- *
- * This source code is licensed under the MIT license found in the
- * LICENSE file in the root directory of this source tree.
- *
- * @format
- */
- 'use strict';
- const NativeEventEmitter = require('../EventEmitter/NativeEventEmitter');
- import NativeWebSocketModule from './NativeWebSocketModule';
- const base64 = require('base64-js');
- const originalRCTWebSocketConnect = NativeWebSocketModule.connect;
- const originalRCTWebSocketSend = NativeWebSocketModule.send;
- const originalRCTWebSocketSendBinary = NativeWebSocketModule.sendBinary;
- const originalRCTWebSocketClose = NativeWebSocketModule.close;
- let eventEmitter: NativeEventEmitter;
- let subscriptions: Array<EventSubscription>;
- let closeCallback;
- let sendCallback;
- let connectCallback;
- let onOpenCallback;
- let onMessageCallback;
- let onErrorCallback;
- let onCloseCallback;
- let isInterceptorEnabled = false;
- /**
- * A network interceptor which monkey-patches RCTWebSocketModule methods
- * to gather all websocket network requests/responses, in order to show
- * their information in the React Native inspector development tool.
- */
- const WebSocketInterceptor = {
- /**
- * Invoked when RCTWebSocketModule.close(...) is called.
- */
- setCloseCallback(callback) {
- closeCallback = callback;
- },
- /**
- * Invoked when RCTWebSocketModule.send(...) or sendBinary(...) is called.
- */
- setSendCallback(callback) {
- sendCallback = callback;
- },
- /**
- * Invoked when RCTWebSocketModule.connect(...) is called.
- */
- setConnectCallback(callback) {
- connectCallback = callback;
- },
- /**
- * Invoked when event "websocketOpen" happens.
- */
- setOnOpenCallback(callback) {
- onOpenCallback = callback;
- },
- /**
- * Invoked when event "websocketMessage" happens.
- */
- setOnMessageCallback(callback) {
- onMessageCallback = callback;
- },
- /**
- * Invoked when event "websocketFailed" happens.
- */
- setOnErrorCallback(callback) {
- onErrorCallback = callback;
- },
- /**
- * Invoked when event "websocketClosed" happens.
- */
- setOnCloseCallback(callback) {
- onCloseCallback = callback;
- },
- isInterceptorEnabled() {
- return isInterceptorEnabled;
- },
- _unregisterEvents() {
- subscriptions.forEach(e => e.remove());
- subscriptions = [];
- },
- /**
- * Add listeners to the RCTWebSocketModule events to intercept them.
- */
- _registerEvents() {
- subscriptions = [
- eventEmitter.addListener('websocketMessage', ev => {
- if (onMessageCallback) {
- onMessageCallback(
- ev.id,
- ev.type === 'binary'
- ? WebSocketInterceptor._arrayBufferToString(ev.data)
- : ev.data,
- );
- }
- }),
- eventEmitter.addListener('websocketOpen', ev => {
- if (onOpenCallback) {
- onOpenCallback(ev.id);
- }
- }),
- eventEmitter.addListener('websocketClosed', ev => {
- if (onCloseCallback) {
- onCloseCallback(ev.id, {code: ev.code, reason: ev.reason});
- }
- }),
- eventEmitter.addListener('websocketFailed', ev => {
- if (onErrorCallback) {
- onErrorCallback(ev.id, {message: ev.message});
- }
- }),
- ];
- },
- enableInterception() {
- if (isInterceptorEnabled) {
- return;
- }
- eventEmitter = new NativeEventEmitter(NativeWebSocketModule);
- WebSocketInterceptor._registerEvents();
- // Override `connect` method for all RCTWebSocketModule requests
- // to intercept the request url, protocols, options and socketId,
- // then pass them through the `connectCallback`.
- NativeWebSocketModule.connect = function(
- url,
- protocols,
- options,
- socketId,
- ) {
- if (connectCallback) {
- connectCallback(url, protocols, options, socketId);
- }
- originalRCTWebSocketConnect.apply(this, arguments);
- };
- // Override `send` method for all RCTWebSocketModule requests to intercept
- // the data sent, then pass them through the `sendCallback`.
- NativeWebSocketModule.send = function(data, socketId) {
- if (sendCallback) {
- sendCallback(data, socketId);
- }
- originalRCTWebSocketSend.apply(this, arguments);
- };
- // Override `sendBinary` method for all RCTWebSocketModule requests to
- // intercept the data sent, then pass them through the `sendCallback`.
- NativeWebSocketModule.sendBinary = function(data, socketId) {
- if (sendCallback) {
- sendCallback(WebSocketInterceptor._arrayBufferToString(data), socketId);
- }
- originalRCTWebSocketSendBinary.apply(this, arguments);
- };
- // Override `close` method for all RCTWebSocketModule requests to intercept
- // the close information, then pass them through the `closeCallback`.
- NativeWebSocketModule.close = function() {
- if (closeCallback) {
- if (arguments.length === 3) {
- closeCallback(arguments[0], arguments[1], arguments[2]);
- } else {
- closeCallback(null, null, arguments[0]);
- }
- }
- originalRCTWebSocketClose.apply(this, arguments);
- };
- isInterceptorEnabled = true;
- },
- _arrayBufferToString(data) {
- const value = base64.toByteArray(data).buffer;
- if (value === undefined || value === null) {
- return '(no value)';
- }
- if (
- typeof ArrayBuffer !== 'undefined' &&
- typeof Uint8Array !== 'undefined' &&
- value instanceof ArrayBuffer
- ) {
- return `ArrayBuffer {${String(Array.from(new Uint8Array(value)))}}`;
- }
- return value;
- },
- // Unpatch RCTWebSocketModule methods and remove the callbacks.
- disableInterception() {
- if (!isInterceptorEnabled) {
- return;
- }
- isInterceptorEnabled = false;
- NativeWebSocketModule.send = originalRCTWebSocketSend;
- NativeWebSocketModule.sendBinary = originalRCTWebSocketSendBinary;
- NativeWebSocketModule.close = originalRCTWebSocketClose;
- NativeWebSocketModule.connect = originalRCTWebSocketConnect;
- connectCallback = null;
- closeCallback = null;
- sendCallback = null;
- onOpenCallback = null;
- onMessageCallback = null;
- onCloseCallback = null;
- onErrorCallback = null;
- WebSocketInterceptor._unregisterEvents();
- },
- };
- module.exports = WebSocketInterceptor;
|