NewServer creates a new HTTP server
(cfg *config.Config, registryService service.RegistryService, metrics *telemetry.Metrics, versionInfo *v0.VersionBody)
| 97 | |
| 98 | // NewServer creates a new HTTP server |
| 99 | func NewServer(cfg *config.Config, registryService service.RegistryService, metrics *telemetry.Metrics, versionInfo *v0.VersionBody) *Server { |
| 100 | // Create HTTP mux and Huma API |
| 101 | mux := http.NewServeMux() |
| 102 | |
| 103 | api := router.NewHumaAPI(cfg, registryService, mux, metrics, versionInfo) |
| 104 | |
| 105 | // Configure CORS with permissive settings for public API |
| 106 | corsHandler := cors.New(cors.Options{ |
| 107 | AllowedOrigins: []string{"*"}, |
| 108 | AllowedMethods: []string{ |
| 109 | http.MethodGet, |
| 110 | http.MethodPost, |
| 111 | http.MethodPut, |
| 112 | http.MethodDelete, |
| 113 | http.MethodOptions, |
| 114 | }, |
| 115 | AllowedHeaders: []string{"*"}, |
| 116 | ExposedHeaders: []string{"Content-Type", "Content-Length"}, |
| 117 | AllowCredentials: false, // Must be false when AllowedOrigins is "*" |
| 118 | MaxAge: 86400, // 24 hours |
| 119 | }) |
| 120 | |
| 121 | // Wrap the mux with middleware stack |
| 122 | // Order: NulByteValidation -> TrailingSlash -> CORS -> Mux |
| 123 | handler := NulByteValidationMiddleware(TrailingSlashMiddleware(corsHandler.Handler(mux))) |
| 124 | |
| 125 | server := &Server{ |
| 126 | config: cfg, |
| 127 | registry: registryService, |
| 128 | humaAPI: api, |
| 129 | server: &http.Server{ |
| 130 | Addr: cfg.ServerAddress, |
| 131 | Handler: handler, |
| 132 | ReadHeaderTimeout: 10 * time.Second, |
| 133 | ReadTimeout: 30 * time.Second, |
| 134 | // WriteTimeout intentionally not set: the publish path runs |
| 135 | // outbound package validators sequentially (npm/pypi/nuget up to |
| 136 | // 10s each, OCI up to 30s), so any tight cap could cut off a |
| 137 | // legitimate multi-package publish mid-response — surfacing as a |
| 138 | // truncated read to the publisher even when the DB commit |
| 139 | // succeeded. Slow-response-read DoS is bounded upstream by |
| 140 | // NGINX ingress timeouts and the per-IP rate limit. Revisit once |
| 141 | // validators are parallelised or per-request package counts are |
| 142 | // bounded. |
| 143 | IdleTimeout: 120 * time.Second, |
| 144 | }, |
| 145 | } |
| 146 | |
| 147 | return server |
| 148 | } |
| 149 | |
| 150 | // Start begins listening for incoming HTTP requests |
| 151 | func (s *Server) Start() error { |
searching dependent graphs…