Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 225 lines (206 sloc) 8.246 kb
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
1 -module(yaws_multipart).
2 -export([read_multipart_form/2]).
3
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
4 -include("../include/yaws.hrl").
5 -include("../include/yaws_api.hrl").
6
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
7 -record(upload, {
8 fd,
9 filename,
10 fixed_filename,
11 last = false,
12 param_name,
13 param_running_value,
14 params,
15 running_file_size = 0,
16 max_file_size,
17 no_temp_file,
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
18 temp_dir = yaws:tmpdir("/tmp"),
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
19 temp_file,
20 headers = []
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
21 }).
22
23 read_multipart_form(A, Options) when A#arg.state == undefined ->
24 State = #upload{params = dict:new()},
25 NewState = read_options(Options,State),
26 multipart(A, NewState);
27 read_multipart_form(A, _Options) ->
28 multipart(A, A#arg.state).
29
30 read_options([], State) -> State;
31 read_options([Option|Rest], State) ->
32 NewState = case Option of
33 {max_file_size, SizeInBytes} ->
34 State#upload{max_file_size = SizeInBytes};
35 no_temp_file ->
36 State#upload{no_temp_file = true};
37 {temp_file, FullPath} ->
38 State#upload{fixed_filename = FullPath};
39 {temp_dir, Dir} ->
40 true = filelib:is_dir(Dir),
41 State#upload{temp_dir = Dir}
42 end,
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
43 read_options(Rest, NewState).
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
44
45 multipart(A, State) ->
46 Parse = yaws_api:parse_multipart_post(A),
47 case Parse of
48 {cont, Cont, Res} ->
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
49 case add_file_chunk(A, Res, State) of
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
50 {done, NewState} ->
51 {done, NewState#upload.params};
52 {cont, NewState} ->
53 {get_more, Cont, NewState};
54 Error={error, _Reason} ->
55 Error
56 end;
57 {result, Res} ->
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
58 case add_file_chunk(A, Res, State#upload{last=true}) of
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
59 {done, S2} ->
60 {done,S2#upload.params};
61 Error={error, _Reason} ->
62 Error
63 end
64 end.
65
66
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
67 add_file_chunk(A, [{part_body, Data}|Res], State) ->
68 add_file_chunk(A, [{body, Data}|Res], State);
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
69
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
70 add_file_chunk(_A, [], State) when State#upload.last == true ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
71 {done, close_previous_param(State)};
72
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
73 add_file_chunk(_A, [], State) ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
74 {cont, State};
75
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
76 add_file_chunk(A, [{head, {_Name, Opts}}|Res], State ) ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
77 S1 = close_previous_param(State),
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
78 S2 = lists:foldl(
79 fun({filename, Fname0}, RunningState) ->
80 case create_temp_file(State) of
81 [undefined, undefined] ->
82 %% values will be stored in memory as
83 %% dictated by state#upload.no_temp_file
84 RunningState#upload{
85 filename = Fname0,
86 param_running_value = undefined,
87 running_file_size = 0};
88 [Fname, Fd] ->
89 RunningState#upload{
90 fd = Fd,
91 filename = Fname0,
92 temp_file = Fname,
93 param_running_value = undefined,
94 running_file_size = 0}
95 end;
96 ({name, ParamName}, RunningState) ->
97 RunningState#upload{
98 param_name = ParamName,
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
99 param_running_value = undefined};
100 (HdrVal, RunningState) ->
101 RunningState#upload{
102 headers = [HdrVal | RunningState#upload.headers]}
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
103 end,
104 S1,
105 Opts),
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
106 add_file_chunk(A,Res,S2);
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
107
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
108 add_file_chunk(A, [{body, Data}|Res], State) when State#upload.fd /= undefined ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
109 NewSize = compute_new_size(State,Data),
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
110 Check = check_param_size(State, NewSize),
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
111 case Check of
112 ok ->
113 ok = file:write(State#upload.fd, Data),
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
114 add_file_chunk(A, Res, State#upload{running_file_size = NewSize});
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
115 Error={error, _Reason} ->
116 Error
117 end;
118
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
119 add_file_chunk(A, [{body, Data}|Res], State) ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
120 NewSize = compute_new_size(State,Data),
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
121 Check = check_param_size(State, NewSize),
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
122 case Check of
123 ok ->
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
124 NewState =
125 case State#upload.param_running_value of
126 undefined ->
127 State#upload{param_running_value = Data};
128 PrevValue ->
129 NewData = compute_new_value(PrevValue, Data),
130 State#upload{param_running_value = NewData}
131 end,
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
132 add_file_chunk(A, Res, NewState#upload{running_file_size = NewSize});
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
133 Error={error, _Reason} ->
134 Error
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
135 end.
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
136
137 create_temp_file(State) ->
138 case State#upload.no_temp_file of
139 undefined ->
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
140 FilePath =
141 case State#upload.fixed_filename of
142 undefined ->
143 {A, B, C} = now(),
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
144 FileName = yaws:join_sep(["yaws",
145 integer_to_list(A),
146 integer_to_list(B),
147 integer_to_list(C)], "_"),
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
148 filename:join([State#upload.temp_dir, FileName]);
149 Filename ->
150 Filename
151 end,
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
152 {ok,Fd} = file:open(FilePath, [write,binary]),
153 [FilePath, Fd];
154 true ->
155 [undefined, undefined]
156 end
157 .
158
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
159 close_previous_param(#upload{param_name = undefined} = State) ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
160 State;
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
161 close_previous_param(#upload{param_name = ParamName} = State) ->
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
162 S2 = case State#upload.filename of
163 undefined ->
164 ParamValue = State#upload.param_running_value,
165 State#upload{
166 params = dict:store(ParamName, ParamValue,
167 State#upload.params)};
168 _ ->
169 ParamInfo = [{filename, State#upload.filename}],
170 ParamInfo2 = case State#upload.fd of
171 undefined ->
172 lists:append(
173 ParamInfo,
174 [{value,
175 State#upload.param_running_value}]);
176 Fd ->
177 file:close(Fd),
178 lists:append(ParamInfo,
179 [{temp_file,
180 State#upload.temp_file}])
181 end,
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
182 ParamInfo3 = lists:append(ParamInfo2, State#upload.headers),
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
183 State#upload{
184 filename = undefined,
185 fd = undefined,
186 temp_file= undefined,
187 running_file_size = 0,
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
188 params = dict:store(ParamName, ParamInfo3,
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
189 State#upload.params)
190 }
191 end,
192 S2#upload{param_name = undefined,
641939a @vinoski return part headers from yaws_multipart:read_multipart_form
vinoski authored
193 param_running_value = undefined,
194 headers = []}.
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
195
196 compute_new_size(State, Data) ->
197 case Data of
4248f8d @vinoski move yaws_multipart.erl to src dir and incorporate klacke's changes
vinoski authored
198 undefined ->
199 State#upload.running_file_size;
200 _ ->
201 State#upload.running_file_size + iolist_size(Data)
b605e5c @vinoski fixes for yaws_multipart.erl (Praveen Ray)
vinoski authored
202 end.
203
204
205 check_param_size(State, NewSize) ->
206 case State#upload.max_file_size of
207 undefined -> ok;
208 MaxSizeInBytes ->
209 case NewSize > MaxSizeInBytes of
210 true ->
211 {error, io_lib:format("~p is too large",
212 [State#upload.param_name])};
213 false ->
214 ok
215 end
216 end.
217
218 compute_new_value(PrevValue, NewData) ->
219 case NewData of
220 Data when is_binary(NewData) ->
221 <<PrevValue/binary, Data/binary>>;
222 Data when is_list(NewData) ->
223 PrevValue ++ Data
224 end.
Something went wrong with that request. Please try again.