mirror of
https://github.com/yusing/godoxy.git
synced 2026-04-27 10:47:06 +02:00
feat(api): rules playground API
- updated swagger
This commit is contained in:
@@ -81,6 +81,7 @@ func NewHandler() *gin.Engine {
|
|||||||
route.GET("/:which", routeApi.Route)
|
route.GET("/:which", routeApi.Route)
|
||||||
route.GET("/providers", routeApi.Providers)
|
route.GET("/providers", routeApi.Providers)
|
||||||
route.GET("/by_provider", routeApi.ByProvider)
|
route.GET("/by_provider", routeApi.ByProvider)
|
||||||
|
route.POST("/playground", routeApi.Playground)
|
||||||
}
|
}
|
||||||
|
|
||||||
file := v1.Group("/file")
|
file := v1.Group("/file")
|
||||||
|
|||||||
@@ -105,12 +105,6 @@
|
|||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "#/definitions/ErrorResponse"
|
"$ref": "#/definitions/ErrorResponse"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"500": {
|
|
||||||
"description": "Internal Server Error",
|
|
||||||
"schema": {
|
|
||||||
"$ref": "#/definitions/ErrorResponse"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-id": "list",
|
"x-id": "list",
|
||||||
@@ -2135,6 +2129,54 @@
|
|||||||
"operationId": "routes"
|
"operationId": "routes"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/route/playground": {
|
||||||
|
"post": {
|
||||||
|
"description": "Test rules against mock request/response",
|
||||||
|
"consumes": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"produces": [
|
||||||
|
"application/json"
|
||||||
|
],
|
||||||
|
"tags": [
|
||||||
|
"route"
|
||||||
|
],
|
||||||
|
"summary": "Rule Playground",
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"description": "Playground request",
|
||||||
|
"name": "request",
|
||||||
|
"in": "body",
|
||||||
|
"required": true,
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/PlaygroundRequest"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "OK",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/PlaygroundResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"400": {
|
||||||
|
"description": "Bad Request",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ErrorResponse"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"403": {
|
||||||
|
"description": "Forbidden",
|
||||||
|
"schema": {
|
||||||
|
"$ref": "#/definitions/ErrorResponse"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-id": "playground",
|
||||||
|
"operationId": "playground"
|
||||||
|
}
|
||||||
|
},
|
||||||
"/route/providers": {
|
"/route/providers": {
|
||||||
"get": {
|
"get": {
|
||||||
"description": "List route providers",
|
"description": "List route providers",
|
||||||
@@ -2726,6 +2768,83 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
|
"FinalRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"body": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"FinalResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"body": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"statusCode": {
|
||||||
|
"type": "integer",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
"HTTPHeader": {
|
"HTTPHeader": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2799,6 +2918,75 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
|
"HealthInfo": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"detail": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"latency": {
|
||||||
|
"description": "latency in microseconds",
|
||||||
|
"type": "number",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"healthy",
|
||||||
|
"unhealthy",
|
||||||
|
"napping",
|
||||||
|
"starting",
|
||||||
|
"error",
|
||||||
|
"unknown"
|
||||||
|
],
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"description": "uptime in milliseconds",
|
||||||
|
"type": "number",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"HealthInfoWithoutDetail": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"latency": {
|
||||||
|
"description": "latency in microseconds",
|
||||||
|
"type": "number",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"status": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"healthy",
|
||||||
|
"unhealthy",
|
||||||
|
"napping",
|
||||||
|
"starting",
|
||||||
|
"error",
|
||||||
|
"unknown"
|
||||||
|
],
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"uptime": {
|
||||||
|
"description": "uptime in milliseconds",
|
||||||
|
"type": "number",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
"HealthJSON": {
|
"HealthJSON": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -2882,7 +3070,7 @@
|
|||||||
"HealthMap": {
|
"HealthMap": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"$ref": "#/definitions/routes.HealthInfo"
|
"$ref": "#/definitions/HealthInfo"
|
||||||
},
|
},
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
@@ -3494,6 +3682,113 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
|
"MockCookie": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"value": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"MockRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"body": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"cookies": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/MockCookie"
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"host": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"method": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"path": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"query": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"remoteIP": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"MockResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"body": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"headers": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"statusCode": {
|
||||||
|
"type": "integer",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
"NewAgentRequest": {
|
"NewAgentRequest": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"required": [
|
"required": [
|
||||||
@@ -3589,6 +3884,120 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
|
"ParsedRule": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"do": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"isResponseRule": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"on": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"validationError": {
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"PlaygroundRequest": {
|
||||||
|
"type": "object",
|
||||||
|
"required": [
|
||||||
|
"rules"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"mockRequest": {
|
||||||
|
"$ref": "#/definitions/MockRequest"
|
||||||
|
},
|
||||||
|
"mockResponse": {
|
||||||
|
"$ref": "#/definitions/MockResponse"
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/routeApi.RawRule"
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"PlaygroundResponse": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"executionError": {
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"finalRequest": {
|
||||||
|
"$ref": "#/definitions/FinalRequest",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"finalResponse": {
|
||||||
|
"$ref": "#/definitions/FinalResponse",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"matchedRules": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"parsedRules": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"$ref": "#/definitions/ParsedRule"
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"upstreamCalled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"Port": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"listening": {
|
||||||
|
"type": "integer",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"proxy": {
|
||||||
|
"type": "integer",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
"ProviderStats": {
|
"ProviderStats": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
@@ -3844,7 +4253,7 @@
|
|||||||
"x-nullable": true
|
"x-nullable": true
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"$ref": "#/definitions/github_com_yusing_go-proxy_internal_route_types.Port",
|
"$ref": "#/definitions/Port",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
@@ -3868,9 +4277,12 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
|
"rule_file": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": true
|
||||||
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"uniqueItems": true,
|
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/rules.Rule"
|
"$ref": "#/definitions/rules.Rule"
|
||||||
},
|
},
|
||||||
@@ -3878,7 +4290,47 @@
|
|||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"scheme": {
|
"scheme": {
|
||||||
"$ref": "#/definitions/route.Scheme",
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"http",
|
||||||
|
"https",
|
||||||
|
"tcp",
|
||||||
|
"udp",
|
||||||
|
"fileserver"
|
||||||
|
],
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_certificate": {
|
||||||
|
"description": "Path to client certificate",
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_certificate_key": {
|
||||||
|
"description": "Path to client certificate key",
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_protocols": {
|
||||||
|
"description": "Allowed TLS protocols",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_server_name": {
|
||||||
|
"description": "SSL/TLS proxy options (nginx-like)",
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_trusted_certificate": {
|
||||||
|
"description": "Path to trusted CA certificates",
|
||||||
|
"type": "string",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
}
|
}
|
||||||
@@ -3975,7 +4427,7 @@
|
|||||||
"statuses": {
|
"statuses": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"additionalProperties": {
|
"additionalProperties": {
|
||||||
"$ref": "#/definitions/routes.HealthInfo"
|
"$ref": "#/definitions/HealthInfoWithoutDetail"
|
||||||
},
|
},
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
@@ -4499,7 +4951,6 @@
|
|||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"iops": {
|
"iops": {
|
||||||
"description": "godoxy",
|
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
@@ -4522,7 +4973,6 @@
|
|||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"read_speed": {
|
"read_speed": {
|
||||||
"description": "godoxy",
|
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
@@ -4538,7 +4988,6 @@
|
|||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"write_speed": {
|
"write_speed": {
|
||||||
"description": "godoxy",
|
|
||||||
"type": "number",
|
"type": "number",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
@@ -4566,7 +5015,7 @@
|
|||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"total": {
|
"total": {
|
||||||
"type": "integer",
|
"type": "number",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
@@ -4628,31 +5077,9 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"github_com_yusing_go-proxy_internal_route_types.Port": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"listening": {
|
|
||||||
"type": "integer",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"proxy": {
|
|
||||||
"type": "integer",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"homepage.FetchResult": {
|
"homepage.FetchResult": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"errMsg": {
|
|
||||||
"type": "string",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"icon": {
|
"icon": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"items": {
|
"items": {
|
||||||
@@ -4739,29 +5166,11 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"free": {
|
|
||||||
"description": "This is the kernel's notion of free memory; RAM chips whose bits nobody\ncares about the value of right now. For a human consumable number,\nAvailable is what you really want.",
|
|
||||||
"type": "integer",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"total": {
|
|
||||||
"description": "Total amount of RAM on this system",
|
|
||||||
"type": "integer",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"used": {
|
"used": {
|
||||||
"description": "RAM used by programs\n\nThis value is computed from the kernel specific values.",
|
"description": "RAM used by programs\n\nThis value is computed from the kernel specific values.",
|
||||||
"type": "integer",
|
"type": "integer",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
|
||||||
"used_percent": {
|
|
||||||
"description": "Percentage of RAM used by programs\n\nThis value is computed from the kernel specific values.",
|
|
||||||
"type": "number",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
@@ -4907,7 +5316,7 @@
|
|||||||
"x-nullable": true
|
"x-nullable": true
|
||||||
},
|
},
|
||||||
"port": {
|
"port": {
|
||||||
"$ref": "#/definitions/github_com_yusing_go-proxy_internal_route_types.Port",
|
"$ref": "#/definitions/Port",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
@@ -4931,9 +5340,12 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
|
"rule_file": {
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": true
|
||||||
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"type": "array",
|
"type": "array",
|
||||||
"uniqueItems": true,
|
|
||||||
"items": {
|
"items": {
|
||||||
"$ref": "#/definitions/rules.Rule"
|
"$ref": "#/definitions/rules.Rule"
|
||||||
},
|
},
|
||||||
@@ -4941,7 +5353,47 @@
|
|||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"scheme": {
|
"scheme": {
|
||||||
"$ref": "#/definitions/route.Scheme",
|
"type": "string",
|
||||||
|
"enum": [
|
||||||
|
"http",
|
||||||
|
"https",
|
||||||
|
"tcp",
|
||||||
|
"udp",
|
||||||
|
"fileserver"
|
||||||
|
],
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_certificate": {
|
||||||
|
"description": "Path to client certificate",
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_certificate_key": {
|
||||||
|
"description": "Path to client certificate key",
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_protocols": {
|
||||||
|
"description": "Allowed TLS protocols",
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_server_name": {
|
||||||
|
"description": "SSL/TLS proxy options (nginx-like)",
|
||||||
|
"type": "string",
|
||||||
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
},
|
||||||
|
"ssl_trusted_certificate": {
|
||||||
|
"description": "Path to trusted CA certificates",
|
||||||
|
"type": "string",
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
}
|
}
|
||||||
@@ -4949,22 +5401,25 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"route.Scheme": {
|
"routeApi.RawRule": {
|
||||||
"type": "string",
|
"type": "object",
|
||||||
"enum": [
|
"properties": {
|
||||||
"http",
|
"do": {
|
||||||
"https",
|
"type": "string",
|
||||||
"tcp",
|
"x-nullable": false,
|
||||||
"udp",
|
"x-omitempty": false
|
||||||
"fileserver"
|
},
|
||||||
],
|
"name": {
|
||||||
"x-enum-varnames": [
|
"type": "string",
|
||||||
"SchemeHTTP",
|
"x-nullable": false,
|
||||||
"SchemeHTTPS",
|
"x-omitempty": false
|
||||||
"SchemeTCP",
|
},
|
||||||
"SchemeUDP",
|
"on": {
|
||||||
"SchemeFileServer"
|
"type": "string",
|
||||||
],
|
"x-nullable": false,
|
||||||
|
"x-omitempty": false
|
||||||
|
}
|
||||||
|
},
|
||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
@@ -4979,43 +5434,6 @@
|
|||||||
"x-nullable": false,
|
"x-nullable": false,
|
||||||
"x-omitempty": false
|
"x-omitempty": false
|
||||||
},
|
},
|
||||||
"routes.HealthInfo": {
|
|
||||||
"type": "object",
|
|
||||||
"properties": {
|
|
||||||
"detail": {
|
|
||||||
"type": "string",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"latency": {
|
|
||||||
"description": "latency in microseconds",
|
|
||||||
"type": "number",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"status": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": [
|
|
||||||
"healthy",
|
|
||||||
"unhealthy",
|
|
||||||
"napping",
|
|
||||||
"starting",
|
|
||||||
"error",
|
|
||||||
"unknown"
|
|
||||||
],
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"uptime": {
|
|
||||||
"description": "uptime in milliseconds",
|
|
||||||
"type": "number",
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"x-nullable": false,
|
|
||||||
"x-omitempty": false
|
|
||||||
},
|
|
||||||
"rules.Rule": {
|
"rules.Rule": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -217,6 +217,42 @@ definitions:
|
|||||||
- FileTypeConfig
|
- FileTypeConfig
|
||||||
- FileTypeProvider
|
- FileTypeProvider
|
||||||
- FileTypeMiddleware
|
- FileTypeMiddleware
|
||||||
|
FinalRequest:
|
||||||
|
properties:
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
headers:
|
||||||
|
additionalProperties:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
host:
|
||||||
|
type: string
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
query:
|
||||||
|
additionalProperties:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
type: object
|
||||||
|
FinalResponse:
|
||||||
|
properties:
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
headers:
|
||||||
|
additionalProperties:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
statusCode:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
HTTPHeader:
|
HTTPHeader:
|
||||||
properties:
|
properties:
|
||||||
key:
|
key:
|
||||||
@@ -248,6 +284,44 @@ definitions:
|
|||||||
additionalProperties: {}
|
additionalProperties: {}
|
||||||
type: object
|
type: object
|
||||||
type: object
|
type: object
|
||||||
|
HealthInfo:
|
||||||
|
properties:
|
||||||
|
detail:
|
||||||
|
type: string
|
||||||
|
latency:
|
||||||
|
description: latency in microseconds
|
||||||
|
type: number
|
||||||
|
status:
|
||||||
|
enum:
|
||||||
|
- healthy
|
||||||
|
- unhealthy
|
||||||
|
- napping
|
||||||
|
- starting
|
||||||
|
- error
|
||||||
|
- unknown
|
||||||
|
type: string
|
||||||
|
uptime:
|
||||||
|
description: uptime in milliseconds
|
||||||
|
type: number
|
||||||
|
type: object
|
||||||
|
HealthInfoWithoutDetail:
|
||||||
|
properties:
|
||||||
|
latency:
|
||||||
|
description: latency in microseconds
|
||||||
|
type: number
|
||||||
|
status:
|
||||||
|
enum:
|
||||||
|
- healthy
|
||||||
|
- unhealthy
|
||||||
|
- napping
|
||||||
|
- starting
|
||||||
|
- error
|
||||||
|
- unknown
|
||||||
|
type: string
|
||||||
|
uptime:
|
||||||
|
description: uptime in milliseconds
|
||||||
|
type: number
|
||||||
|
type: object
|
||||||
HealthJSON:
|
HealthJSON:
|
||||||
properties:
|
properties:
|
||||||
config:
|
config:
|
||||||
@@ -283,7 +357,7 @@ definitions:
|
|||||||
type: object
|
type: object
|
||||||
HealthMap:
|
HealthMap:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
$ref: '#/definitions/routes.HealthInfo'
|
$ref: '#/definitions/HealthInfo'
|
||||||
type: object
|
type: object
|
||||||
HomepageCategory:
|
HomepageCategory:
|
||||||
properties:
|
properties:
|
||||||
@@ -564,6 +638,55 @@ definitions:
|
|||||||
- MetricsPeriod1h
|
- MetricsPeriod1h
|
||||||
- MetricsPeriod1d
|
- MetricsPeriod1d
|
||||||
- MetricsPeriod1mo
|
- MetricsPeriod1mo
|
||||||
|
MockCookie:
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
value:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
MockRequest:
|
||||||
|
properties:
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
cookies:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/MockCookie'
|
||||||
|
type: array
|
||||||
|
headers:
|
||||||
|
additionalProperties:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
host:
|
||||||
|
type: string
|
||||||
|
method:
|
||||||
|
type: string
|
||||||
|
path:
|
||||||
|
type: string
|
||||||
|
query:
|
||||||
|
additionalProperties:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
remoteIP:
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
MockResponse:
|
||||||
|
properties:
|
||||||
|
body:
|
||||||
|
type: string
|
||||||
|
headers:
|
||||||
|
additionalProperties:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
type: object
|
||||||
|
statusCode:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
NewAgentRequest:
|
NewAgentRequest:
|
||||||
properties:
|
properties:
|
||||||
container_runtime:
|
container_runtime:
|
||||||
@@ -612,6 +735,56 @@ definitions:
|
|||||||
format: base64
|
format: base64
|
||||||
type: string
|
type: string
|
||||||
type: object
|
type: object
|
||||||
|
ParsedRule:
|
||||||
|
properties:
|
||||||
|
do:
|
||||||
|
type: string
|
||||||
|
isResponseRule:
|
||||||
|
type: boolean
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
"on":
|
||||||
|
type: string
|
||||||
|
validationError: {}
|
||||||
|
type: object
|
||||||
|
PlaygroundRequest:
|
||||||
|
properties:
|
||||||
|
mockRequest:
|
||||||
|
$ref: '#/definitions/MockRequest'
|
||||||
|
mockResponse:
|
||||||
|
$ref: '#/definitions/MockResponse'
|
||||||
|
rules:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/routeApi.RawRule'
|
||||||
|
type: array
|
||||||
|
required:
|
||||||
|
- rules
|
||||||
|
type: object
|
||||||
|
PlaygroundResponse:
|
||||||
|
properties:
|
||||||
|
executionError: {}
|
||||||
|
finalRequest:
|
||||||
|
$ref: '#/definitions/FinalRequest'
|
||||||
|
finalResponse:
|
||||||
|
$ref: '#/definitions/FinalResponse'
|
||||||
|
matchedRules:
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
parsedRules:
|
||||||
|
items:
|
||||||
|
$ref: '#/definitions/ParsedRule'
|
||||||
|
type: array
|
||||||
|
upstreamCalled:
|
||||||
|
type: boolean
|
||||||
|
type: object
|
||||||
|
Port:
|
||||||
|
properties:
|
||||||
|
listening:
|
||||||
|
type: integer
|
||||||
|
proxy:
|
||||||
|
type: integer
|
||||||
|
type: object
|
||||||
ProviderStats:
|
ProviderStats:
|
||||||
properties:
|
properties:
|
||||||
reverse_proxies:
|
reverse_proxies:
|
||||||
@@ -738,7 +911,7 @@ definitions:
|
|||||||
type: array
|
type: array
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
port:
|
port:
|
||||||
$ref: '#/definitions/github_com_yusing_go-proxy_internal_route_types.Port'
|
$ref: '#/definitions/Port'
|
||||||
provider:
|
provider:
|
||||||
description: for backward compatibility
|
description: for backward compatibility
|
||||||
type: string
|
type: string
|
||||||
@@ -749,13 +922,38 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
root:
|
root:
|
||||||
type: string
|
type: string
|
||||||
|
rule_file:
|
||||||
|
type: string
|
||||||
|
x-nullable: true
|
||||||
rules:
|
rules:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/rules.Rule'
|
$ref: '#/definitions/rules.Rule'
|
||||||
type: array
|
type: array
|
||||||
uniqueItems: true
|
|
||||||
scheme:
|
scheme:
|
||||||
$ref: '#/definitions/route.Scheme'
|
enum:
|
||||||
|
- http
|
||||||
|
- https
|
||||||
|
- tcp
|
||||||
|
- udp
|
||||||
|
- fileserver
|
||||||
|
type: string
|
||||||
|
ssl_certificate:
|
||||||
|
description: Path to client certificate
|
||||||
|
type: string
|
||||||
|
ssl_certificate_key:
|
||||||
|
description: Path to client certificate key
|
||||||
|
type: string
|
||||||
|
ssl_protocols:
|
||||||
|
description: Allowed TLS protocols
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ssl_server_name:
|
||||||
|
description: SSL/TLS proxy options (nginx-like)
|
||||||
|
type: string
|
||||||
|
ssl_trusted_certificate:
|
||||||
|
description: Path to trusted CA certificates
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
RouteProvider:
|
RouteProvider:
|
||||||
properties:
|
properties:
|
||||||
@@ -798,7 +996,7 @@ definitions:
|
|||||||
properties:
|
properties:
|
||||||
statuses:
|
statuses:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
$ref: '#/definitions/routes.HealthInfo'
|
$ref: '#/definitions/HealthInfoWithoutDetail'
|
||||||
type: object
|
type: object
|
||||||
timestamp:
|
timestamp:
|
||||||
type: integer
|
type: integer
|
||||||
@@ -1072,7 +1270,6 @@ definitions:
|
|||||||
disk.IOCountersStat:
|
disk.IOCountersStat:
|
||||||
properties:
|
properties:
|
||||||
iops:
|
iops:
|
||||||
description: godoxy
|
|
||||||
type: integer
|
type: integer
|
||||||
name:
|
name:
|
||||||
description: |-
|
description: |-
|
||||||
@@ -1096,14 +1293,12 @@ definitions:
|
|||||||
read_count:
|
read_count:
|
||||||
type: integer
|
type: integer
|
||||||
read_speed:
|
read_speed:
|
||||||
description: godoxy
|
|
||||||
type: number
|
type: number
|
||||||
write_bytes:
|
write_bytes:
|
||||||
type: integer
|
type: integer
|
||||||
write_count:
|
write_count:
|
||||||
type: integer
|
type: integer
|
||||||
write_speed:
|
write_speed:
|
||||||
description: godoxy
|
|
||||||
type: number
|
type: number
|
||||||
type: object
|
type: object
|
||||||
disk.UsageStat:
|
disk.UsageStat:
|
||||||
@@ -1115,7 +1310,7 @@ definitions:
|
|||||||
path:
|
path:
|
||||||
type: string
|
type: string
|
||||||
total:
|
total:
|
||||||
type: integer
|
type: number
|
||||||
used:
|
used:
|
||||||
type: integer
|
type: integer
|
||||||
used_percent:
|
used_percent:
|
||||||
@@ -1156,17 +1351,8 @@ definitions:
|
|||||||
required:
|
required:
|
||||||
- id
|
- id
|
||||||
type: object
|
type: object
|
||||||
github_com_yusing_go-proxy_internal_route_types.Port:
|
|
||||||
properties:
|
|
||||||
listening:
|
|
||||||
type: integer
|
|
||||||
proxy:
|
|
||||||
type: integer
|
|
||||||
type: object
|
|
||||||
homepage.FetchResult:
|
homepage.FetchResult:
|
||||||
properties:
|
properties:
|
||||||
errMsg:
|
|
||||||
type: string
|
|
||||||
icon:
|
icon:
|
||||||
items:
|
items:
|
||||||
format: int32
|
format: int32
|
||||||
@@ -1212,27 +1398,12 @@ definitions:
|
|||||||
|
|
||||||
This value is computed from the kernel specific values.
|
This value is computed from the kernel specific values.
|
||||||
type: integer
|
type: integer
|
||||||
free:
|
|
||||||
description: |-
|
|
||||||
This is the kernel's notion of free memory; RAM chips whose bits nobody
|
|
||||||
cares about the value of right now. For a human consumable number,
|
|
||||||
Available is what you really want.
|
|
||||||
type: integer
|
|
||||||
total:
|
|
||||||
description: Total amount of RAM on this system
|
|
||||||
type: integer
|
|
||||||
used:
|
used:
|
||||||
description: |-
|
description: |-
|
||||||
RAM used by programs
|
RAM used by programs
|
||||||
|
|
||||||
This value is computed from the kernel specific values.
|
This value is computed from the kernel specific values.
|
||||||
type: integer
|
type: integer
|
||||||
used_percent:
|
|
||||||
description: |-
|
|
||||||
Percentage of RAM used by programs
|
|
||||||
|
|
||||||
This value is computed from the kernel specific values.
|
|
||||||
type: number
|
|
||||||
type: object
|
type: object
|
||||||
net.IOCountersStat:
|
net.IOCountersStat:
|
||||||
properties:
|
properties:
|
||||||
@@ -1307,7 +1478,7 @@ definitions:
|
|||||||
type: array
|
type: array
|
||||||
x-nullable: true
|
x-nullable: true
|
||||||
port:
|
port:
|
||||||
$ref: '#/definitions/github_com_yusing_go-proxy_internal_route_types.Port'
|
$ref: '#/definitions/Port'
|
||||||
provider:
|
provider:
|
||||||
description: for backward compatibility
|
description: for backward compatibility
|
||||||
type: string
|
type: string
|
||||||
@@ -1318,54 +1489,54 @@ definitions:
|
|||||||
type: integer
|
type: integer
|
||||||
root:
|
root:
|
||||||
type: string
|
type: string
|
||||||
|
rule_file:
|
||||||
|
type: string
|
||||||
|
x-nullable: true
|
||||||
rules:
|
rules:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/rules.Rule'
|
$ref: '#/definitions/rules.Rule'
|
||||||
type: array
|
type: array
|
||||||
uniqueItems: true
|
|
||||||
scheme:
|
scheme:
|
||||||
$ref: '#/definitions/route.Scheme'
|
enum:
|
||||||
|
- http
|
||||||
|
- https
|
||||||
|
- tcp
|
||||||
|
- udp
|
||||||
|
- fileserver
|
||||||
|
type: string
|
||||||
|
ssl_certificate:
|
||||||
|
description: Path to client certificate
|
||||||
|
type: string
|
||||||
|
ssl_certificate_key:
|
||||||
|
description: Path to client certificate key
|
||||||
|
type: string
|
||||||
|
ssl_protocols:
|
||||||
|
description: Allowed TLS protocols
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
type: array
|
||||||
|
ssl_server_name:
|
||||||
|
description: SSL/TLS proxy options (nginx-like)
|
||||||
|
type: string
|
||||||
|
ssl_trusted_certificate:
|
||||||
|
description: Path to trusted CA certificates
|
||||||
|
type: string
|
||||||
|
type: object
|
||||||
|
routeApi.RawRule:
|
||||||
|
properties:
|
||||||
|
do:
|
||||||
|
type: string
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
"on":
|
||||||
|
type: string
|
||||||
type: object
|
type: object
|
||||||
route.Scheme:
|
|
||||||
enum:
|
|
||||||
- http
|
|
||||||
- https
|
|
||||||
- tcp
|
|
||||||
- udp
|
|
||||||
- fileserver
|
|
||||||
type: string
|
|
||||||
x-enum-varnames:
|
|
||||||
- SchemeHTTP
|
|
||||||
- SchemeHTTPS
|
|
||||||
- SchemeTCP
|
|
||||||
- SchemeUDP
|
|
||||||
- SchemeFileServer
|
|
||||||
routeApi.RoutesByProvider:
|
routeApi.RoutesByProvider:
|
||||||
additionalProperties:
|
additionalProperties:
|
||||||
items:
|
items:
|
||||||
$ref: '#/definitions/route.Route'
|
$ref: '#/definitions/route.Route'
|
||||||
type: array
|
type: array
|
||||||
type: object
|
type: object
|
||||||
routes.HealthInfo:
|
|
||||||
properties:
|
|
||||||
detail:
|
|
||||||
type: string
|
|
||||||
latency:
|
|
||||||
description: latency in microseconds
|
|
||||||
type: number
|
|
||||||
status:
|
|
||||||
enum:
|
|
||||||
- healthy
|
|
||||||
- unhealthy
|
|
||||||
- napping
|
|
||||||
- starting
|
|
||||||
- error
|
|
||||||
- unknown
|
|
||||||
type: string
|
|
||||||
uptime:
|
|
||||||
description: uptime in milliseconds
|
|
||||||
type: number
|
|
||||||
type: object
|
|
||||||
rules.Rule:
|
rules.Rule:
|
||||||
properties:
|
properties:
|
||||||
do:
|
do:
|
||||||
@@ -1494,10 +1665,6 @@ paths:
|
|||||||
description: Forbidden
|
description: Forbidden
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/definitions/ErrorResponse'
|
$ref: '#/definitions/ErrorResponse'
|
||||||
"500":
|
|
||||||
description: Internal Server Error
|
|
||||||
schema:
|
|
||||||
$ref: '#/definitions/ErrorResponse'
|
|
||||||
summary: List agents
|
summary: List agents
|
||||||
tags:
|
tags:
|
||||||
- agent
|
- agent
|
||||||
@@ -2878,6 +3045,37 @@ paths:
|
|||||||
- route
|
- route
|
||||||
- websocket
|
- websocket
|
||||||
x-id: routes
|
x-id: routes
|
||||||
|
/route/playground:
|
||||||
|
post:
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
description: Test rules against mock request/response
|
||||||
|
parameters:
|
||||||
|
- description: Playground request
|
||||||
|
in: body
|
||||||
|
name: request
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/PlaygroundRequest'
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: OK
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/PlaygroundResponse'
|
||||||
|
"400":
|
||||||
|
description: Bad Request
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
"403":
|
||||||
|
description: Forbidden
|
||||||
|
schema:
|
||||||
|
$ref: '#/definitions/ErrorResponse'
|
||||||
|
summary: Rule Playground
|
||||||
|
tags:
|
||||||
|
- route
|
||||||
|
x-id: playground
|
||||||
/route/providers:
|
/route/providers:
|
||||||
get:
|
get:
|
||||||
consumes:
|
consumes:
|
||||||
|
|||||||
361
internal/api/v1/route/playground.go
Normal file
361
internal/api/v1/route/playground.go
Normal file
@@ -0,0 +1,361 @@
|
|||||||
|
package routeApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/yusing/godoxy/internal/common"
|
||||||
|
"github.com/yusing/godoxy/internal/route/rules"
|
||||||
|
apitypes "github.com/yusing/goutils/apitypes"
|
||||||
|
gperr "github.com/yusing/goutils/errs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RawRule struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
On string `json:"on"`
|
||||||
|
Do string `json:"do"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PlaygroundRequest struct {
|
||||||
|
Rules []RawRule `json:"rules" binding:"required"`
|
||||||
|
MockRequest MockRequest `json:"mockRequest"`
|
||||||
|
MockResponse MockResponse `json:"mockResponse"`
|
||||||
|
} // @name PlaygroundRequest
|
||||||
|
|
||||||
|
type MockRequest struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Headers map[string][]string `json:"headers"`
|
||||||
|
Query map[string][]string `json:"query"`
|
||||||
|
Cookies []MockCookie `json:"cookies"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
RemoteIP string `json:"remoteIP"`
|
||||||
|
} // @name MockRequest
|
||||||
|
|
||||||
|
type MockCookie struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Value string `json:"value"`
|
||||||
|
} // @name MockCookie
|
||||||
|
|
||||||
|
type MockResponse struct {
|
||||||
|
StatusCode int `json:"statusCode"`
|
||||||
|
Headers map[string][]string `json:"headers"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
} // @name MockResponse
|
||||||
|
|
||||||
|
type PlaygroundResponse struct {
|
||||||
|
ParsedRules []ParsedRule `json:"parsedRules"`
|
||||||
|
MatchedRules []string `json:"matchedRules"`
|
||||||
|
FinalRequest FinalRequest `json:"finalRequest"`
|
||||||
|
FinalResponse FinalResponse `json:"finalResponse"`
|
||||||
|
ExecutionError gperr.Error `json:"executionError,omitempty"`
|
||||||
|
UpstreamCalled bool `json:"upstreamCalled"`
|
||||||
|
} // @name PlaygroundResponse
|
||||||
|
|
||||||
|
type ParsedRule struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
On string `json:"on"`
|
||||||
|
Do string `json:"do"`
|
||||||
|
ValidationError gperr.Error `json:"validationError,omitempty"`
|
||||||
|
IsResponseRule bool `json:"isResponseRule"`
|
||||||
|
} // @name ParsedRule
|
||||||
|
|
||||||
|
type FinalRequest struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Path string `json:"path"`
|
||||||
|
Host string `json:"host"`
|
||||||
|
Headers map[string][]string `json:"headers"`
|
||||||
|
Query map[string][]string `json:"query"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
} // @name FinalRequest
|
||||||
|
|
||||||
|
type FinalResponse struct {
|
||||||
|
StatusCode int `json:"statusCode"`
|
||||||
|
Headers map[string][]string `json:"headers"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
} // @name FinalResponse
|
||||||
|
|
||||||
|
// @x-id "playground"
|
||||||
|
// @BasePath /api/v1
|
||||||
|
// @Summary Rule Playground
|
||||||
|
// @Description Test rules against mock request/response
|
||||||
|
// @Tags route
|
||||||
|
// @Accept json
|
||||||
|
// @Produce json
|
||||||
|
// @Param request body PlaygroundRequest true "Playground request"
|
||||||
|
// @Success 200 {object} PlaygroundResponse
|
||||||
|
// @Failure 400 {object} apitypes.ErrorResponse
|
||||||
|
// @Failure 403 {object} apitypes.ErrorResponse
|
||||||
|
// @Router /route/playground [post]
|
||||||
|
func Playground(c *gin.Context) {
|
||||||
|
var req PlaygroundRequest
|
||||||
|
if err := c.ShouldBindJSON(&req); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, apitypes.Error("invalid request", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply defaults
|
||||||
|
if req.MockRequest.Method == "" {
|
||||||
|
req.MockRequest.Method = "GET"
|
||||||
|
}
|
||||||
|
if req.MockRequest.Path == "" {
|
||||||
|
req.MockRequest.Path = "/"
|
||||||
|
}
|
||||||
|
if req.MockRequest.Host == "" {
|
||||||
|
req.MockRequest.Host = "localhost"
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse rules
|
||||||
|
parsedRules, rulesList, parseErr := parseRules(req.Rules)
|
||||||
|
|
||||||
|
// Create mock HTTP request
|
||||||
|
mockReq := createMockRequest(req.MockRequest)
|
||||||
|
|
||||||
|
// Create mock HTTP response writer
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// Set initial mock response if provided
|
||||||
|
if req.MockResponse.StatusCode > 0 {
|
||||||
|
recorder.Code = req.MockResponse.StatusCode
|
||||||
|
}
|
||||||
|
if req.MockResponse.Headers != nil {
|
||||||
|
for k, values := range req.MockResponse.Headers {
|
||||||
|
for _, v := range values {
|
||||||
|
recorder.Header().Add(k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if req.MockResponse.Body != "" {
|
||||||
|
recorder.Body.WriteString(req.MockResponse.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Execute rules
|
||||||
|
matchedRules := []string{}
|
||||||
|
upstreamCalled := false
|
||||||
|
var executionError gperr.Error
|
||||||
|
|
||||||
|
// Variables to capture modified request state
|
||||||
|
var finalReqMethod, finalReqPath, finalReqHost string
|
||||||
|
var finalReqHeaders http.Header
|
||||||
|
var finalReqQuery url.Values
|
||||||
|
|
||||||
|
if parseErr == nil && len(rulesList) > 0 {
|
||||||
|
// Create upstream handler that records if it was called and captures request state
|
||||||
|
upstreamHandler := func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
upstreamCalled = true
|
||||||
|
// Capture the request state when upstream is called
|
||||||
|
finalReqMethod = r.Method
|
||||||
|
finalReqPath = r.URL.Path
|
||||||
|
finalReqHost = r.Host
|
||||||
|
finalReqHeaders = r.Header.Clone()
|
||||||
|
finalReqQuery = r.URL.Query()
|
||||||
|
|
||||||
|
// Debug: also check RequestURI
|
||||||
|
if r.URL.Path != r.URL.RawPath && r.URL.RawPath != "" {
|
||||||
|
finalReqPath = r.URL.RawPath
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's mock response body, write it during upstream call
|
||||||
|
if req.MockResponse.Body != "" && w.Header().Get("Content-Type") == "" {
|
||||||
|
w.Header().Set("Content-Type", "text/plain")
|
||||||
|
}
|
||||||
|
if req.MockResponse.StatusCode > 0 {
|
||||||
|
w.WriteHeader(req.MockResponse.StatusCode)
|
||||||
|
}
|
||||||
|
if req.MockResponse.Body != "" {
|
||||||
|
w.Write([]byte(req.MockResponse.Body))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build handler with rules
|
||||||
|
handler := rulesList.BuildHandler(upstreamHandler)
|
||||||
|
|
||||||
|
// Execute the handler
|
||||||
|
handlerWithRecover(recorder, mockReq, handler, &executionError)
|
||||||
|
|
||||||
|
// Track which rules matched
|
||||||
|
// Since we can't easily instrument the rules, we'll check each rule manually
|
||||||
|
matchedRules = checkMatchedRules(rulesList, recorder, mockReq)
|
||||||
|
} else if parseErr != nil {
|
||||||
|
executionError = parseErr
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build final request state
|
||||||
|
// Use captured state if upstream was called, otherwise use current state
|
||||||
|
var finalRequest FinalRequest
|
||||||
|
if upstreamCalled {
|
||||||
|
finalRequest = FinalRequest{
|
||||||
|
Method: finalReqMethod,
|
||||||
|
Path: finalReqPath,
|
||||||
|
Host: finalReqHost,
|
||||||
|
Headers: finalReqHeaders,
|
||||||
|
Query: finalReqQuery,
|
||||||
|
Body: req.MockRequest.Body,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finalRequest = FinalRequest{
|
||||||
|
Method: mockReq.Method,
|
||||||
|
Path: mockReq.URL.Path,
|
||||||
|
Host: mockReq.Host,
|
||||||
|
Headers: mockReq.Header,
|
||||||
|
Query: mockReq.URL.Query(),
|
||||||
|
Body: req.MockRequest.Body,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build final response state
|
||||||
|
finalResponse := FinalResponse{
|
||||||
|
StatusCode: recorder.Code,
|
||||||
|
Headers: recorder.Header(),
|
||||||
|
Body: recorder.Body.String(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure status code defaults to 200 if not set
|
||||||
|
if finalResponse.StatusCode == 0 {
|
||||||
|
finalResponse.StatusCode = http.StatusOK
|
||||||
|
}
|
||||||
|
|
||||||
|
// prevent null in response
|
||||||
|
if parsedRules == nil {
|
||||||
|
parsedRules = []ParsedRule{}
|
||||||
|
}
|
||||||
|
if matchedRules == nil {
|
||||||
|
matchedRules = []string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
response := PlaygroundResponse{
|
||||||
|
ParsedRules: parsedRules,
|
||||||
|
MatchedRules: matchedRules,
|
||||||
|
FinalRequest: finalRequest,
|
||||||
|
FinalResponse: finalResponse,
|
||||||
|
ExecutionError: executionError,
|
||||||
|
UpstreamCalled: upstreamCalled,
|
||||||
|
}
|
||||||
|
|
||||||
|
if common.IsTest {
|
||||||
|
c.Set("response", response)
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, response)
|
||||||
|
}
|
||||||
|
|
||||||
|
func handlerWithRecover(w http.ResponseWriter, r *http.Request, h http.HandlerFunc, outErr *gperr.Error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
if outErr != nil {
|
||||||
|
*outErr = gperr.Errorf("panic during rule execution: %v", r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
h(w, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseRules(rawRules []RawRule) ([]ParsedRule, rules.Rules, gperr.Error) {
|
||||||
|
var parsedRules []ParsedRule
|
||||||
|
var rulesList rules.Rules
|
||||||
|
|
||||||
|
// Parse each rule individually to capture per-rule errors
|
||||||
|
for _, rawRule := range rawRules {
|
||||||
|
var rule rules.Rule
|
||||||
|
|
||||||
|
// Extract fields
|
||||||
|
name := rawRule.Name
|
||||||
|
onStr := rawRule.On
|
||||||
|
doStr := rawRule.Do
|
||||||
|
|
||||||
|
rule.Name = name
|
||||||
|
|
||||||
|
// Parse On
|
||||||
|
var onErr error
|
||||||
|
if onStr != "" {
|
||||||
|
onErr = rule.On.Parse(onStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse Do
|
||||||
|
var doErr error
|
||||||
|
if doStr != "" {
|
||||||
|
doErr = rule.Do.Parse(doStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine if valid
|
||||||
|
isValid := onErr == nil && doErr == nil
|
||||||
|
validationErr := gperr.Join(gperr.PrependSubject("on", onErr), gperr.PrependSubject("do", doErr))
|
||||||
|
|
||||||
|
parsedRules = append(parsedRules, ParsedRule{
|
||||||
|
Name: name,
|
||||||
|
On: onStr,
|
||||||
|
Do: doStr,
|
||||||
|
ValidationError: validationErr,
|
||||||
|
IsResponseRule: rule.IsResponseRule(),
|
||||||
|
})
|
||||||
|
|
||||||
|
// Only add valid rules to execution list
|
||||||
|
if isValid {
|
||||||
|
rulesList = append(rulesList, rule)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsedRules, rulesList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func createMockRequest(mock MockRequest) *http.Request {
|
||||||
|
// Create URL
|
||||||
|
urlStr := mock.Path
|
||||||
|
if len(mock.Query) > 0 {
|
||||||
|
query := url.Values(mock.Query)
|
||||||
|
urlStr = mock.Path + "?" + query.Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create request
|
||||||
|
var body io.Reader
|
||||||
|
if mock.Body != "" {
|
||||||
|
body = strings.NewReader(mock.Body)
|
||||||
|
}
|
||||||
|
|
||||||
|
req := httptest.NewRequest(mock.Method, urlStr, body)
|
||||||
|
|
||||||
|
// Set host
|
||||||
|
req.Host = mock.Host
|
||||||
|
|
||||||
|
// Set headers
|
||||||
|
req.Header = mock.Headers
|
||||||
|
|
||||||
|
// Set cookies
|
||||||
|
if mock.Cookies != nil {
|
||||||
|
for _, cookie := range mock.Cookies {
|
||||||
|
req.AddCookie(&http.Cookie{
|
||||||
|
Name: cookie.Name,
|
||||||
|
Value: cookie.Value,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set remote address
|
||||||
|
if mock.RemoteIP != "" {
|
||||||
|
req.RemoteAddr = mock.RemoteIP + ":0"
|
||||||
|
} else {
|
||||||
|
req.RemoteAddr = "127.0.0.1:0"
|
||||||
|
}
|
||||||
|
|
||||||
|
return req
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkMatchedRules(rulesList rules.Rules, w http.ResponseWriter, r *http.Request) []string {
|
||||||
|
var matched []string
|
||||||
|
|
||||||
|
// Create a ResponseModifier to properly check rules
|
||||||
|
rm := rules.NewResponseModifier(w)
|
||||||
|
|
||||||
|
for _, rule := range rulesList {
|
||||||
|
// Check if rule matches
|
||||||
|
if rule.Check(rm, r) {
|
||||||
|
matched = append(matched, rule.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return matched
|
||||||
|
}
|
||||||
229
internal/api/v1/route/playground_test.go
Normal file
229
internal/api/v1/route/playground_test.go
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
package routeApi
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"net/http"
|
||||||
|
"net/http/httptest"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPlayground(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
request PlaygroundRequest
|
||||||
|
wantStatusCode int
|
||||||
|
checkResponse func(t *testing.T, resp PlaygroundResponse)
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "simple path matching rule",
|
||||||
|
request: PlaygroundRequest{
|
||||||
|
Rules: []RawRule{
|
||||||
|
{
|
||||||
|
Name: "test rule",
|
||||||
|
On: "path /api",
|
||||||
|
Do: "pass",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MockRequest: MockRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/api",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
checkResponse: func(t *testing.T, resp PlaygroundResponse) {
|
||||||
|
if len(resp.ParsedRules) != 1 {
|
||||||
|
t.Errorf("expected 1 parsed rule, got %d", len(resp.ParsedRules))
|
||||||
|
}
|
||||||
|
if resp.ParsedRules[0].ValidationError != nil {
|
||||||
|
t.Errorf("expected rule to be valid, got error: %v", resp.ParsedRules[0].ValidationError)
|
||||||
|
}
|
||||||
|
if len(resp.MatchedRules) != 1 || resp.MatchedRules[0] != "test rule" {
|
||||||
|
t.Errorf("expected matched rules to be ['test rule'], got %v", resp.MatchedRules)
|
||||||
|
}
|
||||||
|
if !resp.UpstreamCalled {
|
||||||
|
t.Error("expected upstream to be called")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "header matching rule",
|
||||||
|
request: PlaygroundRequest{
|
||||||
|
Rules: []RawRule{
|
||||||
|
{
|
||||||
|
Name: "check user agent",
|
||||||
|
On: "header User-Agent Chrome",
|
||||||
|
Do: "error 403 Forbidden",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MockRequest: MockRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/",
|
||||||
|
Headers: map[string][]string{
|
||||||
|
"User-Agent": {"Chrome"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
checkResponse: func(t *testing.T, resp PlaygroundResponse) {
|
||||||
|
if len(resp.ParsedRules) != 1 {
|
||||||
|
t.Errorf("expected 1 parsed rule, got %d", len(resp.ParsedRules))
|
||||||
|
}
|
||||||
|
if resp.ParsedRules[0].ValidationError != nil {
|
||||||
|
t.Errorf("expected rule to be valid, got error: %v", resp.ParsedRules[0].ValidationError)
|
||||||
|
}
|
||||||
|
if len(resp.MatchedRules) != 1 {
|
||||||
|
t.Errorf("expected 1 matched rule, got %d", len(resp.MatchedRules))
|
||||||
|
}
|
||||||
|
if resp.FinalResponse.StatusCode != 403 {
|
||||||
|
t.Errorf("expected status 403, got %d", resp.FinalResponse.StatusCode)
|
||||||
|
}
|
||||||
|
if resp.UpstreamCalled {
|
||||||
|
t.Error("expected upstream not to be called")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid rule syntax",
|
||||||
|
request: PlaygroundRequest{
|
||||||
|
Rules: []RawRule{
|
||||||
|
{
|
||||||
|
Name: "bad rule",
|
||||||
|
On: "invalid_checker something",
|
||||||
|
Do: "pass",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MockRequest: MockRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
checkResponse: func(t *testing.T, resp PlaygroundResponse) {
|
||||||
|
if len(resp.ParsedRules) != 1 {
|
||||||
|
t.Errorf("expected 1 parsed rule, got %d", len(resp.ParsedRules))
|
||||||
|
}
|
||||||
|
if resp.ParsedRules[0].ValidationError == nil {
|
||||||
|
t.Error("expected validation error to be set")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "rewrite path rule",
|
||||||
|
request: PlaygroundRequest{
|
||||||
|
Rules: []RawRule{
|
||||||
|
{
|
||||||
|
Name: "rewrite rule",
|
||||||
|
On: "path glob(/api/*)",
|
||||||
|
Do: "rewrite /api/ /v1/",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MockRequest: MockRequest{
|
||||||
|
Method: "GET",
|
||||||
|
Path: "/api/users",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
checkResponse: func(t *testing.T, resp PlaygroundResponse) {
|
||||||
|
if len(resp.ParsedRules) != 1 {
|
||||||
|
t.Errorf("expected 1 parsed rule, got %d", len(resp.ParsedRules))
|
||||||
|
}
|
||||||
|
if resp.ParsedRules[0].ValidationError != nil {
|
||||||
|
t.Errorf("expected rule to be valid, got error: %v", resp.ParsedRules[0].ValidationError)
|
||||||
|
}
|
||||||
|
if !resp.UpstreamCalled {
|
||||||
|
t.Error("expected upstream to be called")
|
||||||
|
}
|
||||||
|
if resp.FinalRequest.Path != "/v1/users" {
|
||||||
|
t.Errorf("expected path to be rewritten to /v1/users, got %s", resp.FinalRequest.Path)
|
||||||
|
}
|
||||||
|
// Note: matched rules tracking has limitations with fresh ResponseModifier
|
||||||
|
// The important thing is that the rewrite actually worked
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "method matching rule",
|
||||||
|
request: PlaygroundRequest{
|
||||||
|
Rules: []RawRule{
|
||||||
|
{
|
||||||
|
Name: "block POST",
|
||||||
|
On: "method POST",
|
||||||
|
Do: `error "405" "Method Not Allowed"`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
MockRequest: MockRequest{
|
||||||
|
Method: "POST",
|
||||||
|
Path: "/api",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
wantStatusCode: http.StatusOK,
|
||||||
|
checkResponse: func(t *testing.T, resp PlaygroundResponse) {
|
||||||
|
if resp.ParsedRules[0].ValidationError != nil {
|
||||||
|
t.Errorf("expected rule to be valid, got error: %v", resp.ParsedRules[0].ValidationError)
|
||||||
|
}
|
||||||
|
if len(resp.MatchedRules) != 1 {
|
||||||
|
t.Errorf("expected 1 matched rule, got %d", len(resp.MatchedRules))
|
||||||
|
}
|
||||||
|
if resp.FinalResponse.StatusCode != 405 {
|
||||||
|
t.Errorf("expected status 405, got %d", resp.FinalResponse.StatusCode)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
// Create request
|
||||||
|
body, _ := json.Marshal(tt.request)
|
||||||
|
req := httptest.NewRequest("POST", "/api/v1/route/playground", bytes.NewReader(body))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
// Create response recorder
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
|
||||||
|
// Create gin context
|
||||||
|
c, _ := gin.CreateTestContext(w)
|
||||||
|
c.Request = req
|
||||||
|
|
||||||
|
// Call handler
|
||||||
|
Playground(c)
|
||||||
|
|
||||||
|
// Check status code
|
||||||
|
if w.Code != tt.wantStatusCode {
|
||||||
|
t.Errorf("expected status code %d, got %d", tt.wantStatusCode, w.Code)
|
||||||
|
}
|
||||||
|
|
||||||
|
respAny, ok := c.Get("response")
|
||||||
|
if !ok {
|
||||||
|
t.Fatalf("expected response to be set")
|
||||||
|
}
|
||||||
|
resp := respAny.(PlaygroundResponse)
|
||||||
|
|
||||||
|
// Run custom checks
|
||||||
|
if tt.checkResponse != nil {
|
||||||
|
tt.checkResponse(t, resp)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPlaygroundInvalidRequest(t *testing.T) {
|
||||||
|
gin.SetMode(gin.TestMode)
|
||||||
|
|
||||||
|
req := httptest.NewRequest("POST", "/api/v1/route/playground", bytes.NewReader([]byte(`{}`)))
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
w := httptest.NewRecorder()
|
||||||
|
c, _ := gin.CreateTestContext(w)
|
||||||
|
c.Request = req
|
||||||
|
|
||||||
|
Playground(c)
|
||||||
|
|
||||||
|
if w.Code != http.StatusBadRequest {
|
||||||
|
t.Errorf("expected status code %d, got %d", http.StatusBadRequest, w.Code)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user