http.go 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. // Package server provides HTTP server initialization and configuration.
  2. package server
  3. import (
  4. "context"
  5. "log"
  6. "log/slog"
  7. "net/http"
  8. "time"
  9. "github.com/Wei-Shaw/sub2api/internal/config"
  10. "github.com/Wei-Shaw/sub2api/internal/handler"
  11. "github.com/Wei-Shaw/sub2api/internal/pkg/websearch"
  12. middleware2 "github.com/Wei-Shaw/sub2api/internal/server/middleware"
  13. "github.com/Wei-Shaw/sub2api/internal/service"
  14. "github.com/gin-gonic/gin"
  15. "github.com/google/wire"
  16. "github.com/redis/go-redis/v9"
  17. "golang.org/x/net/http2"
  18. )
  19. // ProviderSet 提供服务器层的依赖
  20. var ProviderSet = wire.NewSet(
  21. ProvideRouter,
  22. ProvideHTTPServer,
  23. )
  24. // ProvideRouter 提供路由器
  25. func ProvideRouter(
  26. cfg *config.Config,
  27. handlers *handler.Handlers,
  28. jwtAuth middleware2.JWTAuthMiddleware,
  29. optionalJWTAuth middleware2.OptionalJWTAuthMiddleware,
  30. adminAuth middleware2.AdminAuthMiddleware,
  31. apiKeyAuth middleware2.APIKeyAuthMiddleware,
  32. auditLog middleware2.AuditLogMiddleware,
  33. stepUpAuth middleware2.StepUpAuthMiddleware,
  34. apiKeyService *service.APIKeyService,
  35. subscriptionService *service.SubscriptionService,
  36. opsService *service.OpsService,
  37. settingService *service.SettingService,
  38. userService *service.UserService,
  39. compositeResolver *service.CompositeRouteResolver,
  40. redisClient *redis.Client,
  41. ) *gin.Engine {
  42. if cfg.Server.Mode == "release" {
  43. gin.SetMode(gin.ReleaseMode)
  44. }
  45. r := gin.New()
  46. r.Use(middleware2.Recovery())
  47. configureTrustedProxies(r, cfg.Server)
  48. // Wire up websearch Manager builder so it initializes on startup and rebuilds on config save.
  49. settingService.SetWebSearchManagerBuilder(context.Background(), func(cfg *service.WebSearchEmulationConfig, proxyURLs map[int64]string) {
  50. if cfg == nil || !cfg.Enabled || len(cfg.Providers) == 0 {
  51. service.SetWebSearchManager(nil)
  52. return
  53. }
  54. configs := make([]websearch.ProviderConfig, 0, len(cfg.Providers))
  55. for _, p := range cfg.Providers {
  56. if p.APIKey == "" {
  57. continue
  58. }
  59. pc := websearch.ProviderConfig{
  60. Type: p.Type,
  61. APIKey: p.APIKey,
  62. QuotaLimit: derefInt64(p.QuotaLimit),
  63. ExpiresAt: p.ExpiresAt,
  64. }
  65. if p.SubscribedAt != nil {
  66. pc.SubscribedAt = p.SubscribedAt
  67. }
  68. if p.ProxyID != nil {
  69. pc.ProxyID = *p.ProxyID
  70. if u, ok := proxyURLs[*p.ProxyID]; ok {
  71. pc.ProxyURL = u
  72. } else {
  73. // Proxy configured but not found — skip this provider to prevent direct connection.
  74. slog.Warn("websearch: proxy not found for provider, skipping",
  75. "provider", p.Type, "proxy_id", *p.ProxyID)
  76. continue
  77. }
  78. }
  79. configs = append(configs, pc)
  80. }
  81. service.SetWebSearchManager(websearch.NewManager(configs, redisClient))
  82. })
  83. return SetupRouter(r, handlers, jwtAuth, optionalJWTAuth, adminAuth, apiKeyAuth, auditLog, stepUpAuth, apiKeyService, subscriptionService, opsService, settingService, userService, compositeResolver, cfg, redisClient)
  84. }
  85. func configureTrustedProxies(r *gin.Engine, cfg config.ServerConfig) {
  86. if cfg.TrustedProxiesConfigured {
  87. if err := r.SetTrustedProxies(cfg.TrustedProxies); err != nil {
  88. log.Printf("Failed to set trusted proxies: %v", err)
  89. _ = r.SetTrustedProxies(nil)
  90. }
  91. if len(cfg.TrustedProxies) == 0 && cfg.Mode == "release" {
  92. log.Printf("Warning: server.trusted_proxies is explicitly empty; forwarded client IP trust is disabled")
  93. }
  94. } else {
  95. if err := r.SetTrustedProxies(nil); err != nil {
  96. log.Printf("Failed to disable trusted proxies: %v", err)
  97. }
  98. if cfg.Mode == "release" {
  99. log.Printf("Warning: server.trusted_proxies is not configured; disabling the forwarded-IP compatibility switch will use direct peer addresses only")
  100. }
  101. }
  102. }
  103. // ProvideHTTPServer 提供 HTTP 服务器
  104. func ProvideHTTPServer(cfg *config.Config, router *gin.Engine) *http.Server {
  105. httpHandler := http.Handler(router)
  106. server := &http.Server{
  107. Addr: cfg.Server.Address(),
  108. Handler: httpHandler,
  109. MaxHeaderBytes: cfg.Server.MaxHeaderBytes,
  110. // ReadHeaderTimeout: 读取请求头的超时时间,防止慢速请求头攻击
  111. ReadHeaderTimeout: time.Duration(cfg.Server.ReadHeaderTimeout) * time.Second,
  112. // IdleTimeout: 空闲连接超时时间,释放不活跃的连接资源
  113. IdleTimeout: time.Duration(cfg.Server.IdleTimeout) * time.Second,
  114. // 注意:不设置 WriteTimeout,因为流式响应可能持续十几分钟
  115. // 不设置 ReadTimeout,因为大请求体可能需要较长时间读取
  116. }
  117. globalMaxSize := cfg.Server.MaxRequestBodySize
  118. if globalMaxSize <= 0 {
  119. globalMaxSize = cfg.Gateway.MaxBodySize
  120. }
  121. if globalMaxSize > 0 {
  122. httpHandler = http.MaxBytesHandler(httpHandler, globalMaxSize)
  123. log.Printf("Global max request body size: %d bytes (%.2f MB)", globalMaxSize, float64(globalMaxSize)/(1<<20))
  124. }
  125. // 根据配置决定是否启用 H2C
  126. if cfg.Server.H2C.Enabled {
  127. h2cConfig := cfg.Server.H2C
  128. if err := http2.ConfigureServer(server, &http2.Server{
  129. MaxConcurrentStreams: h2cConfig.MaxConcurrentStreams,
  130. IdleTimeout: time.Duration(h2cConfig.IdleTimeout) * time.Second,
  131. MaxReadFrameSize: uint32(h2cConfig.MaxReadFrameSize),
  132. MaxUploadBufferPerConnection: int32(h2cConfig.MaxUploadBufferPerConnection),
  133. MaxUploadBufferPerStream: int32(h2cConfig.MaxUploadBufferPerStream),
  134. }); err != nil {
  135. log.Printf("Failed to configure HTTP/2 Cleartext (h2c): %v", err)
  136. } else {
  137. protocols := new(http.Protocols)
  138. protocols.SetHTTP1(true)
  139. protocols.SetUnencryptedHTTP2(true)
  140. server.Protocols = protocols
  141. log.Printf("HTTP/2 Cleartext (h2c) enabled: max_concurrent_streams=%d, idle_timeout=%ds, max_read_frame_size=%d, max_upload_buffer_per_connection=%d, max_upload_buffer_per_stream=%d",
  142. h2cConfig.MaxConcurrentStreams,
  143. h2cConfig.IdleTimeout,
  144. h2cConfig.MaxReadFrameSize,
  145. h2cConfig.MaxUploadBufferPerConnection,
  146. h2cConfig.MaxUploadBufferPerStream,
  147. )
  148. }
  149. }
  150. server.Handler = httpHandler
  151. return server
  152. }
  153. func derefInt64(p *int64) int64 {
  154. if p == nil {
  155. return 0
  156. }
  157. return *p
  158. }