-
Notifications
You must be signed in to change notification settings - Fork 180
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix!: fix colon in media type for windows (#698)
Fixes #697 Signed-off-by: Billy Zha <jinzha1@microsoft.com>
- Loading branch information
Showing
8 changed files
with
285 additions
and
50 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
//go:build !windows | ||
|
||
/* | ||
Copyright The ORAS Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package fileref | ||
|
||
import "testing" | ||
|
||
func Test_ParseFileReference(t *testing.T) { | ||
type args struct { | ||
reference string | ||
mediaType string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantFilePath string | ||
wantMediatype string | ||
}{ | ||
{"file name and media type", args{"az:b", ""}, "az", "b"}, | ||
{"file name and empty media type", args{"az:", ""}, "az", ""}, | ||
{"file name and default media type", args{"az", "c"}, "az", "c"}, | ||
{"file name and media type, default type ignored", args{"az:b", "c"}, "az", "b"}, | ||
{"file name and empty media type, default type ignored", args{"az:", "c"}, "az", ""}, | ||
{"colon file name and media type", args{"az:b:c", "d"}, "az:b", "c"}, | ||
{"colon file name and empty media type", args{"az:b:", "c"}, "az:b", ""}, | ||
{"colon-prefix file name and media type", args{":az:b:c", "d"}, ":az:b", "c"}, | ||
|
||
{"pure colon file name and media type", args{"::a", "b"}, ":", "a"}, | ||
{"pure colon file name and empty media type", args{"::", "a"}, ":", ""}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
gotFilePath, gotMediatype, _ := Parse(tt.args.reference, tt.args.mediaType) | ||
if gotFilePath != tt.wantFilePath { | ||
t.Errorf("Parse() gotFilePath = %v, want %v", gotFilePath, tt.wantFilePath) | ||
} | ||
if gotMediatype != tt.wantMediatype { | ||
t.Errorf("Parse() gotMediatype = %v, want %v", gotMediatype, tt.wantMediatype) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestParse(t *testing.T) { | ||
type args struct { | ||
reference string | ||
mediaType string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantFilePath string | ||
wantMediatype string | ||
wantErr bool | ||
}{ | ||
|
||
{"no input", args{"", ""}, "", "", true}, | ||
{"empty file name and media type", args{":", ""}, "", "", true}, | ||
{"empty file name with media type", args{":a", "b"}, "", "", true}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
gotFilePath, gotMediatype, err := Parse(tt.args.reference, tt.args.mediaType) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if gotFilePath != tt.wantFilePath { | ||
t.Errorf("Parse() gotFilePath = %v, want %v", gotFilePath, tt.wantFilePath) | ||
} | ||
if gotMediatype != tt.wantMediatype { | ||
t.Errorf("Parse() gotMediatype = %v, want %v", gotMediatype, tt.wantMediatype) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
//go:build windows | ||
|
||
/* | ||
Copyright The ORAS Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package fileref | ||
|
||
import ( | ||
"fmt" | ||
"strings" | ||
"unicode" | ||
) | ||
|
||
// Parse parses file reference on windows. | ||
func Parse(reference string, defaultMediaType string) (filePath, mediaType string, err error) { | ||
filePath, mediaType = doParse(reference, defaultMediaType) | ||
if filePath == "" { | ||
return "", "", fmt.Errorf("found empty file path in %q", reference) | ||
} | ||
if strings.ContainsAny(filePath, `<>:"|?*`) { | ||
// Reference: https://learn.microsoft.com/windows/win32/fileio/naming-a-file#naming-conventions | ||
return "", "", fmt.Errorf("reserved characters found in the file path: %s", filePath) | ||
} | ||
return filePath, mediaType, nil | ||
} | ||
|
||
func doParse(reference string, mediaType string) (filePath, mediatype string) { | ||
i := strings.LastIndex(reference, ":") | ||
if i < 0 || (i == 1 && len(reference) > 2 && unicode.IsLetter(rune(reference[0])) && reference[2] == '\\') { | ||
// Relative file path with disk prefix is NOT supported, e.g. `c:file1` | ||
return reference, mediaType | ||
} | ||
return reference[:i], reference[i+1:] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
//go:build windows | ||
|
||
/* | ||
Copyright The ORAS Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package fileref | ||
|
||
import ( | ||
"testing" | ||
) | ||
|
||
func Test_doParse(t *testing.T) { | ||
type args struct { | ||
reference string | ||
mediaType string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantFilePath string | ||
wantMediatype string | ||
}{ | ||
{"file name and media type", args{"az:b", ""}, "az", "b"}, | ||
{"file name and empty media type", args{"az:", ""}, "az", ""}, | ||
{"file name and default media type", args{"az", "c"}, "az", "c"}, | ||
{"file name and media type, default type ignored", args{"az:b", "c"}, "az", "b"}, | ||
{"file name and empty media type, default type ignored", args{"az:", "c"}, "az", ""}, | ||
|
||
{"empty file name and media type", args{":a", "b"}, "", "a"}, | ||
{"empty file name and empty media type", args{":", "a"}, "", ""}, | ||
{"empty name and default media type", args{"", "a"}, "", "a"}, | ||
|
||
{"colon file name and media type", args{"az:b:c", "d"}, "az:b", "c"}, | ||
{"colon file name and empty media type", args{"az:b:", "c"}, "az:b", ""}, | ||
{"colon-prefix file name and media type", args{":az:b:c", "d"}, ":az:b", "c"}, | ||
|
||
{"pure colon file name and media type", args{"::a", "b"}, ":", "a"}, | ||
{"pure colon file name and empty media type", args{"::", "a"}, ":", ""}, | ||
|
||
{"windows file name1 and default type", args{`a:\b`, "c"}, `a:\b`, "c"}, | ||
{"windows file name2 and default type", args{`z:b`, "c"}, `z`, "b"}, | ||
{"windows file name and media type", args{`a:\b:c`, "d"}, `a:\b`, "c"}, | ||
{"windows file name and empty media type", args{`a:\b:`, "c"}, `a:\b`, ""}, | ||
{"numeric file name and media type", args{`1:\a`, "b"}, `1`, `\a`}, | ||
{"non-windows file name and media type", args{`ab:\c`, ""}, `ab`, `\c`}, | ||
{"non-windows file name and media type, default type ignored", args{`1:\a`, "b"}, `1`, `\a`}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
gotFilePath, gotMediatype := doParse(tt.args.reference, tt.args.mediaType) | ||
if gotFilePath != tt.wantFilePath { | ||
t.Errorf("doParse() gotFilePath = %v, want %v", gotFilePath, tt.wantFilePath) | ||
} | ||
if gotMediatype != tt.wantMediatype { | ||
t.Errorf("doParse() gotMediatype = %v, want %v", gotMediatype, tt.wantMediatype) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestParse(t *testing.T) { | ||
type args struct { | ||
reference string | ||
mediaType string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
wantFilePath string | ||
wantMediatype string | ||
wantErr bool | ||
}{ | ||
{"no input", args{"", ""}, "", "", true}, | ||
{"empty file name", args{":", ""}, "", "", true}, | ||
{"reserved character1 in file name", args{"<", "a"}, "", "", true}, | ||
{"reserved character2 in file name", args{">", "a"}, "", "", true}, | ||
{"reserved character3 in file name", args{"*", "a"}, "", "", true}, | ||
{"reserved character4 in file name", args{`"`, "a"}, "", "", true}, | ||
{"reserved character5 in file name", args{"|", "a"}, "", "", true}, | ||
{"reserved character6 in file name", args{"?", "a"}, "", "", true}, | ||
{"empty file name, with media type", args{":", "a"}, "", "", true}, | ||
{"reserved character1 in file name, with media type", args{"<:", "a"}, "", "", true}, | ||
{"reserved character2 in file name, with media type", args{">:", "a"}, "", "", true}, | ||
{"reserved character3 in file name, with media type", args{"*:", "a"}, "", "", true}, | ||
{"reserved character4 in file name, with media type", args{`":`, "a"}, "", "", true}, | ||
{"reserved character5 in file name, with media type", args{"|:", "a"}, "", "", true}, | ||
{"reserved character6 in file name, with media type", args{"?:", "a"}, "", "", true}, | ||
{"reserved character7 in file name, with media type", args{"::", "a"}, "", "", true}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
gotFilePath, gotMediatype, err := Parse(tt.args.reference, tt.args.mediaType) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if gotFilePath != tt.wantFilePath { | ||
t.Errorf("Parse() gotFilePath = %v, want %v", gotFilePath, tt.wantFilePath) | ||
} | ||
if gotMediatype != tt.wantMediatype { | ||
t.Errorf("Parse() gotMediatype = %v, want %v", gotMediatype, tt.wantMediatype) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters