n2o_static.erl 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. -module(n2o_static).
  2. -description('N2O Static Bridge to files in LING image, MAD bundle or OS').
  3. -author('Maxim Sokhatsky').
  4. -compile([export_all, nowarn_export_all]).
  5. -include_lib("kernel/include/file.hrl").
  6. init(_, _, _) -> {upgrade, protocol, cowboy_rest}.
  7. rest_init(Req, {dir, Path, Extra}) when is_binary(Path) -> rest_init(Req, {dir, binary_to_list(Path), Extra});
  8. rest_init(Req, {dir, Path, Extra}) ->
  9. {PathInfo, Req2} = cowboy_req:path_info(Req),
  10. Info = {ok, #file_info{type=regular,size=0}},
  11. FileName = filename:join([Path|PathInfo]),
  12. wf:info(?MODULE,"Rest Init: ~p~n\r",[FileName]),
  13. {ok, Req2, {FileName, Info, Extra}}.
  14. malformed_request(Req, State) -> {State =:= error, Req, State}.
  15. forbidden(Req, State={_, {ok, #file_info{type=directory}}, _}) -> {true, Req, State};
  16. forbidden(Req, State={_, {error, eacces}, _}) -> {true, Req, State};
  17. forbidden(Req, State={_, {ok, #file_info{access=Access}}, _}) when Access =:= write; Access =:= none -> {true, Req, State};
  18. forbidden(Req, State) -> {false, Req, State}.
  19. content_types_provided(Req, State={Path, _, Extra}) ->
  20. wf:info(?MODULE,"Content Type Provided: ~p~n\r",[Path]),
  21. case lists:keyfind(mimetypes, 1, Extra) of
  22. false -> {[{cow_mimetypes:web(Path), get_file}], Req, State};
  23. {mimetypes, Module, Function} -> {[{Module:Function(Path), get_file}], Req, State};
  24. {mimetypes, Type} -> {[{Type, get_file}], Req, State}
  25. end.
  26. resource_exists(Req, State={_, {ok, #file_info{type=regular}}, _}) -> {true, Req, State};
  27. resource_exists(Req, State) -> {false, Req, State}.
  28. generate_etag(Req, State={Path, {ok, #file_info{size=Size, mtime=Mtime}}, Extra}) ->
  29. case lists:keyfind(etag, 1, Extra) of
  30. false -> {generate_default_etag(Size, Mtime), Req, State};
  31. {etag, Module, Function} -> {Module:Function(Path, Size, Mtime), Req, State};
  32. {etag, false} -> {undefined, Req, State}
  33. end.
  34. generate_default_etag(Size, Mtime) ->
  35. {strong, list_to_binary(integer_to_list(
  36. erlang:phash2({Size, Mtime}, 16#ffffffff)))}.
  37. last_modified(Req, State={_, {ok, #file_info{mtime=Modified}}, _}) -> {Modified, Req, State}.
  38. get_file(Req, State={Path, {ok, #file_info{size=_Size}}, _}) ->
  39. StringPath = wf:to_list(unicode:characters_to_binary(Path,utf8,utf8)),
  40. [_Type,Name|RestPath]=SplitPath = filename:split(StringPath),
  41. wf:info(?MODULE,"Split Path: ~p~n\r",[SplitPath]),
  42. %wf:info(?MODULE,"Code Path: ~p~n\r",[filename:join([code:lib_dir(Name)|RestPath])]),
  43. FileName = filename:absname(StringPath),
  44. wf:info(?MODULE,"Abs Name: ~p~n\r",[FileName]),
  45. Raw = case file:read_file(FileName) of
  46. {ok,Bin} -> Bin;
  47. {error,_} ->
  48. case mad_repl:load_file(StringPath) of
  49. {ok,ETSFile} -> ETSFile;
  50. {error,_} ->
  51. case file:read_file(filename:join([code:lib_dir(Name)|RestPath])) of
  52. {ok,ReleaseFile} -> ReleaseFile;
  53. {error,_} -> <<>> end end end,
  54. wf:info(?MODULE,"Cowboy Requested Static File: ~p~n\r ~p~n\r",[Raw,filename:absname(StringPath)]),
  55. Sendfile = fun (Socket, Transport) ->
  56. case Transport:send(Socket, Raw) of
  57. {ok, _} -> ok;
  58. {error, closed} -> ok;
  59. {error, etimedout} -> ok;
  60. _ -> ok end end,
  61. {{stream, size(Raw), Sendfile}, Req, State}.