build(deps): bump github.com/gabriel-vasile/mimetype from 1.4.3 to 1.4.4
Bumps [github.com/gabriel-vasile/mimetype](https://github.com/gabriel-vasile/mimetype) from 1.4.3 to 1.4.4. - [Release notes](https://github.com/gabriel-vasile/mimetype/releases) - [Commits](https://github.com/gabriel-vasile/mimetype/compare/v1.4.3...v1.4.4) --- updated-dependencies: - dependency-name: github.com/gabriel-vasile/mimetype dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
committed by
Ralf Haferkamp
parent
0a1ee3906c
commit
ca79f2003c
@@ -19,7 +19,7 @@ require (
|
|||||||
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
|
github.com/dhowden/tag v0.0.0-20230630033851-978a0926ee25
|
||||||
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
github.com/dutchcoders/go-clamd v0.0.0-20170520113014-b970184f4d9e
|
||||||
github.com/egirna/icap-client v0.1.1
|
github.com/egirna/icap-client v0.1.1
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3
|
github.com/gabriel-vasile/mimetype v1.4.4
|
||||||
github.com/ggwhite/go-masker v1.1.0
|
github.com/ggwhite/go-masker v1.1.0
|
||||||
github.com/go-chi/chi/v5 v5.0.12
|
github.com/go-chi/chi/v5 v5.0.12
|
||||||
github.com/go-chi/cors v1.2.1
|
github.com/go-chi/cors v1.2.1
|
||||||
|
|||||||
@@ -1124,8 +1124,8 @@ github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMo
|
|||||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
github.com/gabriel-vasile/mimetype v1.4.4 h1:QjV6pZ7/XZ7ryI2KuyeEDE8wnh7fHP9YnQy+R0LnH8I=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
github.com/gabriel-vasile/mimetype v1.4.4/go.mod h1:JwLei5XPtWdGiMFB5Pjle1oEeoSeEuJfJE+TtfvdB/s=
|
||||||
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
|
github.com/gdexlab/go-render v1.0.1 h1:rxqB3vo5s4n1kF0ySmoNeSPRYkEsyHgln4jFIQY7v0U=
|
||||||
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
|
github.com/gdexlab/go-render v1.0.1/go.mod h1:wRi5nW2qfjiGj4mPukH4UV0IknS1cHD4VgFTmJX5JzM=
|
||||||
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
|
github.com/getkin/kin-openapi v0.13.0/go.mod h1:WGRs2ZMM1Q8LR1QBEwUxC6RJEfaBcD0s+pcEVXFuAjw=
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018-2020 Gabriel Vasile
|
Copyright (c) 2018 Gabriel Vasile
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
|||||||
-3
@@ -16,9 +16,6 @@
|
|||||||
<a href="https://goreportcard.com/report/github.com/gabriel-vasile/mimetype">
|
<a href="https://goreportcard.com/report/github.com/gabriel-vasile/mimetype">
|
||||||
<img alt="Go report card" src="https://goreportcard.com/badge/github.com/gabriel-vasile/mimetype">
|
<img alt="Go report card" src="https://goreportcard.com/badge/github.com/gabriel-vasile/mimetype">
|
||||||
</a>
|
</a>
|
||||||
<a href="https://codecov.io/gh/gabriel-vasile/mimetype">
|
|
||||||
<img alt="Code coverage" src="https://codecov.io/gh/gabriel-vasile/mimetype/branch/master/graph/badge.svg?token=qcfJF1kkl2"/>
|
|
||||||
</a>
|
|
||||||
<a href="LICENSE">
|
<a href="LICENSE">
|
||||||
<img alt="License" src="https://img.shields.io/badge/License-MIT-green.svg">
|
<img alt="License" src="https://img.shields.io/badge/License-MIT-green.svg">
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
+74
-37
@@ -3,6 +3,7 @@ package magic
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -74,51 +75,87 @@ func CRX(raw []byte, limit uint32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tar matches a (t)ape (ar)chive file.
|
// Tar matches a (t)ape (ar)chive file.
|
||||||
|
// Tar files are divided into 512 bytes records. First record contains a 257
|
||||||
|
// bytes header padded with NUL.
|
||||||
func Tar(raw []byte, _ uint32) bool {
|
func Tar(raw []byte, _ uint32) bool {
|
||||||
// The "magic" header field for files in in UStar (POSIX IEEE P1003.1) archives
|
const sizeRecord = 512
|
||||||
// has the prefix "ustar". The values of the remaining bytes in this field vary
|
|
||||||
// by archiver implementation.
|
|
||||||
if len(raw) >= 512 && bytes.HasPrefix(raw[257:], []byte{0x75, 0x73, 0x74, 0x61, 0x72}) {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(raw) < 256 {
|
// The structure of a tar header:
|
||||||
|
// type TarHeader struct {
|
||||||
|
// Name [100]byte
|
||||||
|
// Mode [8]byte
|
||||||
|
// Uid [8]byte
|
||||||
|
// Gid [8]byte
|
||||||
|
// Size [12]byte
|
||||||
|
// Mtime [12]byte
|
||||||
|
// Chksum [8]byte
|
||||||
|
// Linkflag byte
|
||||||
|
// Linkname [100]byte
|
||||||
|
// Magic [8]byte
|
||||||
|
// Uname [32]byte
|
||||||
|
// Gname [32]byte
|
||||||
|
// Devmajor [8]byte
|
||||||
|
// Devminor [8]byte
|
||||||
|
// }
|
||||||
|
|
||||||
|
if len(raw) < sizeRecord {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
raw = raw[:sizeRecord]
|
||||||
|
|
||||||
|
// First 100 bytes of the header represent the file name.
|
||||||
|
// Check if file looks like Gentoo GLEP binary package.
|
||||||
|
if bytes.Contains(raw[:100], []byte("/gpkg-1\x00")) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// The older v7 format has no "magic" field, and therefore must be identified
|
// Get the checksum recorded into the file.
|
||||||
// with heuristics based on legal ranges of values for other header fields:
|
recsum, err := tarParseOctal(raw[148:156])
|
||||||
// https://www.nationalarchives.gov.uk/PRONOM/Format/proFormatSearch.aspx?status=detailReport&id=385&strPageToDisplay=signatures
|
if err != nil {
|
||||||
rules := []struct {
|
return false
|
||||||
min, max uint8
|
|
||||||
i int
|
|
||||||
}{
|
|
||||||
{0x21, 0xEF, 0},
|
|
||||||
{0x30, 0x37, 105},
|
|
||||||
{0x20, 0x37, 106},
|
|
||||||
{0x00, 0x00, 107},
|
|
||||||
{0x30, 0x37, 113},
|
|
||||||
{0x20, 0x37, 114},
|
|
||||||
{0x00, 0x00, 115},
|
|
||||||
{0x30, 0x37, 121},
|
|
||||||
{0x20, 0x37, 122},
|
|
||||||
{0x00, 0x00, 123},
|
|
||||||
{0x30, 0x37, 134},
|
|
||||||
{0x30, 0x37, 146},
|
|
||||||
{0x30, 0x37, 153},
|
|
||||||
{0x00, 0x37, 154},
|
|
||||||
}
|
}
|
||||||
for _, r := range rules {
|
sum1, sum2 := tarChksum(raw)
|
||||||
if raw[r.i] < r.min || raw[r.i] > r.max {
|
return recsum == sum1 || recsum == sum2
|
||||||
return false
|
}
|
||||||
}
|
|
||||||
|
// tarParseOctal converts octal string to decimal int.
|
||||||
|
func tarParseOctal(b []byte) (int64, error) {
|
||||||
|
// Because unused fields are filled with NULs, we need to skip leading NULs.
|
||||||
|
// Fields may also be padded with spaces or NULs.
|
||||||
|
// So we remove leading and trailing NULs and spaces to be sure.
|
||||||
|
b = bytes.Trim(b, " \x00")
|
||||||
|
|
||||||
|
if len(b) == 0 {
|
||||||
|
return 0, nil
|
||||||
|
}
|
||||||
|
x, err := strconv.ParseUint(tarParseString(b), 8, 64)
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return int64(x), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// tarParseString converts a NUL ended bytes slice to a string.
|
||||||
|
func tarParseString(b []byte) string {
|
||||||
|
if i := bytes.IndexByte(b, 0); i >= 0 {
|
||||||
|
return string(b[:i])
|
||||||
}
|
}
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
|
|
||||||
for _, i := range []uint8{135, 147, 155} {
|
// tarChksum computes the checksum for the header block b.
|
||||||
if raw[i] != 0x00 && raw[i] != 0x20 {
|
// The actual checksum is written to same b block after it has been calculated.
|
||||||
return false
|
// Before calculation the bytes from b reserved for checksum have placeholder
|
||||||
|
// value of ASCII space 0x20.
|
||||||
|
// POSIX specifies a sum of the unsigned byte values, but the Sun tar used
|
||||||
|
// signed byte values. We compute and return both.
|
||||||
|
func tarChksum(b []byte) (unsigned, signed int64) {
|
||||||
|
for i, c := range b {
|
||||||
|
if 148 <= i && i < 156 {
|
||||||
|
c = ' ' // Treat the checksum field itself as all spaces.
|
||||||
}
|
}
|
||||||
|
unsigned += int64(c)
|
||||||
|
signed += int64(int8(c))
|
||||||
}
|
}
|
||||||
|
return unsigned, signed
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-1
@@ -153,8 +153,11 @@ func ftyp(sigs ...[]byte) Detector {
|
|||||||
if len(raw) < 12 {
|
if len(raw) < 12 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
if !bytes.Equal(raw[4:8], []byte("ftyp")) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
for _, s := range sigs {
|
for _, s := range sigs {
|
||||||
if bytes.Equal(raw[4:12], append([]byte("ftyp"), s...)) {
|
if bytes.Equal(raw[8:12], s) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-19
@@ -1,7 +1,6 @@
|
|||||||
package magic
|
package magic
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
|
||||||
"bytes"
|
"bytes"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -234,9 +233,10 @@ func GeoJSON(raw []byte, limit uint32) bool {
|
|||||||
// types.
|
// types.
|
||||||
func NdJSON(raw []byte, limit uint32) bool {
|
func NdJSON(raw []byte, limit uint32) bool {
|
||||||
lCount, hasObjOrArr := 0, false
|
lCount, hasObjOrArr := 0, false
|
||||||
sc := bufio.NewScanner(dropLastLine(raw, limit))
|
raw = dropLastLine(raw, limit)
|
||||||
for sc.Scan() {
|
var l []byte
|
||||||
l := sc.Bytes()
|
for len(raw) != 0 {
|
||||||
|
l, raw = scanLine(raw)
|
||||||
// Empty lines are allowed in NDJSON.
|
// Empty lines are allowed in NDJSON.
|
||||||
if l = trimRWS(trimLWS(l)); len(l) == 0 {
|
if l = trimRWS(trimLWS(l)); len(l) == 0 {
|
||||||
continue
|
continue
|
||||||
@@ -301,20 +301,15 @@ func Svg(raw []byte, limit uint32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Srt matches a SubRip file.
|
// Srt matches a SubRip file.
|
||||||
func Srt(in []byte, _ uint32) bool {
|
func Srt(raw []byte, _ uint32) bool {
|
||||||
s := bufio.NewScanner(bytes.NewReader(in))
|
line, raw := scanLine(raw)
|
||||||
if !s.Scan() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
// First line must be 1.
|
|
||||||
if s.Text() != "1" {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if !s.Scan() {
|
// First line must be 1.
|
||||||
|
if string(line) != "1" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
secondLine := s.Text()
|
line, raw = scanLine(raw)
|
||||||
|
secondLine := string(line)
|
||||||
// Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine
|
// Timestamp format (e.g: 00:02:16,612 --> 00:02:19,376) limits secondLine
|
||||||
// length to exactly 29 characters.
|
// length to exactly 29 characters.
|
||||||
if len(secondLine) != 29 {
|
if len(secondLine) != 29 {
|
||||||
@@ -325,14 +320,12 @@ func Srt(in []byte, _ uint32) bool {
|
|||||||
if strings.Contains(secondLine, ".") {
|
if strings.Contains(secondLine, ".") {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
// For Go <1.17, comma is not recognised as a decimal separator by `time.Parse`.
|
|
||||||
secondLine = strings.ReplaceAll(secondLine, ",", ".")
|
|
||||||
// Second line must be a time range.
|
// Second line must be a time range.
|
||||||
ts := strings.Split(secondLine, " --> ")
|
ts := strings.Split(secondLine, " --> ")
|
||||||
if len(ts) != 2 {
|
if len(ts) != 2 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const layout = "15:04:05.000"
|
const layout = "15:04:05,000"
|
||||||
t0, err := time.Parse(layout, ts[0])
|
t0, err := time.Parse(layout, ts[0])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false
|
return false
|
||||||
@@ -345,8 +338,9 @@ func Srt(in []byte, _ uint32) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
line, _ = scanLine(raw)
|
||||||
// A third line must exist and not be empty. This is the actual subtitle text.
|
// A third line must exist and not be empty. This is the actual subtitle text.
|
||||||
return s.Scan() && len(s.Bytes()) != 0
|
return len(line) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Vtt matches a Web Video Text Tracks (WebVTT) file. See
|
// Vtt matches a Web Video Text Tracks (WebVTT) file. See
|
||||||
@@ -373,3 +367,15 @@ func Vtt(raw []byte, limit uint32) bool {
|
|||||||
return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT"
|
return bytes.Equal(raw, []byte{0xEF, 0xBB, 0xBF, 0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) || // UTF-8 BOM and "WEBVTT"
|
||||||
bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT"
|
bytes.Equal(raw, []byte{0x57, 0x45, 0x42, 0x56, 0x54, 0x54}) // "WEBVTT"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// dropCR drops a terminal \r from the data.
|
||||||
|
func dropCR(data []byte) []byte {
|
||||||
|
if len(data) > 0 && data[len(data)-1] == '\r' {
|
||||||
|
return data[0 : len(data)-1]
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
func scanLine(b []byte) (line, remainder []byte) {
|
||||||
|
line, remainder, _ = bytes.Cut(b, []byte("\n"))
|
||||||
|
return dropCR(line), remainder
|
||||||
|
}
|
||||||
|
|||||||
+8
-14
@@ -18,7 +18,7 @@ func Tsv(raw []byte, limit uint32) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func sv(in []byte, comma rune, limit uint32) bool {
|
func sv(in []byte, comma rune, limit uint32) bool {
|
||||||
r := csv.NewReader(dropLastLine(in, limit))
|
r := csv.NewReader(bytes.NewReader(dropLastLine(in, limit)))
|
||||||
r.Comma = comma
|
r.Comma = comma
|
||||||
r.ReuseRecord = true
|
r.ReuseRecord = true
|
||||||
r.LazyQuotes = true
|
r.LazyQuotes = true
|
||||||
@@ -44,20 +44,14 @@ func sv(in []byte, comma rune, limit uint32) bool {
|
|||||||
// mimetype limits itself to ReadLimit bytes when performing a detection.
|
// mimetype limits itself to ReadLimit bytes when performing a detection.
|
||||||
// This means, for file formats like CSV for NDJSON, the last line of the input
|
// This means, for file formats like CSV for NDJSON, the last line of the input
|
||||||
// can be an incomplete line.
|
// can be an incomplete line.
|
||||||
func dropLastLine(b []byte, cutAt uint32) io.Reader {
|
func dropLastLine(b []byte, readLimit uint32) []byte {
|
||||||
if cutAt == 0 {
|
if readLimit == 0 || uint32(len(b)) < readLimit {
|
||||||
return bytes.NewReader(b)
|
return b
|
||||||
}
|
}
|
||||||
if uint32(len(b)) >= cutAt {
|
for i := len(b) - 1; i > 0; i-- {
|
||||||
for i := cutAt - 1; i > 0; i-- {
|
if b[i] == '\n' {
|
||||||
if b[i] == '\n' {
|
return b[:i]
|
||||||
return bytes.NewReader(b[:i])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No newline was found between the 0 index and cutAt.
|
|
||||||
return bytes.NewReader(b[:cutAt])
|
|
||||||
}
|
}
|
||||||
|
return b
|
||||||
return bytes.NewReader(b)
|
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-3
@@ -7,14 +7,15 @@ package mimetype
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
|
||||||
"mime"
|
"mime"
|
||||||
"os"
|
"os"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var defaultLimit uint32 = 3072
|
||||||
|
|
||||||
// readLimit is the maximum number of bytes from the input used when detecting.
|
// readLimit is the maximum number of bytes from the input used when detecting.
|
||||||
var readLimit uint32 = 3072
|
var readLimit uint32 = defaultLimit
|
||||||
|
|
||||||
// Detect returns the MIME type found from the provided byte slice.
|
// Detect returns the MIME type found from the provided byte slice.
|
||||||
//
|
//
|
||||||
@@ -48,7 +49,7 @@ func DetectReader(r io.Reader) (*MIME, error) {
|
|||||||
// Using atomic because readLimit can be written at the same time in other goroutine.
|
// Using atomic because readLimit can be written at the same time in other goroutine.
|
||||||
l := atomic.LoadUint32(&readLimit)
|
l := atomic.LoadUint32(&readLimit)
|
||||||
if l == 0 {
|
if l == 0 {
|
||||||
in, err = ioutil.ReadAll(r)
|
in, err = io.ReadAll(r)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errMIME, err
|
return errMIME, err
|
||||||
}
|
}
|
||||||
@@ -103,6 +104,7 @@ func EqualsAny(s string, mimes ...string) bool {
|
|||||||
// SetLimit sets the maximum number of bytes read from input when detecting the MIME type.
|
// SetLimit sets the maximum number of bytes read from input when detecting the MIME type.
|
||||||
// Increasing the limit provides better detection for file formats which store
|
// Increasing the limit provides better detection for file formats which store
|
||||||
// their magical numbers towards the end of the file: docx, pptx, xlsx, etc.
|
// their magical numbers towards the end of the file: docx, pptx, xlsx, etc.
|
||||||
|
// During detection data is read in a single block of size limit, i.e. it is not buffered.
|
||||||
// A limit of 0 means the whole input file will be used.
|
// A limit of 0 means the whole input file will be used.
|
||||||
func SetLimit(limit uint32) {
|
func SetLimit(limit uint32) {
|
||||||
// Using atomic because readLimit can be read at the same time in other goroutine.
|
// Using atomic because readLimit can be read at the same time in other goroutine.
|
||||||
|
|||||||
Vendored
+1
-1
@@ -799,7 +799,7 @@ github.com/felixge/httpsnoop
|
|||||||
# github.com/fsnotify/fsnotify v1.7.0
|
# github.com/fsnotify/fsnotify v1.7.0
|
||||||
## explicit; go 1.17
|
## explicit; go 1.17
|
||||||
github.com/fsnotify/fsnotify
|
github.com/fsnotify/fsnotify
|
||||||
# github.com/gabriel-vasile/mimetype v1.4.3
|
# github.com/gabriel-vasile/mimetype v1.4.4
|
||||||
## explicit; go 1.20
|
## explicit; go 1.20
|
||||||
github.com/gabriel-vasile/mimetype
|
github.com/gabriel-vasile/mimetype
|
||||||
github.com/gabriel-vasile/mimetype/internal/charset
|
github.com/gabriel-vasile/mimetype/internal/charset
|
||||||
|
|||||||
Reference in New Issue
Block a user