diff --git a/modules/http/http.go b/modules/http/http.go index 78cc5b7..4a80275 100644 --- a/modules/http/http.go +++ b/modules/http/http.go @@ -208,74 +208,89 @@ func WaitForServers() { func handleRequest(ctx *fasthttp.RequestCtx) { path := string(ctx.Path()) - // Check static handlers first - staticMu.RLock() - for prefix, fs := range staticHandlers { - if strings.HasPrefix(path, prefix) { - staticMu.RUnlock() - // Remove prefix and serve - ctx.Request.URI().SetPath(strings.TrimPrefix(path, prefix)) - fs.NewRequestHandler()(ctx) - return - } + // Fast path for likely static files (has extension) + if isLikelyStaticFile(path) && tryStaticHandler(ctx, path) { + return } - staticMu.RUnlock() - // Fall back to Lua handling + // Try Lua routing globalMu.RLock() pool := globalWorkerPool globalMu.RUnlock() - if pool == nil { - ctx.SetStatusCode(fasthttp.StatusInternalServerError) - ctx.SetBodyString("Worker pool not initialized") + if pool != nil { + worker := pool.Get() + if worker != nil { + defer pool.Put(worker) + + req := GetRequest() + defer PutRequest(req) + + resp := GetResponse() + defer PutResponse(resp) + + // Populate request + req.Method = string(ctx.Method()) + req.Path = path + req.Body = string(ctx.Request.Body()) + + ctx.QueryArgs().VisitAll(func(key, value []byte) { + req.Query[string(key)] = string(value) + }) + + ctx.Request.Header.VisitAll(func(key, value []byte) { + req.Headers[string(key)] = string(value) + }) + + err := worker.HandleRequest(req, resp) + if err != nil { + ctx.SetStatusCode(fasthttp.StatusInternalServerError) + ctx.SetBodyString(fmt.Sprintf("Internal Server Error: %v", err)) + return + } + + // If Lua found a route, use it + if resp.StatusCode != 404 { + ctx.SetStatusCode(resp.StatusCode) + for key, value := range resp.Headers { + ctx.Response.Header.Set(key, value) + } + if resp.Body != "" { + ctx.SetBodyString(resp.Body) + } + return + } + } + } + + // Lua 404, try static handlers if not already checked + if !isLikelyStaticFile(path) && tryStaticHandler(ctx, path) { return } - worker := pool.Get() - defer pool.Put(worker) + ctx.SetStatusCode(fasthttp.StatusNotFound) + ctx.SetBodyString("Not Found") +} - if worker == nil { - ctx.SetStatusCode(fasthttp.StatusInternalServerError) - ctx.SetBodyString("No worker available") - return +func tryStaticHandler(ctx *fasthttp.RequestCtx, path string) bool { + staticMu.RLock() + defer staticMu.RUnlock() + + for prefix, fs := range staticHandlers { + if strings.HasPrefix(path, prefix) { + ctx.Request.URI().SetPath(strings.TrimPrefix(path, prefix)) + fs.NewRequestHandler()(ctx) + return true + } } + return false +} - req := GetRequest() - defer PutRequest(req) - - resp := GetResponse() - defer PutResponse(resp) - - // Populate request - req.Method = string(ctx.Method()) - req.Path = string(ctx.Path()) - req.Body = string(ctx.Request.Body()) - - ctx.QueryArgs().VisitAll(func(key, value []byte) { - req.Query[string(key)] = string(value) - }) - - ctx.Request.Header.VisitAll(func(key, value []byte) { - req.Headers[string(key)] = string(value) - }) - - // Let Lua handle everything - err := worker.HandleRequest(req, resp) - if err != nil { - ctx.SetStatusCode(fasthttp.StatusInternalServerError) - ctx.SetBodyString(fmt.Sprintf("Internal Server Error: %v", err)) - return - } - - // Apply response - ctx.SetStatusCode(resp.StatusCode) - for key, value := range resp.Headers { - ctx.Response.Header.Set(key, value) - } - if resp.Body != "" { - ctx.SetBodyString(resp.Body) - } +func isLikelyStaticFile(path string) bool { + // Check for file extension + lastSlash := strings.LastIndex(path, "/") + lastDot := strings.LastIndex(path, ".") + return lastDot > lastSlash && lastDot != -1 } // RegisterStaticHandler adds a static file handler