toppage_handler.erl 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. %% Feel free to use, reuse and abuse the code in this file.
  2. %% @doc Pastebin handler.
  3. -module(toppage_handler).
  4. %% Standard callbacks.
  5. -export([init/3]).
  6. -export([allowed_methods/2]).
  7. -export([content_types_provided/2]).
  8. -export([content_types_accepted/2]).
  9. -export([resource_exists/2]).
  10. %% Custom callbacks.
  11. -export([create_paste/2]).
  12. -export([paste_html/2]).
  13. -export([paste_text/2]).
  14. init(_Transport, _Req, []) ->
  15. % For the random number generator:
  16. {X, Y, Z} = now(),
  17. random:seed(X, Y, Z),
  18. {upgrade, protocol, cowboy_rest}.
  19. allowed_methods(Req, State) ->
  20. {[<<"GET">>, <<"POST">>], Req, State}.
  21. content_types_provided(Req, State) ->
  22. {[
  23. {{<<"text">>, <<"plain">>, []}, paste_text},
  24. {{<<"text">>, <<"html">>, []}, paste_html}
  25. ], Req, State}.
  26. content_types_accepted(Req, State) ->
  27. {[{{<<"application">>, <<"x-www-form-urlencoded">>, []}, create_paste}],
  28. Req, State}.
  29. resource_exists(Req, _State) ->
  30. case cowboy_req:binding(paste_id, Req) of
  31. {undefined, Req2} ->
  32. {true, Req2, index};
  33. {PasteID, Req2} ->
  34. case valid_path(PasteID) and file_exists(PasteID) of
  35. true -> {true, Req2, PasteID};
  36. false -> {false, Req2, PasteID}
  37. end
  38. end.
  39. create_paste(Req, State) ->
  40. PasteID = new_paste_id(),
  41. {ok, [{<<"paste">>, Paste}], Req3} = cowboy_req:body_qs(Req),
  42. ok = file:write_file(full_path(PasteID), Paste),
  43. case cowboy_req:method(Req3) of
  44. {<<"POST">>, Req4} ->
  45. {{true, <<$/, PasteID/binary>>}, Req4, State};
  46. {_, Req4} ->
  47. {true, Req4, State}
  48. end.
  49. paste_html(Req, index) ->
  50. {read_file("index.html"), Req, index};
  51. paste_html(Req, Paste) ->
  52. {Style, Req2} = cowboy_req:qs_val(<<"lang">>, Req, plain),
  53. {format_html(Paste, Style), Req2, Paste}.
  54. paste_text(Req, index) ->
  55. {read_file("index.txt"), Req, index};
  56. paste_text(Req, Paste) ->
  57. {Style, Req2} = cowboy_req:qs_val(<<"lang">>, Req, plain),
  58. {format_text(Paste, Style), Req2, Paste}.
  59. % Private
  60. read_file(Name) ->
  61. {ok, Binary} = file:read_file(full_path(Name)),
  62. Binary.
  63. full_path(Name) ->
  64. filename:join([code:priv_dir(rest_pastebin), Name]).
  65. file_exists(Name) ->
  66. case file:read_file_info(full_path(Name)) of
  67. {ok, _Info} -> true;
  68. {error, _Reason} -> false
  69. end.
  70. valid_path(<<>>) -> true;
  71. valid_path(<<$., _T/binary>>) -> false;
  72. valid_path(<<$/, _T/binary>>) -> false;
  73. valid_path(<<_Char, T/binary>>) -> valid_path(T).
  74. new_paste_id() ->
  75. Initial = random:uniform(62) - 1,
  76. new_paste_id(<<Initial>>, 7).
  77. new_paste_id(Bin, 0) ->
  78. Chars = <<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890">>,
  79. << <<(binary_part(Chars, B, 1))/binary>> || <<B>> <= Bin >>;
  80. new_paste_id(Bin, Rem) ->
  81. Next = random:uniform(62) - 1,
  82. new_paste_id(<<Bin/binary, Next>>, Rem - 1).
  83. format_html(Paste, plain) ->
  84. Text = escape_html_chars(read_file(Paste)),
  85. <<"<!DOCTYPE html><html>",
  86. "<head><title>paste</title></head>",
  87. "<body><pre><code>", Text/binary, "</code></pre></body></html>\n">>;
  88. format_html(Paste, Lang) ->
  89. highlight(full_path(Paste), Lang, "html").
  90. format_text(Paste, plain) ->
  91. read_file(Paste);
  92. format_text(Paste, Lang) ->
  93. highlight(full_path(Paste), Lang, "ansi").
  94. highlight(Path, Lang, Type) ->
  95. Path1 = binary_to_list(Path),
  96. Lang1 = binary_to_list(Lang),
  97. os:cmd(["highlight --syntax=", Lang1,
  98. " --doc-title=paste ",
  99. " --out-format=", Type,
  100. " --include-style ", Path1]).
  101. % Escape some HTML characters that might make a fuss
  102. escape_html_chars(Bin) ->
  103. << <<(escape_html_char(B))/binary>> || <<B>> <= Bin >>.
  104. escape_html_char($<) -> <<"&lt;">>;
  105. escape_html_char($>) -> <<"&gt;">>;
  106. escape_html_char($&) -> <<"&amp;">>;
  107. escape_html_char(C) -> <<C>>.