- Bugs:
- #76 - Node has a constant header size limit of 80kb
- Serve dynamic HTTP/1.1 content on any
http[s]://host:port/path
combination- can serve pre-configured static responses to regex or glob urls
type GlobPattern = string
type StringMatcher = GlobPattern | RegEx
type StringDictMatcher = { [key: string]: StringMatcher }
type NumberMatcher = number | number[] // list of acceptable numbers
type HttpMethodMatcher = StringMatcher
// all HTTP requests have some basic information
// users would use a `RouteMatcher` to "subscribe" to a certain subset of requests
// no callbacks are supported in matchers - helps cut down on un-needed back-and-forth
// websocket requests to match requests - they are all static
// then, the route is handled by a `RouteHandler`, which will either return a static response
// or send a callback to the driver, where it will be handled
/** Types for Route Matching **/
type RouteMatcher = StringMatcher | RouteMatcherOptions
interface RouteMatcherOptions {
auth?: { username: StringMatcher, password: StringMatcher }
headers?: StringDictMatcher
hostname?: StringMatcher
https?: boolean // serve this over HTTPS
method?: HttpMethodMatcher // defaults to GET
path?: StringMatcher // includes query params
pathname?: StringMatcher // does not include query params
port?: NumberMatcher
query?: StringDictMatcher // match querystring values
url?: StringMatcher
}
/** Types for Route Responses **/
interface CyIncomingResponse {
// an interface like the one brian proposed to make changes to the response
}
interface CyIncomingRequest {
// as much stuff from `incomingmessage` as makes sense to serialize and send
}
type CyResponse = string | object
type CyInterceptor = (res: CyIncomingResponse, send?: () => void) => void
interface CyIncomingHTTPRequest extends CyIncomingRequest {
// if `responseOrInterceptor` is undefined, just forward the modified request to the destination
reply: (responseOrInterceptor?: CyResponse | CyInterceptor) => void
// todo: is this needed, when they could just do `setTimeout(()=>req.reply(), delayMs)`?
// delay: (delayMs: number) => void
}
type HTTPController = (req: CyRequest, next: () => void) => void
interface WebSocketController {
onConnect?: (req: CyIncomingRequest, socket: CyWebSocket) => void
onMessage?: (socket: CyWebSocket, message: CyWebSocketMessage) => void
onDisconnect?: (socket: CyWebSocket) => void
transport: 'socket.io' // socket.io client over websockets
| 'socket.io-longpolling' // socket.io client via longpolling
| 'websockets' // vanilla websockets server
}
type RouteHandlerController = HTTPController | WebSocketController
interface RouteHandler = string | object | RouteHandlerController
/** Driver Commands **/
type CyRoute = (matcher: RouteMatcher, handler: RouteHandler) => void
No reply will be sent until a req.reply
is called. req.reply
can only be called once, to call it multiple times is an error.
If next()
is called inside of a HTTPController
, the next matching HTTPController
will be called with a potentially-modified req
.
next()
cannot be called inside of a req.reply
, as at that point, the response is being sent.
If there is not a "next matching HTTPController
" and next()
is called, then the default middleware will be called, which simply does req.reply()
to passthru the request and send the response.
If there is a req.reply
callback that accepts the send
parameter, Cypress will dispatch the modified res
only when send
is called. If it does not accept send
, Cypress will dispatch the modified res
synchronously at the end of the req.reply
callback.