aboutsummaryrefslogtreecommitdiffstats
path: root/examples/rest_pastebin/src
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2013-02-07 18:34:49 +0100
committerLoïc Hoguin <[email protected]>2013-02-07 18:37:15 +0100
commitefbd9133261e1aabf473f2f6f5ab4cbb36062481 (patch)
tree1b2855534b20c59208edd82be61ae3aa738a0141 /examples/rest_pastebin/src
parentcb15243d8b91458f1c5e2a7e0c664f7b76f593ad (diff)
parentd7b83db92ea6b6a0022c7d19c252037197fc28c4 (diff)
downloadcowboy-efbd9133261e1aabf473f2f6f5ab4cbb36062481.tar.gz
cowboy-efbd9133261e1aabf473f2f6f5ab4cbb36062481.tar.bz2
cowboy-efbd9133261e1aabf473f2f6f5ab4cbb36062481.zip
Merge branch 'add_rest_example' of git://github.com/acammack/cowboy
Diffstat (limited to 'examples/rest_pastebin/src')
-rw-r--r--examples/rest_pastebin/src/rest_pastebin.app.src15
-rw-r--r--examples/rest_pastebin/src/rest_pastebin.erl14
-rw-r--r--examples/rest_pastebin/src/rest_pastebin_app.erl25
-rw-r--r--examples/rest_pastebin/src/rest_pastebin_sup.erl23
-rw-r--r--examples/rest_pastebin/src/toppage_handler.erl132
5 files changed, 209 insertions, 0 deletions
diff --git a/examples/rest_pastebin/src/rest_pastebin.app.src b/examples/rest_pastebin/src/rest_pastebin.app.src
new file mode 100644
index 0000000..7701ebe
--- /dev/null
+++ b/examples/rest_pastebin/src/rest_pastebin.app.src
@@ -0,0 +1,15 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+{application, rest_pastebin, [
+ {description, "Cowboy REST Pastebin example inspired by sprunge."},
+ {vsn, "1"},
+ {modules, []},
+ {registered, []},
+ {applications, [
+ kernel,
+ stdlib,
+ cowboy
+ ]},
+ {mod, {rest_pastebin_app, []}},
+ {env, []}
+]}.
diff --git a/examples/rest_pastebin/src/rest_pastebin.erl b/examples/rest_pastebin/src/rest_pastebin.erl
new file mode 100644
index 0000000..cf03a71
--- /dev/null
+++ b/examples/rest_pastebin/src/rest_pastebin.erl
@@ -0,0 +1,14 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+-module(rest_pastebin).
+
+%% API.
+-export([start/0]).
+
+%% API.
+
+start() ->
+ ok = application:start(crypto),
+ ok = application:start(ranch),
+ ok = application:start(cowboy),
+ ok = application:start(rest_pastebin).
diff --git a/examples/rest_pastebin/src/rest_pastebin_app.erl b/examples/rest_pastebin/src/rest_pastebin_app.erl
new file mode 100644
index 0000000..10ba4c5
--- /dev/null
+++ b/examples/rest_pastebin/src/rest_pastebin_app.erl
@@ -0,0 +1,25 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @private
+-module(rest_pastebin_app).
+-behaviour(application).
+
+%% API.
+-export([start/2]).
+-export([stop/1]).
+
+%% API.
+
+start(_Type, _Args) ->
+ Dispatch = cowboy_router:compile([
+ {'_', [
+ {"/[:paste_id]", toppage_handler, []}
+ ]}
+ ]),
+ {ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [
+ {env, [{dispatch, Dispatch}]}
+ ]),
+ rest_pastebin_sup:start_link().
+
+stop(_State) ->
+ ok.
diff --git a/examples/rest_pastebin/src/rest_pastebin_sup.erl b/examples/rest_pastebin/src/rest_pastebin_sup.erl
new file mode 100644
index 0000000..b5f08d7
--- /dev/null
+++ b/examples/rest_pastebin/src/rest_pastebin_sup.erl
@@ -0,0 +1,23 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @private
+-module(rest_pastebin_sup).
+-behaviour(supervisor).
+
+%% API.
+-export([start_link/0]).
+
+%% supervisor.
+-export([init/1]).
+
+%% API.
+
+-spec start_link() -> {ok, pid()}.
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%% supervisor.
+
+init([]) ->
+ Procs = [],
+ {ok, {{one_for_one, 10, 10}, Procs}}.
diff --git a/examples/rest_pastebin/src/toppage_handler.erl b/examples/rest_pastebin/src/toppage_handler.erl
new file mode 100644
index 0000000..758e11d
--- /dev/null
+++ b/examples/rest_pastebin/src/toppage_handler.erl
@@ -0,0 +1,132 @@
+%% Feel free to use, reuse and abuse the code in this file.
+
+%% @doc Pastebin handler.
+-module(toppage_handler).
+
+%% REST Callbacks
+-export([init/3]).
+-export([allowed_methods/2]).
+-export([content_types_provided/2]).
+-export([content_types_accepted/2]).
+-export([resource_exists/2]).
+-export([post_is_create/2]).
+-export([create_path/2]).
+
+%% Callback Callbacks
+-export([create_paste/2]).
+-export([paste_html/2]).
+-export([paste_text/2]).
+
+init(_Transport, _Req, []) ->
+ % For the random number generator:
+ {X, Y, Z} = now(),
+ random:seed(X, Y, Z),
+ {upgrade, protocol, cowboy_rest}.
+
+allowed_methods(Req, State) ->
+ {[<<"GET">>, <<"POST">>], Req, State}.
+
+content_types_provided(Req, State) ->
+ {[
+ {{<<"text">>, <<"plain">>, []}, paste_text},
+ {{<<"text">>, <<"html">>, []}, paste_html}
+ ], Req, State}.
+
+content_types_accepted(Req, State) ->
+ {[{{<<"application">>, <<"x-www-form-urlencoded">>, []}, create_paste}],
+ Req, State}.
+
+resource_exists(Req, _State) ->
+ case cowboy_req:binding(paste_id, Req) of
+ {undefined, Req2} ->
+ {true, Req2, index};
+ {PasteID, Req2} ->
+ case valid_path(PasteID) and file_exists(PasteID) of
+ true -> {true, Req2, PasteID};
+ false -> {false, Req2, PasteID}
+ end
+ end.
+
+post_is_create(Req, State) ->
+ {true, Req, State}.
+
+create_path(Req, State) ->
+ {<<$/, (new_paste_id())/binary>>, Req, State}.
+
+create_paste(Req, State) ->
+ {<<$/, PasteID/binary>>, Req2} = cowboy_req:meta(put_path, Req),
+ {ok, [{<<"paste">>, Paste}], Req3} = cowboy_req:body_qs(Req2),
+ ok = file:write_file(full_path(PasteID), Paste),
+ {true, Req3, State}.
+
+paste_html(Req, index) ->
+ {read_file("index.html"), Req, index};
+paste_html(Req, Paste) ->
+ {Style, Req2} = cowboy_req:qs_val(<<"lang">>, Req, plain),
+ {format_html(Paste, Style), Req2, Paste}.
+
+paste_text(Req, index) ->
+ {read_file("index.txt"), Req, index};
+paste_text(Req, Paste) ->
+ {Style, Req2} = cowboy_req:qs_val(<<"lang">>, Req, plain),
+ {format_text(Paste, Style), Req2, Paste}.
+
+% Private
+
+read_file(Name) ->
+ {ok, Binary} = file:read_file(full_path(Name)),
+ Binary.
+
+full_path(Name) ->
+ {ok, Cwd} = file:get_cwd(),
+ filename:join([Cwd, "priv", Name]).
+
+file_exists(Name) ->
+ case file:read_file_info(full_path(Name)) of
+ {ok, _Info} -> true;
+ {error, _Reason} -> false
+ end.
+
+valid_path(<<>>) -> true;
+valid_path(<<$., _T/binary>>) -> false;
+valid_path(<<_Char, T/binary>>) -> valid_path(T).
+
+new_paste_id() ->
+ Initial = random:uniform(62) - 1,
+ new_paste_id(<<Initial>>, 7).
+new_paste_id(Bin, 0) ->
+ Chars = <<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890">>,
+ << <<(binary_part(Chars, B, 1))/binary>> || <<B>> <= Bin >>;
+new_paste_id(Bin, Rem) ->
+ Next = random:uniform(62) - 1,
+ new_paste_id(<<Bin/binary, Next>>, Rem - 1).
+
+format_html(Paste, plain) ->
+ Text = escape_html_chars(read_file(Paste)),
+ <<"<!DOCTYPE html><html>",
+ "<head><title>paste</title></head>",
+ "<body><pre><code>", Text/binary, "</code></pre></body></html>\n">>;
+format_html(Paste, Lang) ->
+ highlight(full_path(Paste), Lang, "html").
+
+format_text(Paste, plain) ->
+ read_file(Paste);
+format_text(Paste, Lang) ->
+ highlight(full_path(Paste), Lang, "ansi").
+
+highlight(Path, Lang, Type) ->
+ Path1 = binary_to_list(Path),
+ Lang1 = binary_to_list(Lang),
+ os:cmd(["highlight --syntax=", Lang1,
+ " --doc-title=paste ",
+ " --out-format=", Type,
+ " --include-style ", Path1]).
+
+% Escape some HTML characters that might make a fuss
+escape_html_chars(Bin) ->
+ << <<(escape_html_char(B))/binary>> || <<B>> <= Bin >>.
+
+escape_html_char($<) -> <<"&lt;">>;
+escape_html_char($>) -> <<"&gt;">>;
+escape_html_char($&) -> <<"&amp;">>;
+escape_html_char(C) -> <<C>>.