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.
6 -module(webmachine_demo_fs_resource).
8 -export([allowed_methods/2,
11 content_types_provided/2,
12 content_types_accepted/2,
20 -record(context, {root,response_body=undefined,metadata=[]}).
22 -include_lib("kernel/include/file.hrl").
23 -include_lib("webmachine/include/webmachine.hrl").
26 {root, Root} = proplists:lookup(root, ConfigProps),
27 {ok, #context{root=Root}}.
29 allowed_methods(ReqData, Context) ->
30 {['HEAD', 'GET', 'PUT', 'DELETE', 'POST'], ReqData, Context}.
32 file_path(_Context, []) ->
34 file_path(Context, Name) ->
35 RelName = case hd(Name) of
39 filename:join([Context#context.root, RelName]).
41 file_exists(Context, Name) ->
42 NamePath = file_path(Context, Name),
43 case filelib:is_regular(NamePath) of
50 resource_exists(ReqData, Context) ->
51 Path = wrq:disp_path(ReqData),
52 case file_exists(Context, Path) of
54 {true, ReqData, Context};
57 "p" -> {true, ReqData, Context};
58 _ -> {false, ReqData, Context}
62 maybe_fetch_object(Context, Path) ->
63 % if returns {true, NewContext} then NewContext has response_body
64 case Context#context.response_body of
66 case file_exists(Context, Path) of
68 {ok, Value} = file:read_file(FullPath),
69 {true, Context#context{response_body=Value}};
77 content_types_provided(ReqData, Context) ->
78 CT = webmachine_util:guess_mime(wrq:disp_path(ReqData)),
79 {[{CT, provide_content}], ReqData,
80 Context#context{metadata=[{'content-type', CT}|Context#context.metadata]}}.
82 content_types_accepted(ReqData, Context) ->
83 CT = case wrq:get_req_header("content-type", ReqData) of
84 undefined -> "application/octet-stream";
87 {MT, _Params} = webmachine_util:media_type_to_detail(CT),
88 {[{MT, accept_content}], ReqData,
89 Context#context{metadata=[{'content-type', MT}|Context#context.metadata]}}.
91 accept_content(ReqData, Context) ->
92 Path = wrq:disp_path(ReqData),
93 FP = file_path(Context, Path),
94 ok = filelib:ensure_dir(FP),
95 ReqData1 = case file_exists(Context, Path) of
100 wrq:get_req_header("host", ReqData) ++
102 wrq:set_resp_header("Location", LOC, ReqData)
104 Value = wrq:req_body(ReqData1),
105 case file:write_file(FP, Value) of
107 {true, wrq:set_resp_body(Value, ReqData1), Context};
109 {{error, Err}, ReqData1, Context}
112 post_is_create(ReqData, Context) ->
113 {true, ReqData, Context}.
115 create_path(ReqData, Context) ->
116 case wrq:get_req_header("slug", ReqData) of
117 undefined -> {undefined, ReqData, Context};
119 case file_exists(Context, Slug) of
120 {true, _} -> {undefined, ReqData, Context};
121 _ -> {Slug, ReqData, Context}
125 delete_resource(ReqData, Context) ->
126 case file:delete(file_path(
127 Context, wrq:disp_path(ReqData))) of
128 ok -> {true, ReqData, Context};
129 _ -> {false, ReqData, Context}
132 provide_content(ReqData, Context) ->
133 case maybe_fetch_object(Context, wrq:disp_path(ReqData)) of
134 {true, NewContext} ->
135 Body = NewContext#context.response_body,
136 {Body, ReqData, Context};
137 {false, NewContext} ->
138 {error, ReqData, NewContext}
141 last_modified(ReqData, Context) ->
142 {true, FullPath} = file_exists(Context,
143 wrq:disp_path(ReqData)),
144 LMod = filelib:last_modified(FullPath),
145 {LMod, ReqData, Context#context{metadata=[{'last-modified',
146 httpd_util:rfc1123_date(LMod)}|Context#context.metadata]}}.
148 hash_body(Body) -> mochihex:to_hex(binary_to_list(crypto:sha(Body))).
150 generate_etag(ReqData, Context) ->
151 case maybe_fetch_object(Context, wrq:disp_path(ReqData)) of
152 {true, BodyContext} ->
153 ETag = hash_body(BodyContext#context.response_body),
155 BodyContext#context{metadata=[{etag,ETag}|
156 BodyContext#context.metadata]}};
158 {undefined, ReqData, Context}