[99s-extend] Proposal for Cowboy Routing

Thomas Allen thomas at oinksoft.com
Tue Nov 13 17:10:04 CET 2012


On Tue, Nov 13, 2012 at 04:22:48PM +0100, Loïc Hoguin wrote:
> No, just check that cowboy_req:path/1 ends with $/, and if it
> doesn't then redirect.

OK, so what I'm going for is to actually check for a valid URL with the
slash. I got it to work in current cowboy, but shield your eyes ...

I do this "middleware" thing often ... this might be a misnomer as I
think some definitions of middleware specify that it be able to wrap the
request *and* the response. I digress ...

    %%% foo_app.erl:

    {ok, _} = cowboy:start_http(http, ?ACCEPTORS,
        [{port, ?PORT}],
        [{dispatch, Dispatch},
         {onrequest, fun(Req) ->
             foo_middleware:all(Dispatch, Req)
          end}]
    ),


    %% foo_middleware.erl:

    -define(MIDDLEWARE, [
        fun foo_middleware:slash/2,
        fun foo_middleware:session/2,
        fun foo_middleware:user/2
    ]).

    all(Dispatch, Req) ->
        lists:foldl(fun(F, CurReq) -> F(Dispatch, CurReq) end, Req,
            ?MIDDLEWARE).

    %% ...

    slash(Dispatch, Req) ->
        {Path, _} = cowboy_req:path(Req),
        case binary:last(Path) of
            $/ -> Req;
            _ ->
                SlashPath = <<Path/bitstring, "/">>,
                {Host, _} = cowboy_req:host(Req),
                Match = cowboy_dispatcher:match(Dispatch, Host,
                    SlashPath),
                case element(1, Match) of
                    ok ->
                        cowboy_req:reply(301,
                            [{<<"Location">>, SlashPath}], <<>>, Req);
                    error -> Req
                end
        end.

So, I assume that any path not ending in "/" won't match. Another
version of this could toss that assumption, but then you're performing
an extra match on every request ... much better to use a '_' rule in
that case.

One thing that is icky about using a fallback '_' handler, and the
reason I've elected to use onrequest for this example, is that I do not
see a way to access cowboy_protocol's state.dispatch to access these
rules. So, I enclose them in my `onrequest` fun. Would it be possible to
expose Dispatch? This has many applications, particularly for URL
reversing.

Perhaps I am missing several things ;^)

Thomas



More information about the Extend mailing list