72 lines
2.1 KiB
Go
72 lines
2.1 KiB
Go
package sdkserver
|
|
|
|
import (
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"gac-hkrpg-go/internal/common"
|
|
)
|
|
|
|
// Route name is part of this server's HTTP interface, not a machine URL.
|
|
const luaOverlayRoute = "/gacy-lua-overlay"
|
|
|
|
var luaBundleName = regexp.MustCompile(`^(?:M_LuaV|LuaV_[0-9a-f]{32}|[0-9a-f]{32})\.bytes$`)
|
|
|
|
// Dispatch outside ServeMux: a subtree registration conflicts with the
|
|
// product-name wildcard used by the existing login endpoints in newer Go.
|
|
func withLuaOverlay(next http.Handler, cfg common.LuaOverlayConfig) http.Handler {
|
|
if !cfg.Enabled {
|
|
return next
|
|
}
|
|
overlay := luaOverlayHandler(cfg)
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
if strings.HasPrefix(r.URL.Path, luaOverlayRoute+"/") {
|
|
overlay(w, r)
|
|
return
|
|
}
|
|
next.ServeHTTP(w, r)
|
|
})
|
|
}
|
|
|
|
// Serve only the Lua updater's known flat namespace. Stage files win, then the
|
|
// local hotfix and shipping files; no filesystem path or remote URL is derived
|
|
// from untrusted input. The original caches remain untouched.
|
|
func luaOverlayHandler(cfg common.LuaOverlayConfig) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
if r.Method != http.MethodGet && r.Method != http.MethodHead {
|
|
w.WriteHeader(http.StatusMethodNotAllowed)
|
|
return
|
|
}
|
|
path := strings.TrimPrefix(r.URL.Path, luaOverlayRoute+"/")
|
|
path = strings.TrimPrefix(path, "client/Windows/")
|
|
if !luaBundleName.MatchString(path) {
|
|
http.NotFound(w, r)
|
|
return
|
|
}
|
|
for _, root := range []string{cfg.StageDir, cfg.HotfixDir, cfg.StreamingDir} {
|
|
file, err := os.Open(filepath.Join(root, path))
|
|
if os.IsNotExist(err) {
|
|
continue
|
|
}
|
|
if err != nil {
|
|
http.Error(w, "Lua overlay read failed", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
info, err := file.Stat()
|
|
if err != nil || !info.Mode().IsRegular() {
|
|
file.Close()
|
|
http.Error(w, "Lua overlay file invalid", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "application/octet-stream")
|
|
http.ServeContent(w, r, path, info.ModTime(), file)
|
|
file.Close()
|
|
return
|
|
}
|
|
http.NotFound(w, r)
|
|
}
|
|
}
|