読者です 読者をやめる 読者になる 読者になる

uokadaの見逃し三振は嫌いです

ここで述べられていることは私の個人的な意見に基づくものであり、私が所属する組織には一切の関係はありません。

gorilla/muxのPathでハマってる話

gorilla/mux 使ってwebアプリつくろうと思って下みたいなルーティングを作ったんだけど、 "//"の部分がどうにもダメらしい。

package main

import (
    "net/http"
    "github.com/gorilla/mux"
)

func init() {
    r := mux.NewRouter()
    r.HandleFunc("/*{protocol:(https?)}://{domain}/{path:[a-zA-Z0-9/]+}", BaseHandler)
    http.Handle("/", r)
}

URLパラメータにURLを渡したいんだけどダメみたいだね。 "//"を正規表現に含めるような書き方に変えてもなんかエラーが出てしまう。。。 バグ扱いにして直してくれないかな。

mux - GoDoc ドキュメント読むと正規表現って言ってるんだし受け入れてくれてもいいと思うんだけどな。 とりあえず、過去のissue探してみるか。


追記: mux単体で動かしてみたら"/"2つ含んだパスだと1つ削ってリダイレクトしてたので、 どこでそんな処理してるか調べてみた。
すると下の部分が該当した。 cleanPath()のなかでpath.Clean()してるのが原因。 mux/mux.go at master · gorilla/mux · GitHub

ServerHTTP()の先頭でcleanPath()呼んでるしな。 https://github.com/gorilla/mux/blob/master/mux.go#L67-99

こうなると、path.Clean呼ばれないようにするにはforkするしかないかな。


2015-02-10 追記:
src/net/http/server.go - The Go Programming Language

gorilla/muxを外してnet/httpしかない状態で試しても同じ状態だったのでソースコードを読んでみたらこんな事なってた。

func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string) {
    if r.Method != "CONNECT" {
        if p := cleanPath(r.URL.Path); p != r.URL.Path {
            _, pattern = mux.handler(r.Host, p)
            url := *r.URL
            url.Path = p
            return RedirectHandler(url.String(), StatusMovedPermanently), pattern
        }
    }

    return mux.handler(r.Host, r.URL.Path)
}
// Return the canonical path for p, eliminating . and .. elements.
func cleanPath(p string) string {
    if p == "" {
        return "/"
    }
    if p[0] != '/' {
        p = "/" + p
    }
    np := path.Clean(p)
    // path.Clean removes trailing slash except for root;
    // put the trailing slash back if necessary.
    if p[len(p)-1] == '/' && np != "/" {
        np += "/"
    }
    return np
}

すべてのリクエストがcleanPathで一回処理されて、処理の前後で一致しなかったらリダイレクトしてる。cleanPathで必ず除去されると。

こうなると、net/http使わずに実装するぐらいしか方法ないのかな。


HTTP Server is too clean with its URLs - Google グループ
同じこと質問してる人がいたのでこれやればいけるかな。