OSDN Git Service

Merge branch 'master' into wallet-store-interface-account
[bytom/vapor.git] / vendor / github.com / gin-gonic / gin / path.go
diff --git a/vendor/github.com/gin-gonic/gin/path.go b/vendor/github.com/gin-gonic/gin/path.go
new file mode 100644 (file)
index 0000000..d1f5962
--- /dev/null
@@ -0,0 +1,123 @@
+// Copyright 2013 Julien Schmidt. All rights reserved.
+// Based on the path package, Copyright 2009 The Go Authors.
+// Use of this source code is governed by a BSD-style license that can be found
+// at https://github.com/julienschmidt/httprouter/blob/master/LICENSE.
+
+package gin
+
+// cleanPath is the URL version of path.Clean, it returns a canonical URL path
+// for p, eliminating . and .. elements.
+//
+// The following rules are applied iteratively until no further processing can
+// be done:
+//     1. Replace multiple slashes with a single slash.
+//     2. Eliminate each . path name element (the current directory).
+//     3. Eliminate each inner .. path name element (the parent directory)
+//        along with the non-.. element that precedes it.
+//     4. Eliminate .. elements that begin a rooted path:
+//        that is, replace "/.." by "/" at the beginning of a path.
+//
+// If the result of this process is an empty string, "/" is returned.
+func cleanPath(p string) string {
+       // Turn empty string into "/"
+       if p == "" {
+               return "/"
+       }
+
+       n := len(p)
+       var buf []byte
+
+       // Invariants:
+       //      reading from path; r is index of next byte to process.
+       //      writing to buf; w is index of next byte to write.
+
+       // path must start with '/'
+       r := 1
+       w := 1
+
+       if p[0] != '/' {
+               r = 0
+               buf = make([]byte, n+1)
+               buf[0] = '/'
+       }
+
+       trailing := n > 1 && p[n-1] == '/'
+
+       // A bit more clunky without a 'lazybuf' like the path package, but the loop
+       // gets completely inlined (bufApp). So in contrast to the path package this
+       // loop has no expensive function calls (except 1x make)
+
+       for r < n {
+               switch {
+               case p[r] == '/':
+                       // empty path element, trailing slash is added after the end
+                       r++
+
+               case p[r] == '.' && r+1 == n:
+                       trailing = true
+                       r++
+
+               case p[r] == '.' && p[r+1] == '/':
+                       // . element
+                       r += 2
+
+               case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'):
+                       // .. element: remove to last /
+                       r += 3
+
+                       if w > 1 {
+                               // can backtrack
+                               w--
+
+                               if buf == nil {
+                                       for w > 1 && p[w] != '/' {
+                                               w--
+                                       }
+                               } else {
+                                       for w > 1 && buf[w] != '/' {
+                                               w--
+                                       }
+                               }
+                       }
+
+               default:
+                       // real path element.
+                       // add slash if needed
+                       if w > 1 {
+                               bufApp(&buf, p, w, '/')
+                               w++
+                       }
+
+                       // copy element
+                       for r < n && p[r] != '/' {
+                               bufApp(&buf, p, w, p[r])
+                               w++
+                               r++
+                       }
+               }
+       }
+
+       // re-append trailing slash
+       if trailing && w > 1 {
+               bufApp(&buf, p, w, '/')
+               w++
+       }
+
+       if buf == nil {
+               return p[:w]
+       }
+       return string(buf[:w])
+}
+
+// internal helper to lazily create a buffer if necessary.
+func bufApp(buf *[]byte, s string, w int, c byte) {
+       if *buf == nil {
+               if s[w] == c {
+                       return
+               }
+
+               *buf = make([]byte, len(s))
+               copy(*buf, s[:w])
+       }
+       (*buf)[w] = c
+}