forked from erlyaws/yaws
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathupload.yaws
125 lines (92 loc) · 2.86 KB
/
upload.yaws
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
<html>
<h2> File upload </h2>
<p>This page shows how to upload a file to the webserver, nothing of course
actually gets written to disk, but the upload code is
<a href="code.yaws?file=/upload.yaws">here in file upload.yaws</a>
</p>
<erl>
-record(upload, {
fd,
filename,
last}).
-define(DIR, "/tmp/YawsTestUploads/").
out(A) when A#arg.state == undefined ->
State = #upload{},
multipart(A, State);
out(A) ->
multipart(A, A#arg.state).
err() ->
{ehtml,
{p, [], "error"}}.
multipart(A, State) ->
Parse = yaws_api:parse_multipart_post(A),
case Parse of
{cont, Cont, Res} ->
case addFileChunk(A, Res, State) of
{done, Result} ->
Result;
{cont, NewState} ->
{get_more, Cont, NewState}
end;
{result, Res} ->
case addFileChunk(A, Res, State#upload{last=true}) of
{done, Result} ->
Result;
{cont, _} ->
err()
end;
{error, _Reason} ->
err()
end.
addFileChunk(A, [{part_body, Data}|Res], State) ->
addFileChunk(A, [{body, Data}|Res], State);
addFileChunk(_A, [], State) when State#upload.last==true,
State#upload.filename /= undefined,
State#upload.fd /= undefined ->
file:close(State#upload.fd),
%%file:delete([?DIR,State#upload.filename]),
Res = {ehtml,
{p,[], "File upload done"}},
{done, Res};
addFileChunk(A, [], State) when State#upload.last==true ->
{done, err()};
addFileChunk(_A, [], State) ->
{cont, State};
addFileChunk(A, [{head, {_Name, Opts}}|Res], State ) ->
case lists:keysearch("filename", 1, Opts) of
{value, {_, Fname0}} ->
Fname = yaws_api:sanitize_file_name(basename(Fname0)),
%% we must not put the file in the
%% docroot, it may execute uploade code if the
%% file is a .yaws file !!!!!
file:make_dir(?DIR),
case file:open([?DIR, Fname] ,[write]) of
{ok, Fd} ->
S2 = State#upload{filename = Fname,
fd = Fd},
addFileChunk(A, Res, S2);
Err ->
{done, err()}
end;
false ->
addFileChunk(A,Res,State)
end;
addFileChunk(A, [{body, Data}|Res], State)
when State#upload.filename /= undefined ->
case file:write(State#upload.fd, Data) of
ok ->
addFileChunk(A, Res, State);
Err ->
{done, err()}
end.
basename(FilePath) ->
case string:rchr(FilePath, $\\) of
0 ->
%% probably not a DOS name
filename:basename(FilePath);
N ->
%% probably a DOS name, remove everything after last \
basename(string:substr(FilePath, N+1))
end.
</erl>
</html>