@@ -8,11 +8,14 @@ import { Headers } from '../../types';
88import { css , styled } from '../../styles' ;
99import { WarningIcon } from '../../icons' ;
1010import { uploadFile } from '../../util/ui' ;
11- import { asError } from '../../util/error' ;
11+ import { asError , UnreachableCheck } from '../../util/error' ;
12+ import { byteLength , asBuffer , isProbablyUtf8 } from '../../util' ;
1213
1314import {
1415 Handler ,
15- RuleType
16+ RuleType ,
17+ getRulePartKey ,
18+ AvailableHandlerKey
1619} from '../../model/rules/rules' ;
1720import {
1821 StaticResponseHandler ,
@@ -29,9 +32,12 @@ import {
2932 FromFileResponseHandler
3033} from '../../model/rules/definitions/http-rule-definitions' ;
3134import {
32- WebSocketPassThroughHandler
35+ WebSocketPassThroughHandler ,
36+ EchoWebSocketHandlerDefinition ,
37+ RejectWebSocketHandlerDefinition ,
38+ ListenWebSocketHandlerDefinition
3339} 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' ;
3541import { MethodName , MethodNames } from '../../model/http/methods' ;
3642import {
3743 getDefaultMimeType ,
@@ -45,7 +51,6 @@ import { TextInput, Select, Button } from '../common/inputs';
4551import { EditableHeaders } from '../common/editable-headers' ;
4652import { EditableStatus } from '../common/editable-status' ;
4753import { FormatButton } from '../common/format-button' ;
48- import { byteLength , asBuffer , isProbablyUtf8 } from '../../util' ;
4954
5055type HandlerConfigProps < H extends Handler > = {
5156 ruleType : RuleType ;
@@ -86,32 +91,39 @@ export function HandlerConfiguration(props: {
8691 onInvalidState : onInvalidState || _ . noop
8792 } ;
8893
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 ) ;
112126 }
113-
114- throw new Error ( 'Unknown handler: ' + handler . type ) ;
115127}
116128
117129const SectionLabel = styled . h2 `
@@ -169,10 +181,12 @@ function getHeaderValue(headers: Headers, headerName: string): string | undefine
169181}
170182
171183@observer
172- class StaticResponseHandlerConfig extends React . Component < HandlerConfigProps < StaticResponseHandler > > {
184+ class StaticResponseHandlerConfig extends HandlerConfig < StaticResponseHandler | RejectWebSocketHandlerDefinition > {
173185
174186 @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 ;
176190
177191 @observable
178192 statusMessage = this . props . handler . statusMessage ;
@@ -184,7 +198,10 @@ class StaticResponseHandlerConfig extends React.Component<HandlerConfigProps<Sta
184198 contentType : EditableContentType = 'text' ;
185199
186200 @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+ ) ;
188205
189206 componentDidMount ( ) {
190207 // If any of our data fields change, rebuild & update the handler
@@ -194,7 +211,10 @@ class StaticResponseHandlerConfig extends React.Component<HandlerConfigProps<Sta
194211
195212 // If the handler changes (or when its set initially), update our data fields
196213 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+
198218 runInAction ( ( ) => {
199219 this . statusCode = status ;
200220 this . statusMessage = statusMessage ;
@@ -342,12 +362,19 @@ class StaticResponseHandlerConfig extends React.Component<HandlerConfigProps<Sta
342362 ) return this . props . onInvalidState ( ) ;
343363
344364 this . props . onChange (
345- new StaticResponseHandler (
365+ this . props . ruleType === 'http'
366+ ? new StaticResponseHandler (
346367 this . statusCode ,
347368 this . statusMessage ,
348369 this . body ,
349370 this . headers
350371 )
372+ : new RejectWebSocketHandlerDefinition (
373+ this . statusCode ,
374+ this . statusMessage ?? getStatusMessage ( this . statusCode ) ,
375+ this . headers ,
376+ this . body
377+ )
351378 ) ;
352379 }
353380}
@@ -376,7 +403,7 @@ const BodyFilePath = styled.div`
376403` ;
377404
378405@observer
379- class FromFileResponseHandlerConfig extends React . Component < HandlerConfigProps < FromFileResponseHandler > > {
406+ class FromFileResponseHandlerConfig extends HandlerConfig < FromFileResponseHandler > {
380407
381408 @observable
382409 statusCode : number | undefined = this . props . handler . status ;
@@ -668,9 +695,7 @@ const SelectTransform = styled(Select)`
668695
669696@inject ( 'rulesStore' )
670697@observer
671- class TransformingHandlerConfig extends React . Component < HandlerConfigProps < TransformingHandler > & {
672- rulesStore ?: RulesStore
673- } > {
698+ class TransformingHandlerConfig extends HandlerConfig < TransformingHandler , { rulesStore ?: RulesStore } > {
674699
675700 @observable
676701 transformRequest = this . props . handler . transformRequest || { } ;
@@ -1091,11 +1116,16 @@ const JsonUpdateTransformConfig = (props: {
10911116} ;
10921117
10931118@observer
1094- class PassThroughHandlerConfig extends HandlerConfig < PassThroughHandler > {
1119+ class PassThroughHandlerConfig extends HandlerConfig < PassThroughHandler | WebSocketPassThroughHandler > {
10951120 render ( ) {
10961121 return < ConfigContainer >
10971122 < 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.
10991129 </ ConfigExplanation >
11001130 </ ConfigContainer > ;
11011131 }
@@ -1160,7 +1190,7 @@ class TimeoutHandlerConfig extends HandlerConfig<TimeoutHandler> {
11601190 < ConfigExplanation >
11611191 When a matching {
11621192 this . props . ruleType === 'http'
1163- ? 'HTTP '
1193+ ? 'request '
11641194 // ruleType === 'websocket'
11651195 : 'WebSocket'
11661196 } is received, the server will keep the connection open but do nothing.
@@ -1178,11 +1208,36 @@ class CloseConnectionHandlerConfig extends HandlerConfig<CloseConnectionHandler>
11781208 < ConfigExplanation >
11791209 As soon as a matching {
11801210 this . props . ruleType === 'http'
1181- ? 'HTTP '
1211+ ? 'request '
11821212 // ruleType === 'websocket'
11831213 : 'WebSocket'
11841214 } is received, the connection will be closed, with no response.
11851215 </ ConfigExplanation >
11861216 </ ConfigContainer > ;
11871217 }
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+ }
11881243}
0 commit comments