Fix #735: Allow HEAD requests for download endpoints and fix routing
- Allow HEAD requests in addition to GET for all download handlers (install scripts, binaries, checksums) to prevent 405 errors - Add /uninstall-host-agent.sh to special routes in ServeHTTP - Add test coverage for HEAD request handling - Resolves 'method not allowed' errors during agent installation
This commit is contained in:
parent
07d8381858
commit
9caba86389
2 changed files with 40 additions and 13 deletions
|
|
@ -1508,6 +1508,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
|||
req.URL.Path == "/install-container-agent.sh" ||
|
||||
req.URL.Path == "/install-host-agent.sh" ||
|
||||
req.URL.Path == "/install-host-agent.ps1" ||
|
||||
req.URL.Path == "/uninstall-host-agent.sh" ||
|
||||
req.URL.Path == "/uninstall-host-agent.ps1" {
|
||||
// Use the mux for API and special routes
|
||||
r.mux.ServeHTTP(w, req)
|
||||
|
|
@ -3287,7 +3288,7 @@ func (r *Router) backgroundUpdateChecker() {
|
|||
|
||||
// handleDownloadInstallScript serves the Docker agent installation script
|
||||
func (r *Router) handleDownloadInstallScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3315,7 +3316,7 @@ func (r *Router) handleDownloadInstallScript(w http.ResponseWriter, req *http.Re
|
|||
|
||||
// handleDownloadContainerAgentInstallScript serves the container agent install script
|
||||
func (r *Router) handleDownloadContainerAgentInstallScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3331,7 +3332,7 @@ func (r *Router) handleDownloadContainerAgentInstallScript(w http.ResponseWriter
|
|||
|
||||
// handleDownloadAgent serves the Docker agent binary
|
||||
func (r *Router) handleDownloadAgent(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3401,7 +3402,7 @@ func (r *Router) handleDownloadAgent(w http.ResponseWriter, req *http.Request) {
|
|||
|
||||
// handleDownloadHostAgentInstallScript serves the Host agent installation script
|
||||
func (r *Router) handleDownloadHostAgentInstallScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3429,7 +3430,7 @@ func (r *Router) handleDownloadHostAgentInstallScript(w http.ResponseWriter, req
|
|||
|
||||
// handleDownloadHostAgentInstallScriptPS serves the PowerShell installation script for Windows
|
||||
func (r *Router) handleDownloadHostAgentInstallScriptPS(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3446,7 +3447,7 @@ func (r *Router) handleDownloadHostAgentInstallScriptPS(w http.ResponseWriter, r
|
|||
|
||||
// handleDownloadHostAgentUninstallScript serves the bash uninstallation script for Linux/macOS
|
||||
func (r *Router) handleDownloadHostAgentUninstallScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3462,7 +3463,7 @@ func (r *Router) handleDownloadHostAgentUninstallScript(w http.ResponseWriter, r
|
|||
|
||||
// handleDownloadHostAgentUninstallScriptPS serves the PowerShell uninstallation script for Windows
|
||||
func (r *Router) handleDownloadHostAgentUninstallScriptPS(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3479,7 +3480,7 @@ func (r *Router) handleDownloadHostAgentUninstallScriptPS(w http.ResponseWriter,
|
|||
|
||||
// handleDownloadHostAgent serves the Host agent binary
|
||||
func (r *Router) handleDownloadHostAgent(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
|
@ -3783,7 +3784,7 @@ func (r *Router) handleDiagnosticsDockerPrepareToken(w http.ResponseWriter, req
|
|||
}
|
||||
|
||||
func (r *Router) handleDownloadPulseSensorProxy(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
writeErrorResponse(w, http.StatusMethodNotAllowed, "method_not_allowed", "Only GET is allowed", nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -3909,7 +3910,7 @@ func (r *Router) handleDownloadPulseSensorProxy(w http.ResponseWriter, req *http
|
|||
}
|
||||
|
||||
func (r *Router) handleDownloadInstallerScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
writeErrorResponse(w, http.StatusMethodNotAllowed, "method_not_allowed", "Only GET is allowed", nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -3936,7 +3937,7 @@ func (r *Router) handleDownloadInstallerScript(w http.ResponseWriter, req *http.
|
|||
}
|
||||
|
||||
func (r *Router) handleDownloadDockerInstallerScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
writeErrorResponse(w, http.StatusMethodNotAllowed, "method_not_allowed", "Only GET is allowed", nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -3963,7 +3964,7 @@ func (r *Router) handleDownloadDockerInstallerScript(w http.ResponseWriter, req
|
|||
}
|
||||
|
||||
func (r *Router) handleDownloadMigrationScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
writeErrorResponse(w, http.StatusMethodNotAllowed, "method_not_allowed", "Only GET is allowed", nil)
|
||||
return
|
||||
}
|
||||
|
|
@ -3988,7 +3989,7 @@ func (r *Router) handleDownloadMigrationScript(w http.ResponseWriter, req *http.
|
|||
}
|
||||
|
||||
func (r *Router) handleDownloadTemperatureProxyMigrationScript(w http.ResponseWriter, req *http.Request) {
|
||||
if req.Method != http.MethodGet {
|
||||
if req.Method != http.MethodGet && req.Method != http.MethodHead {
|
||||
writeErrorResponse(w, http.StatusMethodNotAllowed, "method_not_allowed", "Only GET is allowed", nil)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,3 +91,29 @@ func TestHandleDownloadHostAgentServesChecksumForWindowsExe(t *testing.T) {
|
|||
t.Fatalf("unexpected checksum body: got %q want %q", got, expected)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandleDownloadHostAgentAllowsHEAD(t *testing.T) {
|
||||
binDir := setupTempPulseBin(t)
|
||||
filePath := filepath.Join(binDir, "pulse-host-agent-linux-amd64")
|
||||
if err := os.WriteFile(filePath, []byte("binary"), 0o755); err != nil {
|
||||
t.Fatalf("failed to write test binary: %v", err)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest(http.MethodHead, "/download/pulse-host-agent?platform=linux&arch=amd64", nil)
|
||||
rr := httptest.NewRecorder()
|
||||
|
||||
router := &Router{}
|
||||
router.handleDownloadHostAgent(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected 200 OK for HEAD, got %d", rr.Code)
|
||||
}
|
||||
|
||||
// HEAD response should have Content-Length but no body
|
||||
// Note: httptest.ResponseRecorder might capture body even for HEAD if handler writes it,
|
||||
// but standard http.Server suppresses it.
|
||||
// However, our handler uses http.ServeContent which respects HEAD.
|
||||
if rr.Body.Len() > 0 {
|
||||
t.Fatalf("expected empty body for HEAD, got %d bytes", rr.Body.Len())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue