Skip to content

route: service gateway#70

Merged
wuhan005 merged 2 commits intomasterfrom
wh/service-gateway
Dec 27, 2025
Merged

route: service gateway#70
wuhan005 merged 2 commits intomasterfrom
wh/service-gateway

Conversation

@wuhan005
Copy link
Owner

@wuhan005 wuhan005 commented Dec 27, 2025

Summary by CodeRabbit

  • New Features
    • Introduces a service proxy with dynamic, prefix-based routing to multiple configurable backends. Requests to the new endpoint are forwarded to matched backends with tracing and user-identifying headers, and return clear JSON errors when routes or backends are unavailable. Configurable backends can be added without altering core load flow.

✏️ Tip: You can customize this high-level summary in your review settings.

Signed-off-by: E99p1ant <i@github.red>
Copilot AI review requested due to automatic review settings December 27, 2025 14:48
@coderabbitai
Copy link

coderabbitai bot commented Dec 27, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Adds a dynamic reverse-proxy feature: new Service configuration (backend list), configuration parsing to populate backends, a /api/v1/service/{**} route, and a Proxy handler that routes requests to configured backends with header injection and tracing propagation.

Changes

Cohort / File(s) Summary
Configuration Schema
internal/conf/static.go
Adds exported Service config with Backends slice (each: Prefix, ForwardURL) parsed from INI.
Configuration Loading
internal/conf/conf.go
Extends Init() to iterate File.Section("service").ChildSections(), map subsections into backends, wrap mapping errors per subsection, and append to conf.Service.Backends.
Route Registration
internal/route/route.go
Registers new route f.Any("/service/{**}", service.Proxy) under /api/v1.
Reverse Proxy Handler
route/service/proxy.go
Adds Proxy(ctx context.Context) error that matches request path to backend by prefix, rewrites target URL/path, configures reverse proxy (skips TLS verify), forwards OpenTelemetry tracing headers, injects X-NekoBox-From and X-NekoBox-User-ID, logs and returns JSON errors (404/500) on failure.

Sequence Diagram

sequenceDiagram
    participant Client
    participant Router as "API Router\n(/api/v1)"
    participant Proxy as "Service.Proxy\n(handler)"
    participant Backend as "Backend Service"
    participant Tracer as "OpenTelemetry"

    Client->>Router: HTTP request to /service/{...}
    Router->>Proxy: call Proxy(ctx)
    Proxy->>Proxy: extract path, find backend by prefix
    alt backend matched
        Proxy->>Tracer: propagate tracing headers
        Note right of Proxy `#DFF2E1`: inject headers\nX-NekoBox-From, X-NekoBox-User-ID
        Proxy->>Backend: forward request (rewritten URL/path)
        Backend-->>Proxy: response
        Proxy-->>Client: proxied response
    else no match
        Proxy-->>Client: 404 JSON error
    end
    alt forward error
        Proxy-->>Client: 500 JSON error
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Poem

🐇 I hop through configs, prefixes in tow,
I stitch requests where backend winds blow,
With headers and traces, I nudge them along,
A tiny proxy rabbit humming a song,
Routes found, responses returned — hop, all is strong!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'route: service gateway' directly and concisely describes the main change: adding a service gateway routing feature to the application.

📜 Recent review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 582498b and c131dc1.

📒 Files selected for processing (1)
  • internal/conf/conf.go

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a service gateway feature that enables proxying HTTP requests to configurable backend services. The gateway acts as a reverse proxy with OpenTelemetry tracing support and user context propagation.

  • Adds a new reverse proxy handler that routes requests based on URL prefixes to configured backend services
  • Implements configuration support for multiple backend services with prefix-based routing
  • Integrates the service proxy endpoint into the API routing structure

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.

File Description
route/service/proxy.go New reverse proxy handler with tracing, user context propagation, and configurable backend routing
internal/route/route.go Registers the new service proxy endpoint at /api/v1/service/{**}
internal/conf/static.go Adds Service configuration struct to hold backend service definitions
internal/conf/conf.go Implements configuration parsing for service backends from INI file child sections

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Signed-off-by: E99p1ant <i@github.red>
@coderabbitai
Copy link

coderabbitai bot commented Dec 27, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #71

coderabbitai bot added a commit that referenced this pull request Dec 27, 2025
Docstrings generation was requested by @wuhan005.

* #70 (comment)

The following files were modified:

* `internal/conf/conf.go`
* `internal/route/route.go`
* `route/service/proxy.go`
@wuhan005 wuhan005 merged commit 82568a0 into master Dec 27, 2025
9 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (3)
route/service/proxy.go (2)

39-48: Consider optimizing backend lookup for better performance.

The current linear search through conf.Service.Backends is acceptable for a small number of backends, but could become a bottleneck if many services are configured. Consider using a map for O(1) lookup.

🔎 Alternative implementation with map-based lookup

You could create a map during initialization in internal/conf/conf.go:

Service struct {
    Backends []struct {
        Prefix     string `ini:"prefix"`
        ForwardURL string `ini:"forward_url"`
    }
    BackendMap map[string]string // Add this field
}

Then populate it after loading:

// After line 85 in conf.go
Service.BackendMap = make(map[string]string)
for _, backend := range Service.Backends {
    Service.BackendMap[backend.Prefix] = backend.ForwardURL
}

Then in the proxy:

-var forwardURLStr string
-for _, backend := range conf.Service.Backends {
-    if backend.Prefix == basePath {
-        forwardURLStr = backend.ForwardURL
-        break
-    }
-}
-if len(forwardURLStr) == 0 {
+forwardURLStr, ok := conf.Service.BackendMap[basePath]
+if !ok {
     return ctx.JSONError(http.StatusNotFound, "页面不存在")
 }

57-60: Review path construction logic for correctness.

The URL path construction on line 59 may produce incorrect results in some cases:

  • If forwardPath doesn't start with /, it will be concatenated directly: "/api" + "users""/apiusers"
  • If forwardURL contains a path (e.g., http://backend/api), that base path is used, which may or may not be intended

Consider using path.Join or ensuring forwardPath always starts with / for more predictable behavior.

🔎 Suggested improvement
+import "path"

 Director: func(req *http.Request) {
     req.URL = forwardURL
-    req.URL.Path = strings.TrimRight(req.URL.Path, "/") + forwardPath
+    req.URL.Path = path.Join(req.URL.Path, forwardPath)
     req.Host = forwardURL.Host

Or ensure forwardPath always starts with /:

 Director: func(req *http.Request) {
     req.URL = forwardURL
+    if !strings.HasPrefix(forwardPath, "/") && forwardPath != "" {
+        forwardPath = "/" + forwardPath
+    }
     req.URL.Path = strings.TrimRight(req.URL.Path, "/") + forwardPath
     req.Host = forwardURL.Host
internal/route/route.go (1)

145-145: Clarify that the service gateway intentionally allows unauthenticated access.

The service proxy route does not require authentication middleware, unlike the pixel proxy on line 144. However, examining the implementation in route/service/proxy.go reveals this is intentional: the proxy accepts both authenticated and unauthenticated requests, passing the user ID (defaulting to 0 when not logged in) to backends via the X-NekoBox-User-ID header. This design delegates authentication responsibility to the backend services. If this is not the intended behavior, add reqUserSignIn middleware to line 145.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19ae315 and 582498b.

📒 Files selected for processing (4)
  • internal/conf/conf.go
  • internal/conf/static.go
  • internal/route/route.go
  • route/service/proxy.go
🧰 Additional context used
🧬 Code graph analysis (3)
internal/conf/conf.go (1)
internal/conf/static.go (1)
  • Service (87-92)
route/service/proxy.go (3)
internal/context/context.go (1)
  • Context (48-57)
internal/db/users.go (1)
  • User (43-56)
internal/conf/static.go (1)
  • Service (87-92)
internal/route/route.go (2)
route/service/proxy.go (1)
  • Proxy (21-84)
route/pixel/pixel.go (1)
  • Proxy (23-62)
🪛 ast-grep (0.40.3)
route/service/proxy.go

[warning] 71-73: MinVersionis missing from this TLS configuration. By default, TLS 1.2 is currently used as the minimum when acting as a client, and TLS 1.0 when acting as a server. General purpose web applications should default to TLS 1.3 with all other protocols disabled. Only where it is known that a web server must support legacy clients with unsupported an insecure browsers (such as Internet Explorer 10), it may be necessary to enable TLS 1.0 to provide support. AddMinVersion: tls.VersionTLS13' to the TLS configuration to bump the minimum version to TLS 1.3.
Context: tls.Config{
InsecureSkipVerify: true,
}
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
https://owasp.org/Top10/A02_2021-Cryptographic_Failures

(missing-ssl-minversion-go)

🪛 GitHub Check: CodeQL
route/service/proxy.go

[failure] 73-73: Disabled TLS certificate check
InsecureSkipVerify should not be used in production code.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Agent
  • GitHub Check: Test MySQL
🔇 Additional comments (4)
internal/conf/conf.go (1)

74-85: LGTM! Configuration parsing is correct.

The service configuration parsing follows the established pattern in this file. The loop correctly iterates through child sections and populates the Service.Backends slice.

internal/conf/static.go (1)

87-92: LGTM!

The Service configuration struct is well-defined and follows the established patterns in this file. The field names and INI tags are clear and appropriate for the gateway configuration.

route/service/proxy.go (2)

21-33: LGTM! Proper tracing and user context handling.

The implementation correctly handles optional authentication and integrates OpenTelemetry tracing with appropriate defensive checks.


35-37: The path parsing logic is correct and does not have the edge cases described.

In Echo framework, the {**} wildcard parameter captures the remaining path segment without the leading slash. For example, a request to /service/foo/bar results in uri = "foo/bar" (not /foo/bar). Therefore:

  • strings.Split("foo/bar", "/")[0] correctly returns "foo" as the basePath
  • strings.TrimPrefix("foo/bar", "foo") correctly returns "/bar" as the forwardPath

The code functions as intended and properly handles backend prefix matching.

Comment on lines +71 to +75
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

CRITICAL: TLS certificate verification is disabled.

The InsecureSkipVerify: true setting completely disables TLS certificate verification, making the proxy vulnerable to man-in-the-middle attacks. This should never be used in production code.

Additionally, the TLS configuration is missing MinVersion, which should be set to at least tls.VersionTLS12 (or preferably tls.VersionTLS13).

🔎 Required security fix

Remove InsecureSkipVerify and add proper TLS configuration:

 Transport: &http.Transport{
     TLSClientConfig: &tls.Config{
-        InsecureSkipVerify: true,
+        MinVersion: tls.VersionTLS12,
     },
 },

If you need to support self-signed certificates in development environments, use a proper certificate pool or make this configurable per-backend with clear warnings, but never use InsecureSkipVerify in production.

Based on static analysis hints: CWE-327, OWASP A02:2021 - Cryptographic Failures.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
InsecureSkipVerify: true,
},
},
Transport: &http.Transport{
TLSClientConfig: &tls.Config{
MinVersion: tls.VersionTLS12,
},
},
🧰 Tools
🪛 ast-grep (0.40.3)

[warning] 71-73: MinVersionis missing from this TLS configuration. By default, TLS 1.2 is currently used as the minimum when acting as a client, and TLS 1.0 when acting as a server. General purpose web applications should default to TLS 1.3 with all other protocols disabled. Only where it is known that a web server must support legacy clients with unsupported an insecure browsers (such as Internet Explorer 10), it may be necessary to enable TLS 1.0 to provide support. AddMinVersion: tls.VersionTLS13' to the TLS configuration to bump the minimum version to TLS 1.3.
Context: tls.Config{
InsecureSkipVerify: true,
}
Note: [CWE-327]: Use of a Broken or Risky Cryptographic Algorithm [OWASP A03:2017]: Sensitive Data Exposure [OWASP A02:2021]: Cryptographic Failures [REFERENCES]
https://owasp.org/Top10/A02_2021-Cryptographic_Failures

(missing-ssl-minversion-go)

🪛 GitHub Check: CodeQL

[failure] 73-73: Disabled TLS certificate check
InsecureSkipVerify should not be used in production code.

🤖 Prompt for AI Agents
In route/service/proxy.go around lines 71 to 75, the TLS config currently sets
InsecureSkipVerify: true which disables certificate validation; remove that
setting, set TLSConfig.MinVersion to at least tls.VersionTLS12 (prefer
tls.VersionTLS13), and populate RootCAs with a proper x509.CertPool if you need
to trust self-signed certs for dev/testing or make an explicit per-backend
“allow insecure” flag (off by default) that uses a separate, clearly documented
config path for non-production use; do not leave InsecureSkipVerify enabled in
production.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants