toppage_handler.erl 3.4 KB

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