@@ -7,6 +7,7 @@ const Uri = @This();
77/// - consistent percent encoding (implementations may escape differently)
88/// - consistent casing of the Windows drive letter
99/// - consistent path seperator on Windows (convert '\\' to '/')
10+ /// - always add an authority component even if unnecessary
1011raw : []const u8 ,
1112
1213pub fn parse (allocator : std.mem.Allocator , text : []const u8 ) (std .Uri .ParseError || error {OutOfMemory })! Uri {
@@ -22,9 +23,8 @@ fn parseWithOs(
2223
2324 const capacity = capacity : {
2425 var capacity : usize = 0 ;
25- capacity += uri .scheme .len + ":" .len ;
26+ capacity += uri .scheme .len + ":" .len + "//" .len ;
2627 if (uri .host ) | host | {
27- capacity += "//" .len ;
2828 if (uri .user ) | user | {
2929 capacity += user .percent_encoded .len ;
3030 if (uri .password ) | password | {
@@ -47,9 +47,8 @@ fn parseWithOs(
4747 errdefer result .deinit (allocator );
4848
4949 result .appendSliceAssumeCapacity (uri .scheme );
50- result .appendAssumeCapacity ( ':' );
50+ result .appendSliceAssumeCapacity ( "://" );
5151 if (uri .host ) | host | {
52- result .appendSliceAssumeCapacity ("//" );
5352 if (uri .user ) | user | {
5453 normalizePercentEncoded (& result , user .percent_encoded , & isUserChar );
5554 if (uri .password ) | password | {
@@ -92,15 +91,15 @@ fn parseWithOs(
9291}
9392
9493test "parse (posix)" {
95- const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/foo/main.zig" , false );
94+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/// foo/main.zig" , false );
9695 defer uri .deinit (std .testing .allocator );
97- try std .testing .expectEqualStrings ("file:/foo/main.zig" , uri .raw );
96+ try std .testing .expectEqualStrings ("file:/// foo/main.zig" , uri .raw );
9897}
9998
10099test "parse (windows)" {
101- const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/C:/foo\\ main.zig" , true );
100+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/// C:/foo\\ main.zig" , true );
102101 defer uri .deinit (std .testing .allocator );
103- try std .testing .expectEqualStrings ("file:/c:/foo/main.zig" , uri .raw );
102+ try std .testing .expectEqualStrings ("file:/// c:/foo/main.zig" , uri .raw );
104103}
105104
106105test "parse - UNC (windows)" {
@@ -109,34 +108,40 @@ test "parse - UNC (windows)" {
109108 try std .testing .expectEqualStrings ("file://wsl.localhost/foo/main.zig" , uri .raw );
110109}
111110
111+ test "parse - always add authority component (posix)" {
112+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/foo/main.zig" , false );
113+ defer uri .deinit (std .testing .allocator );
114+ try std .testing .expectEqualStrings ("file:///foo/main.zig" , uri .raw );
115+ }
116+
112117test "parse - normalize percent encoding (posix)" {
113- const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/foo%5cmain%2ezig" , false );
118+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/// foo%5cmain%2ezig" , false );
114119 defer uri .deinit (std .testing .allocator );
115- try std .testing .expectEqualStrings ("file:/foo%5Cmain.zig" , uri .raw );
120+ try std .testing .expectEqualStrings ("file:/// foo%5Cmain.zig" , uri .raw );
116121}
117122
118123test "parse - convert percent encoded '\\ ' to '/' (windows)" {
119- const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/C:%5Cmain.zig" , true );
124+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/// C:%5Cmain.zig" , true );
120125 defer uri .deinit (std .testing .allocator );
121- try std .testing .expectEqualStrings ("file:/c:/main.zig" , uri .raw );
126+ try std .testing .expectEqualStrings ("file:/// c:/main.zig" , uri .raw );
122127}
123128
124129test "parse - preserve percent encoded '\\ ' (posix)" {
125- const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/foo%5Cmain.zig" , false );
130+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/// foo%5Cmain.zig" , false );
126131 defer uri .deinit (std .testing .allocator );
127- try std .testing .expectEqualStrings ("file:/foo%5Cmain.zig" , uri .raw );
132+ try std .testing .expectEqualStrings ("file:/// foo%5Cmain.zig" , uri .raw );
128133}
129134
130135test "parse - percent encoded drive letter (windows)" {
131- const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/%43%3a%5Cfoo\\ main.zig" , true );
136+ const uri : Uri = try .parseWithOs (std .testing .allocator , "file:/// %43%3a%5Cfoo\\ main.zig" , true );
132137 defer uri .deinit (std .testing .allocator );
133- try std .testing .expectEqualStrings ("file:/c:/foo/main.zig" , uri .raw );
138+ try std .testing .expectEqualStrings ("file:/// c:/foo/main.zig" , uri .raw );
134139}
135140
136141test "parse - windows like path on posix" {
137142 const uri : Uri = try .parseWithOs (std .testing .allocator , "file:///C:%5Cmain.zig" , false );
138143 defer uri .deinit (std .testing .allocator );
139- try std .testing .expectEqualStrings ("file:/C:%5Cmain.zig" , uri .raw );
144+ try std .testing .expectEqualStrings ("file:/// C:%5Cmain.zig" , uri .raw );
140145}
141146
142147pub fn deinit (uri : Uri , allocator : std.mem.Allocator ) void {
@@ -181,7 +186,7 @@ fn fromPathWithOs(
181186 path : []const u8 ,
182187 comptime is_windows : bool ,
183188) error {OutOfMemory }! Uri {
184- var buf : std .ArrayList (u8 ) = try .initCapacity (allocator , path .len + 6 );
189+ var buf : std .ArrayList (u8 ) = try .initCapacity (allocator , path .len + "file:///" .len );
185190 errdefer buf .deinit (allocator );
186191
187192 buf .appendSliceAssumeCapacity ("file:" );
@@ -192,7 +197,9 @@ fn fromPathWithOs(
192197 {
193198 // UNC path
194199 } else if (! std .mem .startsWith (u8 , path , "/" )) {
195- buf .appendAssumeCapacity ('/' );
200+ buf .appendSliceAssumeCapacity ("///" );
201+ } else {
202+ buf .appendSliceAssumeCapacity ("//" );
196203 }
197204
198205 var value = path ;
@@ -226,7 +233,7 @@ test "fromPath (posix)" {
226233 const uri = try fromPathWithOs (std .testing .allocator , "/home/main.zig" , false );
227234 defer uri .deinit (std .testing .allocator );
228235
229- try std .testing .expectEqualStrings ("file:/home/main.zig" , uri .raw );
236+ try std .testing .expectEqualStrings ("file:/// home/main.zig" , uri .raw );
230237
231238 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , false );
232239 defer reparsed_uri .deinit (std .testing .allocator );
@@ -237,7 +244,7 @@ test "fromPath (windows)" {
237244 const uri = try fromPathWithOs (std .testing .allocator , "C:/main.zig" , true );
238245 defer uri .deinit (std .testing .allocator );
239246
240- try std .testing .expectEqualStrings ("file:/c:/main.zig" , uri .raw );
247+ try std .testing .expectEqualStrings ("file:/// c:/main.zig" , uri .raw );
241248
242249 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , true );
243250 defer reparsed_uri .deinit (std .testing .allocator );
@@ -259,7 +266,7 @@ test "fromPath - preserve '\\' (posix)" {
259266 const uri = try fromPathWithOs (std .testing .allocator , "/home\\ main.zig" , false );
260267 defer uri .deinit (std .testing .allocator );
261268
262- try std .testing .expectEqualStrings ("file:/home%5Cmain.zig" , uri .raw );
269+ try std .testing .expectEqualStrings ("file:/// home%5Cmain.zig" , uri .raw );
263270
264271 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , false );
265272 defer reparsed_uri .deinit (std .testing .allocator );
@@ -270,7 +277,7 @@ test "fromPath - convert '\\' to '/' (windows)" {
270277 const uri = try fromPathWithOs (std .testing .allocator , "C:\\ main.zig" , true );
271278 defer uri .deinit (std .testing .allocator );
272279
273- try std .testing .expectEqualStrings ("file:/c:/main.zig" , uri .raw );
280+ try std .testing .expectEqualStrings ("file:/// c:/main.zig" , uri .raw );
274281
275282 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , true );
276283 defer reparsed_uri .deinit (std .testing .allocator );
@@ -281,7 +288,7 @@ test "fromPath - root directory (posix)" {
281288 const uri = try fromPathWithOs (std .testing .allocator , "/" , false );
282289 defer uri .deinit (std .testing .allocator );
283290
284- try std .testing .expectEqualStrings ("file:/" , uri .raw );
291+ try std .testing .expectEqualStrings ("file:/// " , uri .raw );
285292
286293 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , false );
287294 defer reparsed_uri .deinit (std .testing .allocator );
@@ -292,7 +299,7 @@ test "fromPath - root directory (windows)" {
292299 const uri = try fromPathWithOs (std .testing .allocator , "C:/" , true );
293300 defer uri .deinit (std .testing .allocator );
294301
295- try std .testing .expectEqualStrings ("file:/c:/" , uri .raw );
302+ try std .testing .expectEqualStrings ("file:/// c:/" , uri .raw );
296303
297304 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , true );
298305 defer reparsed_uri .deinit (std .testing .allocator );
@@ -303,7 +310,7 @@ test "fromPath - windows like path on posix" {
303310 const uri = try fromPathWithOs (std .testing .allocator , "/C:\\ main.zig" , false );
304311 defer uri .deinit (std .testing .allocator );
305312
306- try std .testing .expectEqualStrings ("file:/C:%5Cmain.zig" , uri .raw );
313+ try std .testing .expectEqualStrings ("file:/// C:%5Cmain.zig" , uri .raw );
307314
308315 const reparsed_uri : Uri = try .parseWithOs (std .testing .allocator , uri .raw , false );
309316 defer reparsed_uri .deinit (std .testing .allocator );
0 commit comments