diff --git a/CHANGELOG.md b/CHANGELOG.md index cb9540a..e63e3b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ This document outlines major changes between releases. ## [Unreleased] +## [0.32.4] - 2025-02-14 + +### Changed +- Improved content-type detector (#188) + ## [0.32.3] - 2025-02-05 ### Added @@ -202,4 +207,5 @@ To see CHANGELOG for older versions, refer to https://github.com/nspcc-dev/neofs [0.32.1]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.0...v0.32.1 [0.32.2]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.1...v0.32.2 [0.32.3]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.2...v0.32.3 -[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.3...master \ No newline at end of file +[0.32.4]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.3...v0.32.4 +[Unreleased]: https://git.frostfs.info/TrueCloudLab/frostfs-http-gw/compare/v0.32.4...master \ No newline at end of file diff --git a/VERSION b/VERSION index 2c768c5..a630fff 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.32.3 +v0.32.4 diff --git a/internal/handler/head.go b/internal/handler/head.go index f2e9f38..da96eff 100644 --- a/internal/handler/head.go +++ b/internal/handler/head.go @@ -45,7 +45,11 @@ func (h *Handler) headObject(ctx context.Context, req request, objectAddress oid } req.Response.Header.Set(fasthttp.HeaderContentLength, strconv.FormatUint(obj.PayloadSize(), 10)) - var contentType string + var ( + contentType string + filename string + filepath string + ) for _, attr := range obj.Attributes() { key := attr.Key() val := attr.Value() @@ -69,8 +73,15 @@ func (h *Handler) headObject(ctx context.Context, req request, objectAddress oid req.Response.Header.Set(fasthttp.HeaderLastModified, time.Unix(value, 0).UTC().Format(http.TimeFormat)) case object.AttributeContentType: contentType = val + case object.AttributeFilePath: + filepath = val + case object.AttributeFileName: + filename = val } } + if filename == "" { + filename = filepath + } idsToResponse(&req.Response, obj) @@ -85,7 +96,7 @@ func (h *Handler) headObject(ctx context.Context, req request, objectAddress oid } return h.frostfs.RangeObject(ctx, prmRange) - }) + }, filename) if err != nil && err != io.EOF { req.handleFrostFSErr(err, start) return diff --git a/internal/handler/reader.go b/internal/handler/reader.go index 50121c9..60067ab 100644 --- a/internal/handler/reader.go +++ b/internal/handler/reader.go @@ -4,9 +4,11 @@ import ( "bytes" "context" "io" + "mime" "net/http" "path" "strconv" + "strings" "time" "git.frostfs.info/TrueCloudLab/frostfs-http-gw/internal/logs" @@ -25,7 +27,7 @@ type readCloser struct { // initializes io.Reader with the limited size and detects Content-Type from it. // Returns r's error directly. Also returns the processed data. -func readContentType(maxSize uint64, rInit func(uint64) (io.Reader, error)) (string, []byte, error) { +func readContentType(maxSize uint64, rInit func(uint64) (io.Reader, error), filename string) (string, []byte, error) { if maxSize > sizeToDetectType { maxSize = sizeToDetectType } @@ -44,7 +46,20 @@ func readContentType(maxSize uint64, rInit func(uint64) (io.Reader, error)) (str buf = buf[:n] - return http.DetectContentType(buf), buf, err // to not lose io.EOF + contentType := http.DetectContentType(buf) + + // Since the detector detects the "text/plain" content type for various types of text files, + // including CSS, JavaScript, and CSV files, + // we'll determine the final content type based on the file's extension. + if strings.HasPrefix(contentType, "text/plain") { + ext := path.Ext(filename) + // If the file doesn't have a file extension, we'll keep the content type as is. + if len(ext) > 0 { + contentType = mime.TypeByExtension(ext) + } + } + + return contentType, buf, err // to not lose io.EOF } type getMultiobjectBodyParams struct { @@ -128,7 +143,7 @@ func (h *Handler) receiveFile(ctx context.Context, req request, objAddress oid.A contentType, payloadHead, err = readContentType(payloadSize, func(uint64) (io.Reader, error) { return payload, nil - }) + }, filename) if err != nil && err != io.EOF { req.log.Error(logs.CouldNotDetectContentTypeFromPayload, zap.Error(err)) response.Error(req.RequestCtx, "could not detect Content-Type from payload: "+err.Error(), fasthttp.StatusBadRequest) diff --git a/internal/handler/reader_test.go b/internal/handler/reader_test.go index c63a734..f867677 100644 --- a/internal/handler/reader_test.go +++ b/internal/handler/reader_test.go @@ -10,39 +10,80 @@ import ( "github.com/stretchr/testify/require" ) +const ( + txtContentType = "text/plain; charset=utf-8" + cssContentType = "text/css; charset=utf-8" + htmlContentType = "text/html; charset=utf-8" + javascriptContentType = "text/javascript; charset=utf-8" + + htmlBody = "