- Bugs:
- #76 - Node has a constant header size limit of 80kb
- Serve dynamic HTTP/1.1 content on any
http[s]://host:port/pathcombination- 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) => voidNo 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.