|
@@ -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($<) -> <<"<">>;
|
|
|
+escape_html_char($>) -> <<">">>;
|
|
|
+escape_html_char($&) -> <<"&">>;
|
|
|
+escape_html_char(C) -> <<C>>.
|