4

Consider the following very basic "net/http"-program:

package main

import (
    "net/http"
    "log"
)

func entry(w http.ResponseWriter, req *http.Request) {
    log.Println(req.URL.Path)
    path := []byte(req.URL.Path)    
    w.Write(path)
}

func main() {
    http.HandleFunc("/", entry)
    err := http.ListenAndServe("localhost:10000", nil)
    if err != nil {
        log.Fatal("ListenAndServe: ", err)
    }
}

When accessing the URL, http://localhost:10000/a//b, the DefaultServerMux, which is what the default HandleFunc() and ListenAndServe() uses, redirects it to /a/b, effectively removing the double slash.

The documentation for ServerMux does specify that it 'sanitises' URL requests:

ServeMux also takes care of sanitizing the URL request path, redirecting any request containing . or .. elements or repeated slashes to an equivalent, cleaner URL.

But what if I don't want it to? I have a scenario where // != / in my URLs. I could find another solution. But is there a way to still use Go's "net/http" package, while it not sanitising my URLs like this? Preferably with as little re-writing as possible.

(I will probably find a different solution than having // and / being distinct, since I am probably happy with other features that ServerMux provides (in case a solution requires me to use another multiplexer), but now I am curious whether there is a solution with Go's standard "net/http" package.)

Svip
  • 2,958
  • 3
  • 22
  • 33
  • I don't think so if using `//` slash will be a good url indeed. – Himanshu Aug 18 '18 at 11:47
  • It really shouldn't do that, except perhaps for `http.FileServer` (because `//` is equivalent to `/` when the OS resolves a file path). A path with an empty segment is perfectly valid according to RFC 3986. – Michael Hampton Aug 18 '18 at 15:00
  • @MichaelHampton If @Himanshu's answer is accurate, it would seem it uses path's `Clean()` function, we acts upon the path as if it was a file path. For instance, if you accessed `/../`, it would redirect you to `/`. – Svip Aug 18 '18 at 15:13
  • 1
    Write your own mux (aka router) or find a third party mux that does not clean the path. – Charlie Tumahai Aug 18 '18 at 17:18

1 Answers1

2

Go for gorilla mux to route the server using the url. By default the DefaultSeveMux uses Clean which modify the url against various unwanted characters. That's the reason the url changed whn you are using // double slash.

func Clean(path string) string

While if you do not want to sanitize the url. Gorilla mux provide a method SkipClean() which when set to true. It will not sanitize the url.

func (r *Router) SkipClean(value bool) *Router {
    r.skipClean = value
    return r
}

It is mentioned in the document of gorilla mux for SkipClean() as:

SkipClean defines the path cleaning behaviour for new routes. The initial value is false. Users should be careful about which routes are not cleaned When true, if the route path is "/path//to", it will remain with the double slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/ When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will become /fetch/http/xkcd.com/534

Himanshu
  • 12,071
  • 7
  • 46
  • 61