Skip to content

Instantly share code, notes, and snippets.

@SteveSongMIT
Created March 19, 2012 18:59
Show Gist options
  • Save SteveSongMIT/2123991 to your computer and use it in GitHub Desktop.
Save SteveSongMIT/2123991 to your computer and use it in GitHub Desktop.
Simple Cowboy web server
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html> <head>
<title>Cowboy test</title>
</head>
<body>
<h1>Woot!</h1>
<hr>
</body>
</html>
%%-*- mode: erlang -*-
{sub_dirs, [
"rel"
]}.
{erl_opts, [debug_info]}. %, fail_on_warning]}.
{require_otp_vsn, "R15"}.
{deps_dir, ["deps"]}.
{deps,
[
{cowboy, ".*", {git, "https://github.com/extend/cowboy.git", {branch, "master"}}}
]
}.
{sys, [
{lib_dirs, ["../.."]},
{erts, [{mod_cond, derived}, {app_file, strip}]},
{app_file, strip},
{rel, "simple_server", "1",
[
kernel,
stdlib,
sasl,
simple_server
]},
{rel, "start_clean", "",
[
kernel,
stdlib
]},
{boot_rel, "simple_server"},
{profile, embedded},
{incl_cond, exclude},
{excl_archive_filters, [".*"]}, %% Do not archive built libs
{excl_sys_filters, ["^bin/.*", "^erts.*/bin/(dialyzer|typer)",
"^erts.*/(doc|info|include|lib|man|src)"]},
{excl_app_filters, ["\.gitignore"]},
{app, sasl, [{incl_cond, include}]},
{app, stdlib, [{incl_cond, include}]},
{app, kernel, [{incl_cond, include}]},
{app, simple_server, [{incl_cond, include}]}
]}.
{target_dir, "simple_server"}.
{overlay, [
{mkdir, "log/sasl"},
{copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"},
{copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "files/simple_server", "bin/simple_server"},
{copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"},
{copy, "files/simple_server.cmd", "bin/simple_server.cmd"},
{copy, "files/start_erl.cmd", "bin/start_erl.cmd"},
{copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"}
]}.
-module(simple_server).
-export([start/0, stop/0]).
ensure_started(App) ->
case application:start(App) of
ok ->
ok;
{error, {already_started, App}} ->
ok
end.
start() ->
ensure_started(crypto),
ensure_started(sasl),
ensure_started(cowboy),
application:start(simple_server).
stop() ->
application:stop(simple_server).
mkdir simple_server
cd simple_server
cp ../../rebar/rebar .
mkdir -p priv/html
./rebar create-app appid=simple_server
mkdir rel
cd rel
../rebar create-node nodeid=simple_server
-module(simple_server_http).
-behaviour(gen_server).
-define(SERVER, ?MODULE).
-export([start_link/0]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
-record(state, {}).
%% ------------------------------------------------------------------
%% API Function Definitions
%% ------------------------------------------------------------------
start_link() ->
gen_server:start_link({local, ?SERVER}, ?MODULE, [], []).
%% ------------------------------------------------------------------
%% gen_server Function Definitions
%% ------------------------------------------------------------------
dispatch_rules() ->
%% {Host, list({Path, Handler, Opts})}
[{'_', [
{[], simple_server_http_static, [<<"html">>,<<"index.html">>]}
, {'_', simple_server_http_catchall, []}
]}].
confval(Key, Default) ->
case application:get_env(Key) of
undefined -> Default;
Val -> Val
end.
init([]) ->
Port = confval(port, 80),
Ip = confval(ip, "127.0.0.1"),
NumAcceptors = confval(num_acceptors, 16),
IpStr = case is_list(Ip) of true -> Ip; false -> inet_parse:ntoa(Ip) end,
error_logger:info_msg("simple_server listening on http://~s:~B/~n", [IpStr,Port]),
%%
%% Name, NbAcceptors, Transport, TransOpts, Protocol, ProtoOpts
cowboy:start_listener(http, NumAcceptors,
cowboy_tcp_transport, [{port, Port}],
cowboy_http_protocol, [{dispatch, dispatch_rules()}]
),
{ok, #state{}}.
handle_call(_Request, _From, State) ->
{noreply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% ------------------------------------------------------------------
%% Internal Function Definitions
%% ------------------------------------------------------------------
-module(simple_server_http_catchall).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({tcp, http}, Req, _Opts) ->
{ok, Req, undefined_state}.
handle(Req, State) ->
Body = <<"<h1>404</h1>">>,
{ok, Req2} = cowboy_http_req:reply(404, [], Body, Req),
{ok, Req2, State}.
terminate(_Req, _State) ->
ok.
%%
%% show details on the VM, releases, apps, etc.
%%
-module(simple_server_http_static).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
-export([html/1, css/1, js/1]).
-compile(export_all).
init({tcp, http}, Req, []) ->
{ok, Req, undefined_state};
init({tcp, http}, Req, OnlyFile) ->
{ok, Req, OnlyFile}.
handle(Req, undefined_state = State) ->
{[_|Path], Req2} = cowboy_http_req:path(Req), % strip <<"static">>
send(Req2, Path, State);
handle(Req, OnlyFile = State) ->
send(Req, OnlyFile, State).
send(Req, PathBins, State) ->
Path = [ binary_to_list(P) || P <- PathBins ],
case file(filename:join(Path)) of
{ok, Body} ->
Headers = [{<<"Content-Type">>, <<"text/html">>}],
{ok, Req2} = cowboy_http_req:reply(200, Headers, Body, Req),
{ok, Req2, State};
_ ->
{ok, Req2} = cowboy_http_req:reply(404, [], <<"404'd">>, Req),
{ok, Req2, State}
end.
terminate(_Req, _State) ->
ok.
html(Name) ->
type("html", Name).
css(Name) ->
type("css", Name).
js(Name) ->
type("js", Name).
type(Type, Name) ->
file(filename:join([Type, Name ++ Type])).
file(Path) ->
Priv = priv(),
file:read_file(filename:join(Priv, Path)).
priv() ->
case code:priv_dir(simple_server) of
{error,_} -> "priv";
Priv -> Priv
end.
init([]) ->
Http = ?CHILD(simple_server_http, worker),
Specs = [
Http
],
{ok, { {one_for_one, 5, 10}, Specs} }.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment