@@ -8,11 +8,14 @@ import { Headers } from '../../types';
8
8
import { css , styled } from '../../styles' ;
9
9
import { WarningIcon } from '../../icons' ;
10
10
import { uploadFile } from '../../util/ui' ;
11
- import { asError } from '../../util/error' ;
11
+ import { asError , UnreachableCheck } from '../../util/error' ;
12
+ import { byteLength , asBuffer , isProbablyUtf8 } from '../../util' ;
12
13
13
14
import {
14
15
Handler ,
15
- RuleType
16
+ RuleType ,
17
+ getRulePartKey ,
18
+ AvailableHandlerKey
16
19
} from '../../model/rules/rules' ;
17
20
import {
18
21
StaticResponseHandler ,
@@ -29,9 +32,12 @@ import {
29
32
FromFileResponseHandler
30
33
} from '../../model/rules/definitions/http-rule-definitions' ;
31
34
import {
32
- WebSocketPassThroughHandler
35
+ WebSocketPassThroughHandler ,
36
+ EchoWebSocketHandlerDefinition ,
37
+ RejectWebSocketHandlerDefinition ,
38
+ ListenWebSocketHandlerDefinition
33
39
} from '../../model/rules/definitions/websocket-rule-definitions' ;
34
- import { HEADER_NAME_REGEX } from '../../model/http/http-docs' ;
40
+ import { getStatusMessage , HEADER_NAME_REGEX } from '../../model/http/http-docs' ;
35
41
import { MethodName , MethodNames } from '../../model/http/methods' ;
36
42
import {
37
43
getDefaultMimeType ,
@@ -45,7 +51,6 @@ import { TextInput, Select, Button } from '../common/inputs';
45
51
import { EditableHeaders } from '../common/editable-headers' ;
46
52
import { EditableStatus } from '../common/editable-status' ;
47
53
import { FormatButton } from '../common/format-button' ;
48
- import { byteLength , asBuffer , isProbablyUtf8 } from '../../util' ;
49
54
50
55
type HandlerConfigProps < H extends Handler > = {
51
56
ruleType : RuleType ;
@@ -86,32 +91,39 @@ export function HandlerConfiguration(props: {
86
91
onInvalidState : onInvalidState || _ . noop
87
92
} ;
88
93
89
- if ( handler instanceof StaticResponseHandler ) {
90
- return < StaticResponseHandlerConfig { ...configProps } /> ;
91
- } else if ( handler instanceof FromFileResponseHandler ) {
92
- return < FromFileResponseHandlerConfig { ...configProps } /> ;
93
- } else if ( handler instanceof ForwardToHostHandler ) {
94
- return < ForwardToHostHandlerConfig { ...configProps } /> ;
95
- } else if (
96
- handler instanceof PassThroughHandler ||
97
- handler instanceof WebSocketPassThroughHandler
98
- ) {
99
- return < PassThroughHandlerConfig { ...configProps } /> ;
100
- } else if ( handler instanceof TransformingHandler ) {
101
- return < TransformingHandlerConfig { ...configProps } /> ;
102
- } else if ( handler instanceof RequestBreakpointHandler ) {
103
- return < RequestBreakpointHandlerConfig { ...configProps } /> ;
104
- } else if ( handler instanceof ResponseBreakpointHandler ) {
105
- return < ResponseBreakpointHandlerConfig { ...configProps } /> ;
106
- } else if ( handler instanceof RequestAndResponseBreakpointHandler ) {
107
- return < RequestAndResponseBreakpointHandlerConfig { ...configProps } /> ;
108
- } else if ( handler instanceof TimeoutHandler ) {
109
- return < TimeoutHandlerConfig { ...configProps } /> ;
110
- } else if ( handler instanceof CloseConnectionHandler ) {
111
- return < CloseConnectionHandlerConfig { ...configProps } /> ;
94
+ const handlerKey = getRulePartKey ( handler ) as AvailableHandlerKey ;
95
+
96
+ switch ( handlerKey ) {
97
+ case 'simple' :
98
+ return < StaticResponseHandlerConfig { ...configProps } /> ;
99
+ case 'file' :
100
+ return < FromFileResponseHandlerConfig { ...configProps } /> ;
101
+ case 'forward-to-host' :
102
+ return < ForwardToHostHandlerConfig { ...configProps } /> ;
103
+ case 'passthrough' :
104
+ case 'ws-passthrough' :
105
+ return < PassThroughHandlerConfig { ...configProps } /> ;
106
+ case 'req-res-transformer' :
107
+ return < TransformingHandlerConfig { ...configProps } /> ;
108
+ case 'request-breakpoint' :
109
+ return < RequestBreakpointHandlerConfig { ...configProps } /> ;
110
+ case 'response-breakpoint' :
111
+ return < ResponseBreakpointHandlerConfig { ...configProps } /> ;
112
+ case 'request-and-response-breakpoint' :
113
+ return < RequestAndResponseBreakpointHandlerConfig { ...configProps } /> ;
114
+ case 'timeout' :
115
+ return < TimeoutHandlerConfig { ...configProps } /> ;
116
+ case 'close-connection' :
117
+ return < CloseConnectionHandlerConfig { ...configProps } /> ;
118
+ case 'ws-echo' :
119
+ return < WebSocketEchoHandlerConfig { ...configProps } /> ;
120
+ case 'ws-reject' :
121
+ return < StaticResponseHandlerConfig { ...configProps } /> ;
122
+ case 'ws-listen' :
123
+ return < WebSocketListenHandlerConfig { ...configProps } /> ;
124
+ default :
125
+ throw new UnreachableCheck ( handlerKey ) ;
112
126
}
113
-
114
- throw new Error ( 'Unknown handler: ' + handler . type ) ;
115
127
}
116
128
117
129
const SectionLabel = styled . h2 `
@@ -169,10 +181,12 @@ function getHeaderValue(headers: Headers, headerName: string): string | undefine
169
181
}
170
182
171
183
@observer
172
- class StaticResponseHandlerConfig extends React . Component < HandlerConfigProps < StaticResponseHandler > > {
184
+ class StaticResponseHandlerConfig extends HandlerConfig < StaticResponseHandler | RejectWebSocketHandlerDefinition > {
173
185
174
186
@observable
175
- statusCode : number | undefined = this . props . handler . status ;
187
+ statusCode : number | undefined = ( this . props . handler instanceof StaticResponseHandler )
188
+ ? this . props . handler . status
189
+ : this . props . handler . statusCode ;
176
190
177
191
@observable
178
192
statusMessage = this . props . handler . statusMessage ;
@@ -184,7 +198,10 @@ class StaticResponseHandlerConfig extends React.Component<HandlerConfigProps<Sta
184
198
contentType : EditableContentType = 'text' ;
185
199
186
200
@observable
187
- body = asBuffer ( this . props . handler . data ) ;
201
+ body = asBuffer ( this . props . handler instanceof StaticResponseHandler
202
+ ? this . props . handler . data
203
+ : this . props . handler . body
204
+ ) ;
188
205
189
206
componentDidMount ( ) {
190
207
// If any of our data fields change, rebuild & update the handler
@@ -194,7 +211,10 @@ class StaticResponseHandlerConfig extends React.Component<HandlerConfigProps<Sta
194
211
195
212
// If the handler changes (or when its set initially), update our data fields
196
213
disposeOnUnmount ( this , autorun ( ( ) => {
197
- const { status, statusMessage, headers, data } = this . props . handler ;
214
+ const { status, statusMessage, headers, data } = this . props . handler instanceof StaticResponseHandler
215
+ ? this . props . handler
216
+ : { ...this . props . handler , status : this . props . handler . statusCode , data : this . props . handler . body } ;
217
+
198
218
runInAction ( ( ) => {
199
219
this . statusCode = status ;
200
220
this . statusMessage = statusMessage ;
@@ -342,12 +362,19 @@ class StaticResponseHandlerConfig extends React.Component<HandlerConfigProps<Sta
342
362
) return this . props . onInvalidState ( ) ;
343
363
344
364
this . props . onChange (
345
- new StaticResponseHandler (
365
+ this . props . ruleType === 'http'
366
+ ? new StaticResponseHandler (
346
367
this . statusCode ,
347
368
this . statusMessage ,
348
369
this . body ,
349
370
this . headers
350
371
)
372
+ : new RejectWebSocketHandlerDefinition (
373
+ this . statusCode ,
374
+ this . statusMessage ?? getStatusMessage ( this . statusCode ) ,
375
+ this . headers ,
376
+ this . body
377
+ )
351
378
) ;
352
379
}
353
380
}
@@ -376,7 +403,7 @@ const BodyFilePath = styled.div`
376
403
` ;
377
404
378
405
@observer
379
- class FromFileResponseHandlerConfig extends React . Component < HandlerConfigProps < FromFileResponseHandler > > {
406
+ class FromFileResponseHandlerConfig extends HandlerConfig < FromFileResponseHandler > {
380
407
381
408
@observable
382
409
statusCode : number | undefined = this . props . handler . status ;
@@ -668,9 +695,7 @@ const SelectTransform = styled(Select)`
668
695
669
696
@inject ( 'rulesStore' )
670
697
@observer
671
- class TransformingHandlerConfig extends React . Component < HandlerConfigProps < TransformingHandler > & {
672
- rulesStore ?: RulesStore
673
- } > {
698
+ class TransformingHandlerConfig extends HandlerConfig < TransformingHandler , { rulesStore ?: RulesStore } > {
674
699
675
700
@observable
676
701
transformRequest = this . props . handler . transformRequest || { } ;
@@ -1091,11 +1116,16 @@ const JsonUpdateTransformConfig = (props: {
1091
1116
} ;
1092
1117
1093
1118
@observer
1094
- class PassThroughHandlerConfig extends HandlerConfig < PassThroughHandler > {
1119
+ class PassThroughHandlerConfig extends HandlerConfig < PassThroughHandler | WebSocketPassThroughHandler > {
1095
1120
render ( ) {
1096
1121
return < ConfigContainer >
1097
1122
< ConfigExplanation >
1098
- All matching traffic will be transparently passed through to the upstream target host.
1123
+ All matching {
1124
+ this . props . ruleType === 'http'
1125
+ ? 'requests'
1126
+ // ruleType === 'websocket'
1127
+ : 'WebSockets'
1128
+ } will be transparently passed through to the upstream target host.
1099
1129
</ ConfigExplanation >
1100
1130
</ ConfigContainer > ;
1101
1131
}
@@ -1160,7 +1190,7 @@ class TimeoutHandlerConfig extends HandlerConfig<TimeoutHandler> {
1160
1190
< ConfigExplanation >
1161
1191
When a matching {
1162
1192
this . props . ruleType === 'http'
1163
- ? 'HTTP '
1193
+ ? 'request '
1164
1194
// ruleType === 'websocket'
1165
1195
: 'WebSocket'
1166
1196
} is received, the server will keep the connection open but do nothing.
@@ -1178,11 +1208,36 @@ class CloseConnectionHandlerConfig extends HandlerConfig<CloseConnectionHandler>
1178
1208
< ConfigExplanation >
1179
1209
As soon as a matching {
1180
1210
this . props . ruleType === 'http'
1181
- ? 'HTTP '
1211
+ ? 'request '
1182
1212
// ruleType === 'websocket'
1183
1213
: 'WebSocket'
1184
1214
} is received, the connection will be closed, with no response.
1185
1215
</ ConfigExplanation >
1186
1216
</ ConfigContainer > ;
1187
1217
}
1218
+ }
1219
+
1220
+ @observer
1221
+ class WebSocketEchoHandlerConfig extends HandlerConfig < EchoWebSocketHandlerDefinition > {
1222
+ render ( ) {
1223
+ return < ConfigContainer >
1224
+ < ConfigExplanation >
1225
+ The WebSocket will be opened successfully, but not forwarded upstream, and every
1226
+ message that's sent will be echoed back to the client until the client closes
1227
+ the connection.
1228
+ </ ConfigExplanation >
1229
+ </ ConfigContainer > ;
1230
+ }
1231
+ }
1232
+
1233
+ @observer
1234
+ class WebSocketListenHandlerConfig extends HandlerConfig < ListenWebSocketHandlerDefinition > {
1235
+ render ( ) {
1236
+ return < ConfigContainer >
1237
+ < ConfigExplanation >
1238
+ The WebSocket will be opened successfully, but not forwarded upstream. All
1239
+ messages from the client will be accepted, but no responses will be sent.
1240
+ </ ConfigExplanation >
1241
+ </ ConfigContainer > ;
1242
+ }
1188
1243
}
0 commit comments