From 6b5bc7bb304975147b4af68df54ac214ed2554c1 Mon Sep 17 00:00:00 2001 From: Erik Dubbelboer Date: Mon, 28 Feb 2022 11:56:59 +0100 Subject: [PATCH] Add windows support to normalizePath This is probably still not 100% sure and there are still many bugs with FS on windows. But it's a slight improvement. Fixes #1226 --- strings.go | 34 ++++++++++++++++++--------------- uri.go | 55 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/strings.go b/strings.go index e4fb08bdac..370e307989 100644 --- a/strings.go +++ b/strings.go @@ -7,21 +7,25 @@ var ( ) var ( - strSlash = []byte("/") - strSlashSlash = []byte("//") - strSlashDotDot = []byte("/..") - strSlashDotSlash = []byte("/./") - strSlashDotDotSlash = []byte("/../") - strCRLF = []byte("\r\n") - strHTTP = []byte("http") - strHTTPS = []byte("https") - strHTTP10 = []byte("HTTP/1.0") - strHTTP11 = []byte("HTTP/1.1") - strColon = []byte(":") - strColonSlashSlash = []byte("://") - strColonSpace = []byte(": ") - strCommaSpace = []byte(", ") - strGMT = []byte("GMT") + strSlash = []byte("/") + strSlashSlash = []byte("//") + strSlashDotDot = []byte("/..") + strSlashDotSlash = []byte("/./") + strSlashDotDotSlash = []byte("/../") + strBackSlashDotDot = []byte(`\..`) + strBackSlashDotBackSlash = []byte(`\.\`) + strSlashDotDotBackSlash = []byte(`/..\`) + strBackSlashDotDotBackSlash = []byte(`\..\`) + strCRLF = []byte("\r\n") + strHTTP = []byte("http") + strHTTPS = []byte("https") + strHTTP10 = []byte("HTTP/1.0") + strHTTP11 = []byte("HTTP/1.1") + strColon = []byte(":") + strColonSlashSlash = []byte("://") + strColonSpace = []byte(": ") + strCommaSpace = []byte(", ") + strGMT = []byte("GMT") strResponseContinue = []byte("HTTP/1.1 100 Continue\r\n\r\n") diff --git a/uri.go b/uri.go index 62974df896..38a431e1d0 100644 --- a/uri.go +++ b/uri.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "io" + "path/filepath" "strconv" "sync" ) @@ -634,6 +635,60 @@ func normalizePath(dst, src []byte) []byte { b = b[:nn+1] } + if filepath.Separator == '\\' { + // remove \.\ parts + b = dst + for { + n := bytes.Index(b, strBackSlashDotBackSlash) + if n < 0 { + break + } + nn := n + len(strSlashDotSlash) - 1 + copy(b[n:], b[nn:]) + b = b[:len(b)-nn+n] + } + + // remove /foo/..\ parts + for { + n := bytes.Index(b, strSlashDotDotBackSlash) + if n < 0 { + break + } + nn := bytes.LastIndexByte(b[:n], '/') + if nn < 0 { + nn = 0 + } + n += len(strSlashDotDotBackSlash) - 1 + copy(b[nn:], b[n:]) + b = b[:len(b)-n+nn] + } + + // remove /foo\..\ parts + for { + n := bytes.Index(b, strBackSlashDotDotBackSlash) + if n < 0 { + break + } + nn := bytes.LastIndexByte(b[:n], '/') + if nn < 0 { + nn = 0 + } + n += len(strBackSlashDotDotBackSlash) - 1 + copy(b[nn:], b[n:]) + b = b[:len(b)-n+nn] + } + + // remove trailing \foo\.. + n := bytes.LastIndex(b, strBackSlashDotDot) + if n >= 0 && n+len(strSlashDotDot) == len(b) { + nn := bytes.LastIndexByte(b[:n], '/') + if nn < 0 { + return append(dst[:0], strSlash...) + } + b = b[:nn+1] + } + } + return b }