PageRenderTime 28ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/middleware/ewgi_stream_file/ewgi_stream_file.erl

http://github.com/skarab/ewgi
Erlang | 108 lines | 83 code | 6 blank | 19 comment | 0 complexity | 1ea7a54967416e94f8690e0795425c38 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. %% @author Hunter Morris <hunter.morris@smarkets.com>
  2. %% @author Filippo Pacini <filippo.pacini@gmail.com>
  3. %% @doc ewgi stream file application
  4. -module(ewgi_stream_file).
  5. -export([run/2]).
  6. %%
  7. %% Files opened in raw mode cannot be read in processes distinct
  8. %% from the one that opened the file! So we need to make sure
  9. %% that both the open and read operations are done in the same
  10. %% process.
  11. %%
  12. %% Since a webserver might need to spawn a new process to handle
  13. %% our stream (Yaws and the old Inets implementation did)
  14. %% we'll get around that by delaying the open operation to the
  15. %% head of the stream.
  16. %%
  17. run(Ctx, [File]) ->
  18. case file:read_file_info(File) of
  19. {ok, _} ->
  20. Mime = guess_mime(File),
  21. LoadIoDevice = {open, File, [raw, binary]},
  22. %% Set ChunkSize to an optimal value
  23. ChunkSize = 1024,
  24. Stream = iodevice_stream(LoadIoDevice, ChunkSize),
  25. ewgi_api:response_status(
  26. {200, "OK"},
  27. ewgi_api:response_headers(
  28. [{"Content-type", Mime}],
  29. ewgi_api:response_message_body(Stream, Ctx)
  30. )
  31. );
  32. _ ->
  33. %% Respond with 404...
  34. ewgi_api:response_message_body(
  35. "404 NOT FOUND",
  36. ewgi_api:response_status({404, "NOT FOUND"}, Ctx)
  37. )
  38. end.
  39. iodevice_stream({open, File, Modes}, ChunkSize) ->
  40. fun() ->
  41. case file:open(File, Modes) of
  42. {ok, IoDevice} ->
  43. {<<>>, iodevice_stream(IoDevice, ChunkSize)};
  44. _ ->
  45. {}
  46. end
  47. end;
  48. iodevice_stream(IoDevice, ChunkSize) ->
  49. fun() ->
  50. case file:read(IoDevice, ChunkSize) of
  51. eof ->
  52. file:close(IoDevice),
  53. {};
  54. {ok, Data} ->
  55. {Data, iodevice_stream(IoDevice, ChunkSize)};
  56. {error, Reason} ->
  57. io:format("got error: ~p~n", [Reason]),
  58. {}
  59. end
  60. end.
  61. %% @spec guess_mime(string()) -> string()
  62. %% @doc Guess the mime type of a file by the extension of its filename.
  63. guess_mime(File) ->
  64. %% Taken from webmachine.
  65. case filename:extension(File) of
  66. ".html" ->
  67. "text/html";
  68. ".xhtml" ->
  69. "application/xhtml+xml";
  70. ".xml" ->
  71. "application/xml";
  72. ".css" ->
  73. "text/css";
  74. ".js" ->
  75. "application/x-javascript";
  76. ".jpg" ->
  77. "image/jpeg";
  78. ".jpeg" ->
  79. "image/jpeg";
  80. ".gif" ->
  81. "image/gif";
  82. ".png" ->
  83. "image/png";
  84. ".ico" ->
  85. "image/x-icon";
  86. ".swf" ->
  87. "application/x-shockwave-flash";
  88. ".zip" ->
  89. "application/zip";
  90. ".bz2" ->
  91. "application/x-bzip2";
  92. ".gz" ->
  93. "application/x-gzip";
  94. ".tar" ->
  95. "application/x-tar";
  96. ".tgz" ->
  97. "application/x-gzip";
  98. ".htc" ->
  99. "text/x-component";
  100. _ ->
  101. "text/plain"
  102. end.