1. Benoit Chesneau
  2. webmachine

Commits

benoitc  committed 634391d

add vhost support to webmachine. Works as discussed on ml :
http://lists.therestfulway.com/pipermail/webmachine_lists.therestfulway.com/2009-September/000077.html

so you can do

[[cname, "example", ".com"], ["a"], some_resource, []}.

[["www", "example", ".com"], ["a"], some_resource, []}.
[['*', "example", ".com"], ["a"], some_resource, []}.

...

all rules for path dispatching works.

  • Participants
  • Parent commits b9b526e
  • Branches vhost

Comments (0)

Files changed (2)

File src/webmachine_dispatcher.erl

View file
 -author('Robert Ahrens <rahrens@basho.com>').
 -author('Justin Sheehy <justin@basho.com>').
 
--export([dispatch/2]).
+-export([dispatch/3]).
 
 -define(SEPARATOR, $\/).
 -define(MATCH_ALL, '*').
 
-%% @spec dispatch(Path::string(), DispatchList::[matchterm()]) ->
+%% @spec dispatch(HostName:string(), Path::string(), DispatchList::[matchterm()]) ->
 %%                                            dispterm() | dispfail()
 %% @doc Interface for URL dispatching.
 %% See also http://bitbucket.org/justin/webmachine/wiki/DispatchConfiguration
-dispatch(PathAsString, DispatchList) ->
+dispatch(HostNameAsString, PathAsString, DispatchList) ->
+    HostNameParts = split_hostname(HostNameAsString),
+    io:format("hostname parts ~p ~n", [HostNameParts]),
     Path = string:tokens(PathAsString, [?SEPARATOR]),
     % URIs that end with a trailing slash are implicitly one token
     % "deeper" than we otherwise might think as we are "inside"
 		     true -> 1;
 		     _ -> 0
 		 end,
-    try_binding(DispatchList, Path, ExtraDepth).
+	case try_binding_host(DispatchList, [], [], HostNameParts) of
+	    no_host_match ->
+            try_binding(DispatchList, Path, ExtraDepth);
+        {DispatchList1, Bindings} ->
+            case try_binding(DispatchList1, Path, ExtraDepth) of
+                {no_dispatch_match, _UnmatchedPathTokens} ->
+                    case try_binding(DispatchList, Path, ExtraDepth) of
+                        {Mod, ModOpts, PathTokens, Bindings1, AppRoot, StringPath} ->
+                            {Mod, ModOpts, PathTokens, Bindings ++ Bindings1, AppRoot, StringPath};
+                        Else ->
+                            Else
+                    end;
+                {Mod, ModOpts, PathTokens, Bindings1, AppRoot, StringPath} ->
+                    {Mod, ModOpts, PathTokens, Bindings ++ Bindings1, AppRoot, StringPath}
+            end
+    end.
+            
 
 %% @type matchterm() = {[pathterm()], matchmod(), matchopts()}.
 % The dispatch configuration is a list of these terms, and the
 
 %% @type dispfail() = {no_dispatch_match, pathtokens()}.
 
+
+try_binding_host([], [], _HostBindings, _HostnameParts) ->
+    no_host_match;
+try_binding_host([], HostDispatchList, HostBindings, _HostnameParts) ->
+    {HostDispatchList, HostBindings};
+try_binding_host([{_PathSchema, _Mod, _Props}|Rest], HostDispatchList, HostBindings, 
+        HostNameParts) ->
+    try_binding_host(Rest, HostDispatchList, HostBindings, HostNameParts);
+try_binding_host([{HostSchema, PathSchema, Mod, Props}|Rest], HostDispatchList, HostBindings, 
+        HostNameParts) ->
+    case bind_host(lists:reverse(HostSchema), HostNameParts, []) of
+        {ok, _Remainder, Bindings} ->
+            try_binding_host(Rest, [{PathSchema, Mod, Props}|HostDispatchList],
+                Bindings, HostNameParts);
+        fail ->
+            try_binding_host(Rest, HostDispatchList, HostBindings,
+                HostNameParts)
+    end.
+      
+bind_host([], [], Bindings) ->
+    {ok, [], Bindings};
+bind_host([?MATCH_ALL], HostRest, Bindings) when is_list(HostRest) ->
+    {ok, HostRest, Bindings};
+bind_host(_, [], _) ->
+    fail;
+bind_host([Token|Rest],[Match|HostRest],Bindings) when is_atom(Token) ->
+    bind_host(Rest, HostRest, [{Token, Match}|Bindings]);
+bind_host([Token|Rest], [Token|HostRest], Bindings) ->
+    bind_host(Rest, HostRest, Bindings);
+bind_host(_, _, _) ->
+    fail.
+    
 try_binding([], PathTokens, _) ->
     {no_dispatch_match, PathTokens};
+try_binding([{_HostSchema, _PathSchema, _Mod, _Props}|Rest], PathTokens, ExtraDepth) ->
+     try_binding(Rest, PathTokens, ExtraDepth);
 try_binding([{PathSchema, Mod, Props}|Rest], PathTokens, ExtraDepth) ->
     case bind_path(PathSchema, PathTokens, [], 0) of
         {ok, Remainder, Bindings, Depth} ->
 calculate_app_root(1) -> ".";
 calculate_app_root(N) when N > 1 ->
     string:join(lists:duplicate(N, ".."), [?SEPARATOR]).
+    
+split_hostname(HostName) ->
+    %% in case there is a port
+	{HostName1, _, _} = mochiweb_util:partition(HostName, ":"),
+	HostnameParts = lists:reverse([mochiweb_util:unquote(Part)
+	    || Part <- string:tokens(HostName1, ".")]),
+    HostnameParts.

File src/webmachine_mochiweb.erl

View file
 loop(MochiReq) ->
     Req = webmachine:new_request(mochiweb, MochiReq),
     {ok, DispatchList} = application:get_env(webmachine, dispatch_list),
-    case webmachine_dispatcher:dispatch(Req:path(), DispatchList) of
+    case webmachine_dispatcher:dispatch(host(MochiReq), Req:path(), DispatchList) of
         {no_dispatch_match, _UnmatchedPathTokens} ->
             {ok, ErrorHandler} = application:get_env(webmachine, error_handler),
 	    ErrorHTML = ErrorHandler:render_error(404, Req, {none, none, []}),
 get_option(Option, Options) ->
     {proplists:get_value(Option, Options), proplists:delete(Option, Options)}.
 
+
+host(MochiReq) ->
+	case MochiReq:get_header_value("Host") of
+        undefined ->
+            {ok, {Address, Port}} = inet:sockname(MochiReq:get(socket)),
+            inet_parse:ntoa(Address) ++ ":" ++ integer_to_list(Port);
+        Value -> Value
+    end.
+