%% 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]). %% 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. create_paste(Req, State) -> PasteID = new_paste_id(), {ok, [{<<"paste">>, Paste}], Req3} = cowboy_req:body_qs(Req), ok = file:write_file(full_path(PasteID), Paste), case cowboy_req:method(Req3) of {<<"POST">>, Req4} -> {{true, <<$/, PasteID/binary>>}, Req4, State}; {_, Req4} -> {true, Req4, State} end. 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(<<$/, _T/binary>>) -> false; valid_path(<<_Char, T/binary>>) -> valid_path(T). new_paste_id() -> Initial = random:uniform(62) - 1, new_paste_id(<>, 7). new_paste_id(Bin, 0) -> Chars = <<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890">>, << <<(binary_part(Chars, B, 1))/binary>> || <> <= Bin >>; new_paste_id(Bin, Rem) -> Next = random:uniform(62) - 1, new_paste_id(<>, Rem - 1). format_html(Paste, plain) -> Text = escape_html_chars(read_file(Paste)), <<"", "paste", "
", Text/binary, "
\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>> || <> <= Bin >>. escape_html_char($<) -> <<"<">>; escape_html_char($>) -> <<">">>; escape_html_char($&) -> <<"&">>; escape_html_char(C) -> <>.