Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

add support for local HTTP routing.

  • Loading branch information...
commit 6f5f358e041a7f6ab888b02a242ae634065b5ee3 1 parent ad82cfc
Benoit Chesneau authored December 06, 2011
31  README.md
Source Rendered
@@ -27,6 +27,8 @@ connection or tell to the proxy to close the connection.
27 27
 
28 28
 * `stop` -> close the connection
29 29
 * `{stop, Reply}` -> send Reply to the client and close the connection
  30
+* `{http, Dispatch}` -> Use the HTTP protocol of cowboy with the
  31
+  dispatch rules list Dispatch.
30 32
 * `{remote, Remote}` -> return the address of the remote connection to
31 33
   proxy. Remote can be one of the following:
32 34
     - `{ip, port}`
@@ -56,6 +58,35 @@ Here is a simple example of function proxying the port 8080 to google.com:
56 58
             cowboy_revproxy, [{proxy, {?MODULE, proxy}}]).
57 59
 
58 60
 
  61
+This simple proxy function allows you to handle an HTTP request locally
  62
+
  63
+
  64
+    proxy(Data) ->
  65
+        Dispatch = [
  66
+            %% {Host, list({Path, Handler, Opts})}
  67
+            {'_', [{'_', my_handler, []}]}
  68
+        ],
  69
+        {http, Dispatch}.
  70
+
  71
+
  72
+A simple "Hello World" HTTP handler:
  73
+
  74
+    -module(my_handler).
  75
+    -behaviour(cowboy_http_handler).
  76
+    -export([init/3, handle/2, terminate/2]).
  77
+
  78
+    init({tcp, http}, Req, Opts) ->
  79
+        {ok, Req, undefined_state}.
  80
+
  81
+    handle(Req, State) ->
  82
+        {ok, Req2} = cowboy_http_req:reply(200, [], <<"Hello World!">>, Req),
  83
+        {ok, Req2, State}.
  84
+
  85
+    terminate(Req, State) ->
  86
+        ok.
  87
+
  88
+
  89
+
59 90
 To test it do, in the source folder:
60 91
 
61 92
     $ rebar get-deps compile
2  src/cowboy_revproxy.app.src
@@ -7,7 +7,7 @@
7 7
 
8 8
 {application, cowboy_revproxy,
9 9
  [{description, "Cownboy reverse proxy handler"},
10  
-  {vsn, "0.1.0"},
  10
+  {vsn, "0.2.0"},
11 11
   {modules, []},
12 12
   {registered, []},  
13 13
   {applications, [kernel, stdlib]}
51  src/cowboy_revproxy.erl
@@ -14,7 +14,8 @@
14 14
 
15 15
 -include_lib("eunit/include/eunit.hrl").
16 16
 
17  
--record(state, {
  17
+%% proxy state
  18
+-record(stproxy, {
18 19
         listener :: pid(),
19 20
         socket :: inet:socket(),
20 21
         transport :: module(),
@@ -26,6 +27,23 @@
26 27
         remote_transport :: module()
27 28
     }).
28 29
 
  30
+%% HTTP protocol state
  31
+-record(state, {
  32
+	listener :: pid(),
  33
+	socket :: inet:socket(),
  34
+	transport :: module(),
  35
+	dispatch :: cowboy_dispatcher:dispatch_rules(),
  36
+	handler :: {module(), any()},
  37
+	req_empty_lines = 0 :: integer(),
  38
+	max_empty_lines = 5:: integer(),
  39
+	max_line_length = 4096:: integer(),
  40
+	timeout = 5000 :: timeout(),
  41
+	buffer = <<>> :: binary(),
  42
+	hibernate = false :: boolean(),
  43
+	loop_timeout = infinity :: timeout(),
  44
+	loop_timeout_ref :: undefined | reference()
  45
+}).
  46
+
29 47
 %% @doc Start a revproxy process
30 48
 -spec start_link(pid(), inet:socket(), module(), any()) -> {ok, pid()}.
31 49
 start_link(ListenerPid, Socket, Transport, Opts) ->
@@ -38,11 +56,11 @@ init(ListenerPid, Socket, Transport, Opts) ->
38 56
     Handler = proplists:get_value(proxy, Opts),
39 57
     Timeout = proplists:get_value(timeout, Opts, 5000),
40 58
     receive shoot -> ok end,
41  
-    wait_request(#state{listener=ListenerPid, socket=Socket,
  59
+    wait_request(#stproxy{listener=ListenerPid, socket=Socket,
42 60
             transport=Transport, handler=Handler, timeout=Timeout}).
43 61
 
44  
--spec wait_request(#state{}) -> ok | none().
45  
-wait_request(State=#state{socket=Socket, transport=Transport, timeout=T,
  62
+-spec wait_request(#stproxy{}) -> ok | none().
  63
+wait_request(State=#stproxy{socket=Socket, transport=Transport, timeout=T,
46 64
         handler=Handler, buffer=Buffer}) ->
47 65
 
48 66
     case Transport:recv(Socket, 0, T) of
@@ -54,32 +72,37 @@ wait_request(State=#state{socket=Socket, transport=Transport, timeout=T,
54 72
                 {stop, Reply} ->
55 73
                 Transport:send(Socket, Reply),
56 74
                     terminate(State);
  75
+                {http, Dispatch} ->
  76
+                    #stproxy{listener=Listener} = State,
  77
+                    cowboy_http_protocol:parse_request(#state{listener=Listener,
  78
+                            socket=Socket, transport=Transport,
  79
+                            dispatch=Dispatch, buffer = Buffer1});
57 80
                 {remote, Remote} ->
58  
-                    start_proxy_loop(State#state{buffer=Buffer1, remote=Remote});
  81
+                    start_proxy_loop(State#stproxy{buffer=Buffer1, remote=Remote});
59 82
                 [{remote, Remote}, {data, Data}] ->
60  
-                    start_proxy_loop(State#state{buffer=Data, remote=Remote});
  83
+                    start_proxy_loop(State#stproxy{buffer=Data, remote=Remote});
61 84
                 [{remote, Remote}, {data, Data}, {reply, Reply}] ->
62 85
                     Transport:send(Socket, Reply),
63  
-                    start_proxy_loop(State#state{buffer=Data, remote=Remote});
  86
+                    start_proxy_loop(State#stproxy{buffer=Data, remote=Remote});
64 87
                 _ ->
65  
-                    wait_request(State#state{buffer=Buffer1})
  88
+                    wait_request(State#stproxy{buffer=Buffer1})
66 89
             end;
67 90
         {error, _Reason} ->
68 91
             terminate(State)
69 92
     end.
70 93
 
71 94
 
72  
-start_proxy_loop(State=#state{remote=Remote, buffer=Buffer}) ->
  95
+start_proxy_loop(State=#stproxy{remote=Remote, buffer=Buffer}) ->
73 96
     case remote_connect(Remote) of
74 97
         {Transport, {ok, Socket}} ->
75 98
             Transport:send(Socket, Buffer),
76  
-            proxy_loop(State#state{remote_socket=Socket,
  99
+            proxy_loop(State#stproxy{remote_socket=Socket,
77 100
                     remote_transport=Transport, buffer= <<>> });
78 101
         {error, _Error} ->
79 102
             terminate(State)
80 103
     end.
81 104
 
82  
-proxy_loop(State=#state{socket=From, transport=TFrom,
  105
+proxy_loop(State=#stproxy{socket=From, transport=TFrom,
83 106
         remote_socket=To, remote_transport=TTo}) ->
84 107
     TFrom:setopts(From, [{packet, 0}, {active, once}]),
85 108
     TTo:setopts(To, [{packet, 0}, {active, once}]),
@@ -105,8 +128,8 @@ call_handler({M, F}, Data) ->
105 128
 call_handler({M, F, A}, Data) ->
106 129
     erlang:apply(M, F, [Data | A]).
107 130
 
108  
--spec terminate(#state{}) -> ok.
109  
-terminate(#state{socket=Socket, transport=Transport}) ->
  131
+-spec terminate(#stproxy{}) -> ok.
  132
+terminate(#stproxy{socket=Socket, transport=Transport}) ->
110 133
     Transport:close(Socket),
111 134
     ok.
112 135
 
@@ -119,7 +142,7 @@ remote_connect({ssl, Ip, Port, Opts}) ->
119 142
     {cowboy_ssl_transport, ssl:connect(Ip, Port, [binary, {packet, 0},
120 143
                 {delay_send, true} | Opts1])}.
121 144
 
122  
-remote_terminate(#state{remote_socket=Socket,
  145
+remote_terminate(#stproxy{remote_socket=Socket,
123 146
         remote_transport=Transport}) ->
124 147
     Transport:close(Socket),
125 148
     ok.

0 notes on commit 6f5f358

Please sign in to comment.
Something went wrong with that request. Please try again.