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