whistle 2.8.10 → 2.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/assets/menu.html CHANGED
@@ -53,51 +53,103 @@
53
53
  window.addEventListener('load', delayOnLoad);
54
54
  } catch (e) {}
55
55
  var toast = {};
56
+ var addNetworkListener = function(l) {
57
+ if (typeof l === 'function' && networkListeners.indexOf(l) === -1) {
58
+ networkListeners.push(l);
59
+ }
60
+ };
61
+ var removeNetworkListener = function(l) {
62
+ l = networkListeners.indexOf(l);
63
+ if (l !== -1) {
64
+ networkListeners.splice(l, 1);
65
+ }
66
+ };
67
+ var removeAllNetworkListeners = function() {
68
+ networkListeners = [];
69
+ };
70
+ var addRulesListener = function(l) {
71
+ if (typeof l === 'function' && rulesListeners.indexOf(l) === -1) {
72
+ rulesListeners.push(l);
73
+ }
74
+ };
75
+ var removeRulesListener = function(l) {
76
+ l = rulesListeners.indexOf(l);
77
+ if (l !== -1) {
78
+ rulesListeners.splice(l, 1);
79
+ }
80
+ };
81
+ var removeAllRulesListeners = function() {
82
+ rulesListeners = [];
83
+ };
84
+ var addValuesListener = function(l) {
85
+ if (typeof l === 'function' && valuesListeners.indexOf(l) === -1) {
86
+ valuesListeners.push(l);
87
+ }
88
+ };
89
+ var removeValuesListener = function(l) {
90
+ l = valuesListeners.indexOf(l);
91
+ if (l !== -1) {
92
+ valuesListeners.splice(l, 1);
93
+ }
94
+ };
95
+ var removeAllValuesListeners = function() {
96
+ valuesListeners = [];
97
+ };
98
+
99
+ function on(type, l) {
100
+ if (typeof l !== 'function') {
101
+ return;
102
+ }
103
+ switch(type) {
104
+ case 'network':
105
+ return addNetworkListener(l);
106
+ case 'rules':
107
+ return addRulesListener(l);
108
+ case 'values':
109
+ return addValuesListener(l);
110
+ }
111
+ }
112
+
113
+ function off(type, l) {
114
+ switch(type) {
115
+ case 'network':
116
+ if (l) {
117
+ removeNetworkListener(l);
118
+ } else {
119
+ removeAllNetworkListeners();
120
+ }
121
+ return;
122
+ case 'rules':
123
+ if (l) {
124
+ removeRulesListener(l);
125
+ } else {
126
+ removeAllRulesListeners();
127
+ }
128
+ return;
129
+ case 'values':
130
+ if (l) {
131
+ removeValuesListener(l);
132
+ } else {
133
+ removeAllValuesListeners();
134
+ }
135
+ return;
136
+ }
137
+ }
138
+
56
139
  var whistleBridge = {
57
140
  config: config,
58
141
  toast: toast,
59
- addNetworkListener: function(l) {
60
- if (typeof l === 'function' && networkListeners.indexOf(l) === -1) {
61
- networkListeners.push(l);
62
- }
63
- },
64
- removeNetworkListener: function(l) {
65
- l = networkListeners.indexOf(l);
66
- if (l !== -1) {
67
- networkListeners.splice(l, 1);
68
- }
69
- },
70
- removeAllNetworkListeners: function() {
71
- networkListeners = [];
72
- },
73
- addRulesListener: function(l) {
74
- if (typeof l === 'function' && rulesListeners.indexOf(l) === -1) {
75
- rulesListeners.push(l);
76
- }
77
- },
78
- removeRulesListener: function(l) {
79
- l = rulesListeners.indexOf(l);
80
- if (l !== -1) {
81
- rulesListeners.splice(l, 1);
82
- }
83
- },
84
- removeAllRulesListeners: function() {
85
- rulesListeners = [];
86
- },
87
- addValuesListener: function(l) {
88
- if (typeof l === 'function' && valuesListeners.indexOf(l) === -1) {
89
- valuesListeners.push(l);
90
- }
91
- },
92
- removeValuesListener: function(l) {
93
- l = valuesListeners.indexOf(l);
94
- if (l !== -1) {
95
- valuesListeners.splice(l, 1);
96
- }
97
- },
98
- removeAllValuesListeners: function() {
99
- valuesListeners = [];
100
- }
142
+ on: on,
143
+ off: off,
144
+ addNetworkListener: addNetworkListener,
145
+ removeNetworkListener: removeNetworkListener,
146
+ removeAllNetworkListeners: removeAllNetworkListeners,
147
+ addRulesListener: addRulesListener,
148
+ removeRulesListener: removeRulesListener,
149
+ removeAllRulesListeners: removeAllRulesListeners,
150
+ addValuesListener: addValuesListener,
151
+ removeValuesListener: removeValuesListener,
152
+ removeAllValuesListeners: removeAllValuesListeners
101
153
  };
102
154
  try {
103
155
  window.initWhistleBridge = function(options) {
@@ -105,6 +157,8 @@
105
157
  Object.keys(options.msgBox).forEach(function(name) {
106
158
  toast[name] = options.msgBox[name];
107
159
  });
160
+ whistleBridge.pageId = options.pageId;
161
+ whistleBridge.compose = options.compose;
108
162
  whistleBridge.decodeBase64 = options.decodeBase64;
109
163
  whistleBridge.importSessions = options.importSessions;
110
164
  whistleBridge.request = options.request;
@@ -0,0 +1,303 @@
1
+ <script>
2
+ ;(function() {
3
+ var config = window.whistleInspectorConfig;
4
+ var activeList = [];
5
+ var stateList = [1];
6
+ var getActiveSession;
7
+ var getSelectedSessionList;
8
+ var listenersList = [];
9
+ var frameChangeListeners = [];
10
+ var composeListeners = [];
11
+ var tabChangeListeners = [];
12
+ var curFrames = null;
13
+ var firstFrame;
14
+ var lastFrame;
15
+ var selected = true;
16
+ var composerItem;
17
+ var frameTimer;
18
+
19
+ function initState(flag) {
20
+ stateList[1] = flag;
21
+ stateList[2] = flag;
22
+ stateList[3] = flag;
23
+ }
24
+
25
+ function updateState(item) {
26
+ if (!item || item.lost || item.endTime) {
27
+ return initState(1);
28
+ }
29
+ initState();
30
+ if (item.responseTime) {
31
+ stateList[2] = 1;
32
+ }
33
+ if (item.requestTime) {
34
+ stateList[1] = 1;
35
+ }
36
+ }
37
+
38
+ function emitTabChange(_selected) {
39
+ if (selected !== _selected) {
40
+ selected = _selected;
41
+ tabChangeListeners.forEach(function(l) {
42
+ l(selected);
43
+ });
44
+ }
45
+ }
46
+
47
+ function emitFrameChange() {
48
+ var curItem = getActiveSession();
49
+ var frames = curItem && curItem.frames || null;
50
+ var hasChanged;
51
+ var listenersLen = frameChangeListeners.length;
52
+ if (curFrames !== frames) {
53
+ curFrames = frames;
54
+ hasChanged = listenersLen;
55
+ } else if (curFrames && listenersLen) {
56
+ var curLen = curFrames.length;
57
+ var len = frames.length;
58
+ hasChanged = curLen !== len || firstFrame != frames[0] || lastFrame != frames[len - 1];
59
+ }
60
+ if (hasChanged) {
61
+ if (curFrames) {
62
+ firstFrame = curFrames[0];
63
+ lastFrame = curFrames[curFrames.length - 1];
64
+ } else {
65
+ firstFrame = lastFrame = undefined;
66
+ }
67
+ frameChangeListeners.forEach(function(l) {
68
+ l(curFrames);
69
+ });
70
+ }
71
+ frameTimer = setTimeout(emitFrameChange, 1000);
72
+ }
73
+
74
+ function emitListeners(item, state) {
75
+ if (stateList[state] && item !== activeList[state]) {
76
+ activeList[state] = item;
77
+ var listeners = listenersList[state];
78
+ listeners.forEach(function(l) {
79
+ l(item);
80
+ });
81
+ }
82
+ }
83
+
84
+ function emitAll(item, hide, comItem) {
85
+ if (comItem) {
86
+ composerItem = comItem;
87
+ composeListeners.forEach(function(l) {
88
+ l(comItem);
89
+ });
90
+ return;
91
+ }
92
+ if (frameTimer) {
93
+ clearTimeout(frameTimer);
94
+ frameTimer = null;
95
+ }
96
+ if (hide) {
97
+ return emitTabChange(false);
98
+ }
99
+ emitTabChange(true);
100
+ updateState(item);
101
+ emitListeners(item, 0);
102
+ emitListeners(item, 1);
103
+ emitListeners(item, 2);
104
+ emitListeners(item, 3);
105
+ emitFrameChange();
106
+ }
107
+
108
+ window.__pushWhistle5b6af7b9884e1165SessionActive__ = emitAll;
109
+
110
+ function getAddEventHandler(state) {
111
+ state = state || 0;
112
+ listenersList[state] = [];
113
+ return function(l) {
114
+ if (typeof l !== 'function') {
115
+ return;
116
+ }
117
+ var item = getActiveSession();
118
+ emitAll(item);
119
+ activeList[state] = item;
120
+ if (stateList[state]) {
121
+ l(item);
122
+ }
123
+ var listeners = listenersList[state];
124
+ listeners.indexOf(l) === -1 && listeners.push(l);
125
+ };
126
+ }
127
+
128
+ function getRemoveEventListener(state) {
129
+ state = state || 0;
130
+ return function(l) {
131
+ var listeners = listenersList[state];
132
+ var index = listeners.indexOf(l);
133
+ index !== -1 && listeners.splice(index, 1);
134
+ };
135
+ }
136
+
137
+ function getRemoveEventListeners(state) {
138
+ state = state || 0;
139
+ return function(l) {
140
+ listenersList[state] = [];
141
+ };
142
+ }
143
+
144
+ var toast = {};
145
+ var addSessionActiveListener = getAddEventHandler();
146
+ var removeSessionActiveListener = getRemoveEventListener();
147
+ var removeSessionActiveListeners = getRemoveEventListeners();
148
+ var addSessionRequestListener = getAddEventHandler(1);
149
+ var removeSessionRequestListener = getRemoveEventListener(1);
150
+ var removeSessionRequestListeners = getRemoveEventListeners(1);
151
+ var addSessionResponseListener = getAddEventHandler(2);
152
+ var removeSessionResponseListener = getRemoveEventListener(2);
153
+ var removeSessionResponseListeners = getRemoveEventListeners(2);
154
+ var addSessionCompleteListener = getAddEventHandler(3);
155
+ var removeSessionCompleteListener = getRemoveEventListener(3);
156
+ var removeSessionCompleteListeners = getRemoveEventListeners(3);
157
+
158
+ function on(type, l) {
159
+ if (typeof l !== 'function') {
160
+ return;
161
+ }
162
+ switch(type) {
163
+ case 'sessionActive':
164
+ return addSessionActiveListener(l);
165
+ case 'sessionRequest':
166
+ return addSessionRequestListener(l);
167
+ case 'sessionResponse':
168
+ return addSessionResponseListener(l);
169
+ case 'sessionComplete':
170
+ return addSessionCompleteListener(l);
171
+ case 'tabChange':
172
+ if (tabChangeListeners.indexOf(l) === -1) {
173
+ tabChangeListeners.push(l);
174
+ }
175
+ return;
176
+ case 'frameChange':
177
+ if (frameChangeListeners.indexOf(l) === -1) {
178
+ frameChangeListeners.push(l);
179
+ }
180
+ return;
181
+ case 'compose':
182
+ if (composeListeners.indexOf(l) === -1) {
183
+ composeListeners.push(l);
184
+ }
185
+ composerItem && l(composerItem);
186
+ return;
187
+ }
188
+ }
189
+
190
+ function off(type, l) {
191
+ switch(type) {
192
+ case 'sessionActive':
193
+ if (l) {
194
+ removeSessionActiveListener(l);
195
+ } else {
196
+ removeSessionActiveListeners();
197
+ }
198
+ return;
199
+ case 'sessionRequest':
200
+ if (l) {
201
+ removeSessionRequestListener(l);
202
+ } else {
203
+ removeSessionRequestListeners();
204
+ }
205
+ return;
206
+ case 'sessionResponse':
207
+ if (l) {
208
+ removeSessionResponseListener(l);
209
+ } else {
210
+ removeSessionResponseListeners();
211
+ }
212
+ return;
213
+ case 'sessionComplete':
214
+ if (l) {
215
+ removeSessionCompleteListener(l);
216
+ } else {
217
+ removeSessionCompleteListeners();
218
+ }
219
+ return;
220
+ case 'tabChange':
221
+ if (l) {
222
+ var index = tabChangeListeners.indexOf(l);
223
+ if (index !== -1) {
224
+ tabChangeListeners.splice(index, 1);
225
+ }
226
+ } else {
227
+ tabChangeListeners = [];
228
+ }
229
+ return;
230
+ case 'frameChange':
231
+ if (l) {
232
+ var index = frameChangeListeners.indexOf(l);
233
+ if (index !== -1) {
234
+ frameChangeListeners.splice(index, 1);
235
+ }
236
+ } else {
237
+ frameChangeListeners = [];
238
+ }
239
+ return;
240
+ case 'compose':
241
+ if (l) {
242
+ var index = composeListeners.indexOf(l);
243
+ if (index !== -1) {
244
+ composeListeners.splice(index, 1);
245
+ }
246
+ } else {
247
+ composeListeners = [];
248
+ }
249
+ return;
250
+ }
251
+ }
252
+
253
+ var whistleBridge = {
254
+ config: config,
255
+ toast: toast,
256
+ on: on,
257
+ off: off,
258
+ isSelected: function() {
259
+ return selected;
260
+ },
261
+ getFrames: function() {
262
+ return curFrames;
263
+ },
264
+ addSessionActiveListener: addSessionActiveListener,
265
+ removeSessionActiveListener: removeSessionActiveListener,
266
+ removeSessionActiveListeners: removeSessionActiveListeners,
267
+ addSessionRequestListener: addSessionRequestListener,
268
+ removeSessionRequestListener: removeSessionRequestListener,
269
+ removeSessionRequestListeners: removeSessionRequestListeners,
270
+ addSessionResponseListener: addSessionResponseListener,
271
+ removeSessionResponseListener: removeSessionResponseListener,
272
+ removeSessionResponseListeners: removeSessionResponseListeners,
273
+ addSessionCompleteListener: addSessionCompleteListener,
274
+ removeSessionCompleteListener: removeSessionCompleteListener,
275
+ removeSessionCompleteListeners: removeSessionCompleteListeners
276
+ };
277
+
278
+ try {
279
+ window.parent.onWhistleInspectorCustomTabReady(function(options) {
280
+ Object.keys(options.msgBox).forEach(function(name) {
281
+ toast[name] = options.msgBox[name];
282
+ });
283
+ getActiveSession = options.getActiveSession;
284
+ getSelectedSessionList = options.getSelectedSessionList;
285
+ whistleBridge.pageId = options.pageId;
286
+ whistleBridge.compose = options.compose;
287
+ whistleBridge.decodeBase64 = options.decodeBase64;
288
+ whistleBridge.importSessions = options.importSessions;
289
+ whistleBridge.request = options.request;
290
+ whistleBridge.createRequest = options.createRequest;
291
+ whistleBridge.showModal = options.showModal;
292
+ whistleBridge.getSelectedSessionList = getSelectedSessionList;
293
+ whistleBridge.getActiveSession = whistleBridge.getSession = whistleBridge.getSelectedSession = getActiveSession;
294
+ whistleBridge.importRules = options.importRules;
295
+ whistleBridge.importValues = options.importValues;
296
+ whistleBridge.getServerInfo = options.getServerInfo;
297
+ whistleBridge.alert = options.alert;
298
+ whistleBridge.confirm = options.confirm;
299
+ });
300
+ } catch (e) {}
301
+ window.whistleBridge = whistleBridge;
302
+ })();
303
+ </script>
@@ -1,7 +1,9 @@
1
1
  var http = require('http');
2
2
  var gzip = require('zlib').gzip;
3
3
  var tls = require('tls');
4
+ var crypto = require('crypto');
4
5
  var Buffer = require('safe-buffer').Buffer;
6
+ var common = require('../../../lib/util/common');
5
7
  var config = require('../../../lib/config');
6
8
  var util = require('../../../lib/util');
7
9
  var zlib = require('../../../lib/util/zlib');
@@ -14,17 +16,19 @@ var getRawHeaders = hparser.getRawHeaders;
14
16
  var getRawHeaderNames = hparser.getRawHeaderNames;
15
17
  var parseReq = hparser.parse;
16
18
  var MAX_LENGTH = 1024 * 512;
19
+ var TLS_PROTOS = 'https:,wss:,tls:'.split(',');
17
20
  var PROXY_OPTS = {
18
21
  host: config.host || '127.0.0.1',
19
22
  port: config.port
20
23
  };
21
24
 
22
25
  function parseHeaders(headers, rawHeaderNames, clientId) {
23
- if (!headers || typeof headers != 'string') {
26
+ var type = headers && typeof headers;
27
+ if (type != 'string' && type !== 'object') {
24
28
  return {};
25
29
  }
26
30
 
27
- var reqHeaders = util.parseRawJson(headers);
31
+ var reqHeaders = type === 'object' ? headers : util.parseRawJson(headers);
28
32
  if (reqHeaders) {
29
33
  reqHeaders = util.lowerCaseify(reqHeaders, rawHeaderNames);
30
34
  } else {
@@ -36,22 +40,6 @@ function parseHeaders(headers, rawHeaderNames, clientId) {
36
40
  return reqHeaders;
37
41
  }
38
42
 
39
- function isWebSocket(options) {
40
- var p = options.protocol;
41
- return p === 'ws:' || p === 'wss:' || options.method === 'UPGRADE';
42
- }
43
-
44
- var crypto = require('crypto');
45
- var CONNECT_PROTOS = 'connect:,socket:,tunnel:,conn:,tls:,tcp:'.split(',');
46
- var TLS_PROTOS = 'https:,wss:,tls:'.split(',');
47
- function isConnect(options) {
48
- if (options.method === 'CONNECT') {
49
- return true;
50
- }
51
- var p = options.protocol;
52
- return CONNECT_PROTOS.indexOf(p) !== -1;
53
- }
54
-
55
43
  function drain(socket) {
56
44
  socket.on('error', util.noop);
57
45
  socket.on('data', util.noop);
@@ -227,10 +215,9 @@ module.exports = function(req, res) {
227
215
  headers[config.CLIENT_PORT_HEAD] = util.getClientPort(req);
228
216
  options.method = util.getMethod(req.body.method);
229
217
 
230
- var isConn = isConnect(options);
231
- var isWs = !isConn && (isWebSocket(options)
232
- || (/^\s*upgrade\s*$/i.test(headers.connection) && /^\s*websocket\s*$/i.test(headers.upgrade)));
233
- var useH2 = req.body.useH2;
218
+ var isConn = common.isConnect(options);
219
+ var isWs = !isConn && common.isWebSocket(options, headers);
220
+ var useH2 = req.body.useH2 || req.body.isH2;
234
221
  req.body.useH2 = false;
235
222
  if (isWs) {
236
223
  headers.connection = 'Upgrade';
@@ -16,7 +16,7 @@ html, body, .main {padding: 0; margin: 0; height: 100%; overflow: hidden;}
16
16
  textarea {resize: none; display: block; padding: 6px; font-size: 12px; width: 100%; height: 100%; border: none; box-sizing: border-box; font-family: consolas, monospace;}
17
17
  </style>
18
18
  </head>
19
- <body>
19
+ <body style="overscroll-behavior-x: none;">
20
20
  <div class="main">
21
21
  <textarea id="editor"></textarea>
22
22
  </div>
@@ -6,8 +6,8 @@
6
6
  <link rel="shortcut icon" href="img/favicon.ico" />
7
7
  <title>Whistle Web Debugger</title>
8
8
  </head>
9
- <body>
9
+ <body style="overscroll-behavior-x: none;">
10
10
  <div id="container" class="main"></div>
11
- <script src="js/index.js?v=2.8.10"></script>
11
+ <script src="js/index.js?v=2.9.0"></script>
12
12
  </body>
13
13
  </html>