toppage_handler.erl 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. %% Feel free to use, reuse and abuse the code in this file.
  2. %% @doc Pastebin handler.
  3. -module(toppage_handler).
  4. %% REST 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. %% Callback 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. {<<$/, 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. {ok, Cwd} = file:get_cwd(),
  65. filename:join([Cwd, "priv", Name]).
  66. file_exists(Name) ->
  67. case file:read_file_info(full_path(Name)) of
  68. {ok, _Info} -> true;
  69. {error, _Reason} -> false
  70. end.
  71. valid_path(<<>>) -> true;
  72. valid_path(<<$., _T/binary>>) -> false;
  73. valid_path(<<$/, _T/binary>>) -> false;
  74. valid_path(<<_Char, T/binary>>) -> valid_path(T).
  75. new_paste_id() ->
  76. Initial = random:uniform(62) - 1,
  77. new_paste_id(<<Initial>>, 7).
  78. new_paste_id(Bin, 0) ->
  79. Chars = <<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890">>,
  80. << <<(binary_part(Chars, B, 1))/binary>> || <<B>> <= Bin >>;
  81. new_paste_id(Bin, Rem) ->
  82. Next = random:uniform(62) - 1,
  83. new_paste_id(<<Bin/binary, Next>>, Rem - 1).
  84. format_html(Paste, plain) ->
  85. Text = escape_html_chars(read_file(Paste)),
  86. <<"<!DOCTYPE html><html>",
  87. "<head><title>paste</title></head>",
  88. "<body><pre><code>", Text/binary, "</code></pre></body></html>\n">>;
  89. format_html(Paste, Lang) ->
  90. highlight(full_path(Paste), Lang, "html").
  91. format_text(Paste, plain) ->
  92. read_file(Paste);
  93. format_text(Paste, Lang) ->
  94. highlight(full_path(Paste), Lang, "ansi").
  95. highlight(Path, Lang, Type) ->
  96. Path1 = binary_to_list(Path),
  97. Lang1 = binary_to_list(Lang),
  98. os:cmd(["highlight --syntax=", Lang1,
  99. " --doc-title=paste ",
  100. " --out-format=", Type,
  101. " --include-style ", Path1]).
  102. % Escape some HTML characters that might make a fuss
  103. escape_html_chars(Bin) ->
  104. << <<(escape_html_char(B))/binary>> || <<B>> <= Bin >>.
  105. escape_html_char($<) -> <<"&lt;">>;
  106. escape_html_char($>) -> <<"&gt;">>;
  107. escape_html_char($&) -> <<"&amp;">>;
  108. escape_html_char(C) -> <<C>>.