toppage_handler.erl 3.4 KB

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