diff --git a/cmd/goget/main.go b/cmd/goget/main.go index 39e6fee..5166ec8 100644 --- a/cmd/goget/main.go +++ b/cmd/goget/main.go @@ -130,9 +130,12 @@ func runPostDownload( fmt.Fprintf(os.Stderr, "Warning: failed to close writer: %v\n", cerr) } - // Adjust extension: append .html to HTML files without extension + // Adjust extension: append .html to HTML files without extension. + // When ContentType is available (WebDAV, Gopher), only apply to + // text/html responses. When ContentType is empty (HTTP legacy + // path), preserve the existing wget-compatible behaviour. if *f.AdjustExt && *f.Output != "" { - if filepath.Ext(*f.Output) == "" { + if filepath.Ext(*f.Output) == "" && isHTMLContentType(result.ContentType) { newPath := *f.Output + ".html" if err := os.Rename(*f.Output, newPath); err == nil { *f.Output = newPath @@ -289,6 +292,20 @@ func runPostDownload( return 0 } +// isHTMLContentType returns true when ct indicates HTML content. +// An empty string is treated as HTML for backward compatibility with +// protocol handlers that do not populate ContentType (e.g. HTTP). +func isHTMLContentType(ct string) bool { + if ct == "" { + return true + } + // Strip parameters (charset, boundary, …). + if i := strings.IndexByte(ct, ';'); i >= 0 { + ct = ct[:i] + } + return strings.TrimSpace(ct) == "text/html" +} + // splitCommand splits a shell-like command string into tokens respecting double quotes. // Used to parse --on-complete and --on-complete-url without invoking a shell. func splitCommand(raw string) []string { diff --git a/internal/core/types.go b/internal/core/types.go index 834cb58..67a5f4a 100644 --- a/internal/core/types.go +++ b/internal/core/types.go @@ -103,6 +103,7 @@ type DownloadResult struct { Parallel bool ChunksCount int HTTPStatusCode int // HTTP status code from response + ContentType string // Content-Type from response (if available) TraceTimings *TraceTimings // HTTP tracing breakdown } diff --git a/internal/protocol/gopher/gopher.go b/internal/protocol/gopher/gopher.go index d7b45d7..84a65f4 100644 --- a/internal/protocol/gopher/gopher.go +++ b/internal/protocol/gopher/gopher.go @@ -209,9 +209,22 @@ func (p *Protocol) downloadText(ctx context.Context, reader *bufio.Reader, req * IPVersion: 4, Speed: speed, OutputPath: req.Output, + ContentType: gopherContentType(firstType), }, nil } +// gopherContentType returns the MIME content type for a gopher item type. +func gopherContentType(t byte) string { + switch t { + case typeHTML: + return "text/html" + case typeTextFile, typeInformation: + return "text/plain" + default: + return "application/octet-stream" + } +} + // downloadDirectory formats a directory listing as readable text. func (p *Protocol) downloadDirectory(reader *bufio.Reader, req *core.DownloadRequest, startTime time.Time) (*core.DownloadResult, error) { var writer io.Writer @@ -261,6 +274,7 @@ func (p *Protocol) downloadDirectory(reader *bufio.Reader, req *core.DownloadReq IPVersion: 4, Speed: speed, OutputPath: req.Output, + ContentType: "text/plain", }, nil } @@ -313,6 +327,7 @@ func (p *Protocol) downloadBinary(ctx context.Context, reader *bufio.Reader, req IPVersion: 4, Speed: speed, OutputPath: req.Output, + ContentType: "application/octet-stream", }, nil } diff --git a/internal/protocol/webdav/protocol.go b/internal/protocol/webdav/protocol.go index 128e0ce..0beef30 100644 --- a/internal/protocol/webdav/protocol.go +++ b/internal/protocol/webdav/protocol.go @@ -680,6 +680,7 @@ func (p *Protocol) downloadFile(ctx context.Context, req *core.DownloadRequest, OutputPath: req.Output, Resumed: resumed, ChunksCount: 1, + ContentType: resp.Header.Get("Content-Type"), }, nil }