Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

mime: range glob expansions in type_unix.go #53974

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
nikola-jokic wants to merge 3 commits into golang:master
base: master
Choose a base branch
Loading
from nikola-jokic:nikola-jokic/mime-glob-range-expansion
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/mime/testdata/test.types.globs2
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
50:example/test:*.t4
50:text/plain:*,v
50:application/x-trash:*~
50:application/x-test-man:*.[1-3]
30:example/do-not-use:*.t4
10:example/glob-question-mark:*.foo?ar
10:example/glob-asterisk:*.foo*r
Expand Down
113 changes: 112 additions & 1 deletion src/mime/type_unix.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"bufio"
"os"
"strings"
"unicode"
)

func init() {
Expand Down Expand Up @@ -49,7 +50,8 @@ func loadMimeGlobsFile(filename string) error {
}

extension := fields[2][1:]
if strings.ContainsAny(extension, "?*[") {
switch {
case strings.ContainsAny(extension, "?*"):
// Not a bare extension, but a glob. Ignore for now:
// - we do not have an implementation for this glob
// syntax (translation to path/filepath.Match could
Expand All @@ -60,7 +62,15 @@ func loadMimeGlobsFile(filename string) error {
// - trying to match glob metacharacters literally is
// not useful
continue
case strings.Contains(extension, "["):
if extensions, ok := expand(extension); ok {
for i := range extensions {
setExtensionType(extensions[i], fields[1])
}
}
continue
}

if _, ok := mimeTypes.Load(extension); ok {
// We've already seen this extension.
// The file is in weight order, so we keep
Expand Down Expand Up @@ -124,3 +134,104 @@ func initMimeForTests() map[string]string {
".png": "image/png",
}
}

func expand(glob string) ([]string, bool) {
openingBracketIndex := -1
closingBracketIndex := -1

var prefix []byte
var suffix []byte
var mux *[]byte = &prefix

for i, c := range glob {
if c > unicode.MaxASCII {
return nil, false
}
switch c {
case '[':
if len(*mux) > 0 && (*mux)[len(*mux)-1] == '\\' {
(*mux)[len(*mux)-1] = glob[i]
continue
}
if openingBracketIndex != -1 {
if closingBracketIndex != -1 {
return nil, false
}
continue
}
openingBracketIndex = i
mux = &suffix
case ']':
if openingBracketIndex == -1 {
*mux = append(*mux, ']')
continue
}
if i == openingBracketIndex+1 {
continue
}
closingBracketIndex = i
default:
if openingBracketIndex > -1 && closingBracketIndex == -1 {
continue
}
*mux = append(*mux, glob[i])
}
}

switch {
case openingBracketIndex == -1 && closingBracketIndex == -1:
return []string{string(prefix)}, true

case openingBracketIndex != -1 && closingBracketIndex == -1:
return []string{string(prefix) + glob[openingBracketIndex:]}, true

case openingBracketIndex != -1 && openingBracketIndex+1 == '!':
return nil, false
}

expansion := expandRangeWithoutNegation(glob[openingBracketIndex+1 : closingBracketIndex])
if expansion == nil {
return nil, false
}

results := make([]string, len(expansion))
for i := 0; i < len(expansion); i++ {
results[i] = string(prefix) + string(expansion[i]) + string(suffix)
}

return results, true
}

func expandRangeWithoutNegation(r string) []byte {
var expansion []byte
for i := 0; i < len(r); i++ {
if r[i] == '!' && i == 0 {
// no negations of range expression
return nil
}

if r[i] != '-' {
expansion = append(expansion, r[i])
continue
}

if i == 0 || i == len(r)-1 {
expansion = append(expansion, '-')
continue
}
if r[i+1] < r[i-1] {
// invalid character range
return nil
}

for c := r[i-1] + 1; c <= r[i+1]; c++ {
if c == '/' {
// '/' cannot be matched: https://man7.org/linux/man-pages/man7/glob.7.html
continue
}
expansion = append(expansion, c)
}
i++
}
return expansion
}
132 changes: 132 additions & 0 deletions src/mime/type_unix_test.go
View file Open in desktop
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
package mime

import (
"reflect"
"testing"
)

Expand All @@ -32,6 +33,9 @@ func TestTypeByExtensionUNIX(t *testing.T) {
".foo?ar": "",
".foo*r": "",
".foo[1-3]": "",
".foo1": "example/glob-range",
".foo2": "example/glob-range",
".foo3": "example/glob-range",
}

for ext, want := range typeTests {
Expand All @@ -41,3 +45,131 @@ func TestTypeByExtensionUNIX(t *testing.T) {
}
}
}

func TestMimeExtension(t *testing.T) {
initMimeUnixTest(t)

tests := []struct {
typ string
want []string
}{
{typ: "example/glob-range", want: []string{".foo1", ".foo2", ".foo3"}},
{typ: "application/x-test-man", want: []string{".1", ".2", ".3"}},
}

for _, tt := range tests {
got, err := ExtensionsByType(tt.typ)
if err != nil {
t.Errorf("ExtensionsByType(%q): %v", tt.typ, err)
continue
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("ExtensionsByType(%q) = %q; want %q", tt.typ, got, tt.want)
}
}
}

func Test_expansion(t *testing.T) {
tests := []struct {
glob string
ok bool
want []string
}{
{
glob: "foo",
ok: true,
want: []string{"foo"},
},
{
glob: ".foo[1-3da-c]",
ok: true,
want: []string{".foo1", ".foo2", ".foo3", ".food", ".fooa", ".foob", ".fooc"},
},
{
glob: ".foo[1-3][1-4]",
ok: false,
},
{
glob: `.foo\[1-3`,
ok: true,
want: []string{".foo[1-3"},
},
{
glob: `.foo[1-3`,
ok: true,
want: []string{".foo[1-3"},
},
{
glob: ".foo1-3]",
ok: true,
want: []string{".foo1-3]"},
},
{
glob: ".foo[12-]",
ok: true,
want: []string{".foo1", ".foo2", ".foo-"},
},
{
glob: ".foo[-12]",
ok: true,
want: []string{".foo-", ".foo1", ".foo2"},
},
{
glob: ".foo[3-1]",
ok: false,
},
{
glob: "foo[1-3].bar",
ok: true,
want: []string{"foo1.bar", "foo2.bar", "foo3.bar"},
},
{
glob: ".foo[!1-3]",
ok: false,
},
{
glob: ".foo[!12]",
ok: false,
},
{
glob: ".foo[1-3!a]",
ok: true,
want: []string{".foo1", ".foo2", ".foo3", ".foo!", ".fooa"},
},
{
glob: "[0-12-5]",
ok: true,
want: []string{"0", "1", "2", "3", "4", "5"},
},
{
glob: "[][!]",
ok: true,
want: []string{"]", "[", "!"},
},
{
glob: "[--0*?]",
ok: true,
want: []string{"-", ".", "0", "*", "?"},
},
{
glob: ".foo[]",
ok: true,
want: []string{".foo[]"},
},
{
glob: ".foo[1-3][4-5]",
ok: false,
},
}

for _, tt := range tests {
got, ok := expand(tt.glob)
if ok != tt.ok {
t.Errorf("expansion(%q) status = %v; want %v", tt.glob, ok, tt.ok)
}

if !reflect.DeepEqual(got, tt.want) {
t.Errorf("expansion(%q) result = %q; want %q", tt.glob, got, tt.want)
}
}
}

AltStyle によって変換されたページ (->オリジナル) /