Re: [go-nuts] http.HandleFunc case insensitive path match, default match

1,837 views
Skip to first unread message

Kyle Lemons

unread,
Mar 5, 2013, 6:33:24 PM3/5/13
to shka...@gmail.com, golang-nuts
On Tue, Mar 5, 2013 at 9:08 AM, <shka...@gmail.com> wrote:
Hi Gophers,
Recently I was playing with go's http package and I ran into a few issues. Could someone help me with those and/or point me in the right direction (I'm on windows).
  1. When I map path to handlers inside http.HandleFunc("path/to/handle", handler) it uses case sensitive match. So if I declare '/home' and user types in '/Home' the server responds with 404 error. Is there any way to use case insensitive match
URLs are case sensitive.  You could wrap your handler with a function that lower-cases the path if that's really what you want. Are your users really used to typing /Home and not clicking a link?
  1. My current setup is 2 handlers: one that handles "/home" (homecontroller) and serves a page and the other one "/" a fallthrough handler that serves CSS, JS, Images, Static html.  The problem is I want default page "/" to be handled by homecontroller and all other pages by the fallthrough handler (something similar to "/*"). Can it be done?
Check the path inside the / handler.  You could also give static content a prefix, like "/static" 
  1. What is the idiomatic way to write a controller in go? One package per controller, one struct per controller (something scalable and maintainable)?
If by "controller" you mean the design pattern, don't.  Just write the code, don't try to fit it into a pattern.  If you mean handler, don't limit yourself to one per package.
 
Thank you.

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Kevin Gillette

unread,
Mar 5, 2013, 8:09:41 PM3/5/13
to golan...@googlegroups.com, shka...@gmail.com
On Tuesday, March 5, 2013 5:11:03 PM UTC-7, shka...@gmail.com wrote:
I'm not sure what you mean by "You could wrap your handler with a function". Could you please give an example. I'm sure it is something obvious I just don't see it :)


It's an example of a function that takes an http.Handler and returns an http.Handler -- essentially mutating the request. Of course, you don't have to follow this model -- you could write a func that takes a HandlerFunc and returns a HandlerFunc that can be passed to http.HandleFunc.

The design of net/http is very flexible, and it's perfectly reasonable to use the provided functions and interface methods in strange ways to meet your needs.

Andy Balholm

unread,
Mar 6, 2013, 10:57:09 PM3/6/13
to golan...@googlegroups.com, shka...@gmail.com
Actually, I think it would make more sense to wrap the ServeMux with an object that converts everything to lower case.

Kyle Lemons

unread,
Mar 6, 2013, 10:57:44 PM3/6/13
to Sergey Shkarupin, golang-nuts
Instead of that, you'd do

http.ListenAndServe(*httpAddr, ignorePath(http.DefaultServeMux))

which would lower-case the path before even going into the serve mux.


On Wed, Mar 6, 2013 at 7:21 PM, <shka...@gmail.com> wrote:
Kevin,
thank you. I assume you mean something like this (from my current implementation): http.HandleFunc("/Home", ignorePathCase(controller.Home))
Isn't the handler called after the path is matched?

--

Kevin Gillette

unread,
Mar 6, 2013, 11:01:04 PM3/6/13
to golan...@googlegroups.com, shka...@gmail.com
To case-insensitively match "/Home" (as in "/home" or "/homE"), you need to match handle the parent path component.

func main() {
    // ...
    mux := http.NewServeMux()
    http.Handle("/", CaselessMatcher(mux))

    // specify all paths passed to mux as lowercase since
    // CaselessMatcher lowercases the paths before they reach mux
    mux.HandleFunc("/home", HandleHome)
    // ...
}

func CaselessMatcher(h http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        r.URL.Path = strings.ToLower(r.URL.Path)
        h.ServeHTTP(w, r)
    })
}

On Wednesday, March 6, 2013 8:21:36 PM UTC-7, shka...@gmail.com wrote:
Kevin,
thank you. I assume you mean something like this (from my current implementation): http.HandleFunc("/Home", ignorePathCase(controller.Home))
Isn't the handler called after the path is matched?

On Tuesday, March 5, 2013 7:09:41 PM UTC-6, Kevin Gillette wrote:

Kyle Lemons

unread,
Mar 7, 2013, 12:46:32 PM3/7/13
to Kevin Gillette, golang-nuts, Sergey Shkarupin
In general it is not good practice to simply lower-case the path and pass it on.  Instead, you want to generate a (permanent) redirect to the correct path if the requested path is incorrect.  Because you probably don't want to do this for all URLs (it would prevent you from using the http.FileServer to serve anything with a capital letter), you probably want to make a simple ServeMux clone that does what you want.  Something like http://play.golang.org/p/1WHFPdTXgR (untested).


--

Kevin Gillette

unread,
Mar 7, 2013, 12:59:26 PM3/7/13
to golan...@googlegroups.com, Kevin Gillette, Sergey Shkarupin
Although I bound to "/" (which may be appropriate if the entire app is purposed around these arbitrarily cased URLs), my intent was that the method would only be applied to the immediate prefix of where these paths live.

It may also be a compatibility concern: if attempting to replace an early IIS-based application with Go and retain transparent compatibility, all paths may need to be treated case insensitively (though query parameters would not), and if you cannot count on a client to obey the casing of published URLs, then you probably cannot count on them to handle redirects either.

That said, yes, I do like the insensitive matching approach you just proposed rather than mutating the URL, though it does involve considerably more code, and would thus be more likely employed if standardized or placed in a published package somewhere.

Kyle Lemons

unread,
Mar 7, 2013, 8:26:18 PM3/7/13
to Kevin Gillette, golang-nuts, Sergey Shkarupin
fwiw, my straw man is really flammable; it should actually check both the case sensitive and case insensitive one so it can change the case of the correct portion of the URL and so it doesn't always fall back to / even if there would be a case insensitive match.  Anyway, thus the (untested) :).
Reply all
Reply to author
Forward
0 new messages