mirror of https://github.com/golang/go.git
Merge ebae55c43b into 49cdf0c42e
This commit is contained in:
commit
95536e0592
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import (
|
|||
"bufio"
|
||||
"os"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
package mime
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
|
@ -33,6 +34,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 {
|
||||
|
|
@ -42,3 +46,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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue