web flow filter refactoring

addon-dailer
lqqyt2423 2 years ago
parent 043f32ccb8
commit 858b8d2274

@ -0,0 +1,125 @@
import type { Flow, Header } from './flow'
const FLOW_FILTER_SCOPES = ['url', 'method', 'code', 'header', 'reqheader', 'resheader', 'body', 'reqbody', 'resbody', 'all'] as const
type FlowFilterScope = typeof FLOW_FILTER_SCOPES[number]
export class FlowFilter {
private keyword: string | RegExp | undefined
private scope: FlowFilterScope = 'url'
constructor(text: string) {
text = text.trim()
if (!text) return
for (const scope of FLOW_FILTER_SCOPES) {
if (text.startsWith(`${scope}:`)) {
this.scope = scope
text = text.replace(`${scope}:`, '').trim()
break
}
}
if (!text) return
// regexp
if (text.startsWith('/') && (text.endsWith('/') || text.endsWith('/i'))) {
let flags: string | undefined
if (text.endsWith('i')) {
flags = 'i'
text = text.slice(0, -1)
}
text = text.slice(1, -1).trim()
if (!text) return
this.keyword = new RegExp(text, flags)
}
// string
else {
this.keyword = text
}
}
public match(flow: Flow): boolean {
switch (this.scope) {
case 'url':
return this.matchUrl(flow)
case 'method':
return this.matchMethod(flow)
case 'code':
return this.matchCode(flow)
case 'reqheader':
return this.matchReqHeader(flow)
case 'resheader':
return this.matchResHeader(flow)
case 'header':
return this.matchHeader(flow)
case 'reqbody':
return this.matchReqBody(flow)
case 'resbody':
return this.matchResBody(flow)
case 'body':
return this.matchBody(flow)
case 'all':
return this.matchAll(flow)
default:
throw new Error(`invalid scope ${this.scope}`)
}
}
private matchUrl(flow: Flow): boolean {
return this.matchKeyword(flow.request.url)
}
private matchMethod(flow: Flow): boolean {
return this.matchKeyword(flow.request.method) || this.matchKeyword(flow.request.method.toLowerCase())
}
private matchCode(flow: Flow): boolean {
if (!flow.response) return false
return this.matchKeyword(flow.response.statusCode.toString())
}
private _matchHeader(header: Header): boolean {
return Object.entries(header).some(([key, vals]) => {
return [key].concat(vals).some(text => this.matchKeyword(text))
})
}
private matchReqHeader(flow: Flow): boolean {
return this._matchHeader(flow.request.header)
}
private matchResHeader(flow: Flow): boolean {
if (!flow.response) return false
return this._matchHeader(flow.response.header)
}
private matchHeader(flow: Flow): boolean {
return this.matchReqHeader(flow) || this.matchResHeader(flow)
}
private matchReqBody(flow: Flow): boolean {
const body = flow.requestBody()
if (!body) return false
return this.matchKeyword(body)
}
private matchResBody(flow: Flow): boolean {
const body = flow.responseBody()
if (!body) return false
return this.matchKeyword(body)
}
private matchBody(flow: Flow): boolean {
return this.matchReqBody(flow) || this.matchResBody(flow)
}
private matchAll(flow: Flow): boolean {
return this.matchUrl(flow) || this.matchMethod(flow) || this.matchHeader(flow) || this.matchBody(flow)
}
private matchKeyword(text: string): boolean {
if (!this.keyword) return true
if (!text) return false
if (this.keyword instanceof RegExp) return this.keyword.test(text)
return text.includes(this.keyword)
}
}

@ -1,6 +1,7 @@
import type { ConnectionManager, IConnection } from './connection' import type { ConnectionManager, IConnection } from './connection'
import { IMessage, MessageType } from './message' import { IMessage, MessageType } from './message'
import { arrayBufferToBase64, bufHexView, getSize, isTextBody } from './utils' import { arrayBufferToBase64, bufHexView, getSize, isTextBody } from './utils'
import { FlowFilter } from './filter'
export type Header = Record<string, string[]> export type Header = Record<string, string[]>
@ -262,130 +263,6 @@ export class Flow {
} }
} }
const FLOW_FILTER_SCOPES = ['url', 'method', 'code', 'header', 'reqheader', 'resheader', 'body', 'reqbody', 'resbody', 'all'] as const
type FlowFilterScope = typeof FLOW_FILTER_SCOPES[number]
class FlowFilter {
private keyword: string | RegExp | undefined
private scope: FlowFilterScope = 'url'
constructor(text: string) {
text = text.trim()
if (!text) return
for (const scope of FLOW_FILTER_SCOPES) {
if (text.startsWith(`${scope}:`)) {
this.scope = scope
text = text.replace(`${scope}:`, '').trim()
break
}
}
if (!text) return
// regexp
if (text.startsWith('/') && (text.endsWith('/') || text.endsWith('/i'))) {
let flags: string | undefined
if (text.endsWith('i')) {
flags = 'i'
text = text.slice(0, -1)
}
text = text.slice(1, -1).trim()
if (!text) return
this.keyword = new RegExp(text, flags)
}
// string
else {
this.keyword = text
}
}
public match(flow: Flow): boolean {
switch (this.scope) {
case 'url':
return this.matchUrl(flow)
case 'method':
return this.matchMethod(flow)
case 'code':
return this.matchCode(flow)
case 'reqheader':
return this.matchReqHeader(flow)
case 'resheader':
return this.matchResHeader(flow)
case 'header':
return this.matchHeader(flow)
case 'reqbody':
return this.matchReqBody(flow)
case 'resbody':
return this.matchResBody(flow)
case 'body':
return this.matchBody(flow)
case 'all':
return this.matchAll(flow)
default:
throw new Error(`invalid scope ${this.scope}`)
}
}
private matchUrl(flow: Flow): boolean {
return this.matchKeyword(flow.request.url)
}
private matchMethod(flow: Flow): boolean {
return this.matchKeyword(flow.request.method) || this.matchKeyword(flow.request.method.toLowerCase())
}
private matchCode(flow: Flow): boolean {
if (!flow.response) return false
return this.matchKeyword(flow.response.statusCode.toString())
}
private _matchHeader(header: Header): boolean {
return Object.entries(header).some(([key, vals]) => {
return [key].concat(vals).some(text => this.matchKeyword(text))
})
}
private matchReqHeader(flow: Flow): boolean {
return this._matchHeader(flow.request.header)
}
private matchResHeader(flow: Flow): boolean {
if (!flow.response) return false
return this._matchHeader(flow.response.header)
}
private matchHeader(flow: Flow): boolean {
return this.matchReqHeader(flow) || this.matchResHeader(flow)
}
private matchReqBody(flow: Flow): boolean {
const body = flow.requestBody()
if (!body) return false
return this.matchKeyword(body)
}
private matchResBody(flow: Flow): boolean {
const body = flow.responseBody()
if (!body) return false
return this.matchKeyword(body)
}
private matchBody(flow: Flow): boolean {
return this.matchReqBody(flow) || this.matchResBody(flow)
}
private matchAll(flow: Flow): boolean {
return this.matchUrl(flow) || this.matchMethod(flow) || this.matchHeader(flow) || this.matchBody(flow)
}
private matchKeyword(text: string): boolean {
if (!this.keyword) return true
if (!text) return false
if (this.keyword instanceof RegExp) return this.keyword.test(text)
return text.includes(this.keyword)
}
}
export class FlowManager { export class FlowManager {
private items: Flow[] private items: Flow[]
private _map: Map<string, Flow> private _map: Map<string, Flow>

Loading…
Cancel
Save