/deps/webmachine/demo/src/demo_fs_resource.erl

https://code.google.com/p/zotonic/ · Erlang · 157 lines · 133 code · 19 blank · 5 comment · 0 complexity · ca4eba93dec0d8b24fe74653885b1621 MD5 · raw file

  1. %% @author Bryan Fink <bryan@basho.com>
  2. %% @author Andy Gross <andy@basho.com>
  3. %% @author Justin Sheehy <justin@basho.com>
  4. %% @copyright 2008-2009 Basho Technologies, Inc.
  5. -module(demo_fs_resource).
  6. -export([init/1]).
  7. -export([allowed_methods/2,
  8. resource_exists/2,
  9. last_modified/2,
  10. content_types_provided/2,
  11. content_types_accepted/2,
  12. delete_resource/2,
  13. post_is_create/2,
  14. create_path/2,
  15. provide_content/2,
  16. accept_content/2,
  17. generate_etag/2]).
  18. -record(context, {root,response_body=undefined,metadata=[]}).
  19. -include_lib("kernel/include/file.hrl").
  20. -include_lib("webmachine/include/webmachine.hrl").
  21. init(ConfigProps) ->
  22. {root, Root} = proplists:lookup(root, ConfigProps),
  23. {ok, #context{root=Root}}.
  24. allowed_methods(ReqData, Context) ->
  25. {['HEAD', 'GET', 'PUT', 'DELETE', 'POST'], ReqData, Context}.
  26. file_path(Context, Name) ->
  27. RelName = case hd(Name) of
  28. "/" -> tl(Name);
  29. _ -> Name
  30. end,
  31. filename:join([Context#context.root, RelName]).
  32. file_exists(Context, Name) ->
  33. NamePath = file_path(Context, Name),
  34. case filelib:is_regular(NamePath) of
  35. true ->
  36. {true, NamePath};
  37. false ->
  38. false
  39. end.
  40. resource_exists(ReqData, Context) ->
  41. Path = wrq:disp_path(ReqData),
  42. case file_exists(Context, Path) of
  43. {true, _} ->
  44. {true, ReqData, Context};
  45. _ ->
  46. case Path of
  47. "p" -> {true, ReqData, Context};
  48. _ -> {false, ReqData, Context}
  49. end
  50. end.
  51. maybe_fetch_object(Context, Path) ->
  52. % if returns {true, NewContext} then NewContext has response_body
  53. case Context#context.response_body of
  54. undefined ->
  55. case file_exists(Context, Path) of
  56. {true, FullPath} ->
  57. {ok, Value} = file:read_file(FullPath),
  58. {true, Context#context{response_body=Value}};
  59. false ->
  60. {false, Context}
  61. end;
  62. _Body ->
  63. {true, Context}
  64. end.
  65. content_types_provided(ReqData, Context) ->
  66. CT = webmachine_util:guess_mime(wrq:disp_path(ReqData)),
  67. {[{CT, provide_content}], ReqData,
  68. Context#context{metadata=[{'content-type', CT}|Context#context.metadata]}}.
  69. content_types_accepted(ReqData, Context) ->
  70. CT = case wrq:get_req_header_lc("content-type", ReqData) of
  71. undefined -> "application/octet-stream";
  72. X -> X
  73. end,
  74. {MT, _Params} = webmachine_util:media_type_to_detail(CT),
  75. {[{MT, accept_content}], ReqData,
  76. Context#context{metadata=[{'content-type', MT}|Context#context.metadata]}}.
  77. accept_content(ReqData, Context) ->
  78. Path = wrq:disp_path(ReqData),
  79. FP = file_path(Context, Path),
  80. ok = filelib:ensure_dir(filename:dirname(FP)),
  81. ReqData1 = case file_exists(Context, Path) of
  82. {true, _} ->
  83. ReqData;
  84. _ ->
  85. LOC = "http://" ++
  86. wrq:get_req_header_lc("host", ReqData) ++
  87. "/fs/" ++ Path,
  88. wrq:set_resp_header("Location", LOC, ReqData)
  89. end,
  90. Value = wrq:req_body(ReqData1),
  91. case file:write_file(FP, Value) of
  92. ok ->
  93. {true, wrq:set_resp_body(Value, ReqData1), Context};
  94. Err ->
  95. {{error, Err}, ReqData1, Context}
  96. end.
  97. post_is_create(ReqData, Context) ->
  98. {true, ReqData, Context}.
  99. create_path(ReqData, Context) ->
  100. case wrq:get_req_header_lc("slug", ReqData) of
  101. undefined -> {undefined, ReqData, Context};
  102. Slug ->
  103. case file_exists(Context, Slug) of
  104. {true, _} -> {undefined, ReqData, Context};
  105. _ -> {Slug, ReqData, Context}
  106. end
  107. end.
  108. delete_resource(ReqData, Context) ->
  109. case file:delete(file_path(
  110. Context, wrq:disp_path(ReqData))) of
  111. ok -> {true, ReqData, Context};
  112. _ -> {false, ReqData, Context}
  113. end.
  114. provide_content(ReqData, Context) ->
  115. case maybe_fetch_object(Context, wrq:disp_path(ReqData)) of
  116. {true, NewContext} ->
  117. Body = NewContext#context.response_body,
  118. {Body, ReqData, Context};
  119. {false, NewContext} ->
  120. {error, ReqData, NewContext}
  121. end.
  122. last_modified(ReqData, Context) ->
  123. {true, FullPath} = file_exists(Context,
  124. wrq:disp_path(ReqData)),
  125. LMod = filelib:last_modified(FullPath),
  126. {LMod, ReqData, Context#context{metadata=[{'last-modified',
  127. httpd_util:rfc1123_date(LMod)}|Context#context.metadata]}}.
  128. hash_body(Body) -> mochihex:to_hex(binary_to_list(crypto:sha(Body))).
  129. generate_etag(ReqData, Context) ->
  130. case maybe_fetch_object(Context, wrq:disp_path(ReqData)) of
  131. {true, BodyContext} ->
  132. ETag = hash_body(BodyContext#context.response_body),
  133. {ETag, ReqData,
  134. BodyContext#context{metadata=[{etag,ETag}|
  135. BodyContext#context.metadata]}};
  136. _ ->
  137. {undefined, ReqData, Context}
  138. end.