PageRenderTime 97ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 0ms

/ucengine/src/core/uce_http.erl

http://github.com/AF83/ucengine
Erlang | 200 lines | 168 code | 15 blank | 17 comment | 1 complexity | 3f845a89a4accfdcc320e80d866669ec MD5 | raw file
  1. %%
  2. %% U.C.Engine - Unified Collaboration Engine
  3. %% Copyright (C) 2011 af83
  4. %%
  5. %% This program is free software: you can redistribute it and/or modify
  6. %% it under the terms of the GNU Affero General Public License as published by
  7. %% the Free Software Foundation, either version 3 of the License, or
  8. %% (at your option) any later version.
  9. %%
  10. %% This program is distributed in the hope that it will be useful,
  11. %% but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. %% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. %% GNU Affero General Public License for more details.
  14. %%
  15. %% You should have received a copy of the GNU Affero General Public License
  16. %% along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. %%
  18. -module(uce_http).
  19. -include("uce.hrl").
  20. -include_lib("yaws/include/yaws_api.hrl").
  21. -export([parse/2]).
  22. write_file(Data, File) ->
  23. case file:write(File#file_upload.fd, Data) of
  24. ok ->
  25. ok;
  26. Err ->
  27. ?ERROR_MSG("Upload error: ~p.~n", [Err]),
  28. error
  29. end.
  30. process_part(_Host, _Arg, [], Params) ->
  31. Params;
  32. process_part(_Host, _Arg, [{part_body, Data}|_Res], [{_Name, File}|_] = Params) when is_record(File, file_upload) ->
  33. case write_file(Data, File) of
  34. ok ->
  35. Params;
  36. error ->
  37. {error, unexpected_error}
  38. end;
  39. process_part(_Host, _Arg, [{part_body, Data}|_Res], [{Name, Value}|OtherParams]) ->
  40. [{Name, Value ++ Data}] ++ OtherParams;
  41. process_part(Host, Arg, [{body, Data}|Res], [{_Name, File}|_] = Params) when is_record(File, file_upload) ->
  42. case write_file(Data, File) of
  43. ok ->
  44. ok = file:close(File#file_upload.fd),
  45. process_part(Host, Arg, Res, Params);
  46. error ->
  47. {error, unexpected_error}
  48. end;
  49. process_part(Host, Arg, [{body, Data}|Rest], [{Name, Value}|OtherParams]) ->
  50. process_part(Host, Arg, Rest, [{Name, Value ++ Data}] ++ OtherParams);
  51. process_part(Host, Arg, [{head, {Name, Opts}}|Res], Params) ->
  52. case lists:keyfind(filename, 1, Opts) of
  53. {_, Fname} ->
  54. Dir = lists:concat([config:get(Host, data), "/", utils:random(3)]),
  55. FilePath = lists:concat([Dir, "/", utils:random()]),
  56. file:make_dir(Dir),
  57. case file:open(FilePath,[write]) of
  58. {ok, Fd} ->
  59. File = #file_upload{filename = Fname,
  60. uri = "file://"++ FilePath,
  61. fd = Fd},
  62. process_part(Host, Arg, Res, [{Name, File}] ++ Params);
  63. Err ->
  64. ?ERROR_MSG("Upload error: ~p.", [Err]),
  65. {error, unexpected_error}
  66. end;
  67. false ->
  68. process_part(Host, Arg, Res, [{Name, ""}] ++ Params)
  69. end.
  70. parse_multipart(Host, Arg, State) ->
  71. case yaws_api:parse_multipart_post(Arg) of
  72. {cont, Cont, Res} ->
  73. NewState = process_part(Host, Arg, Res, State),
  74. case NewState of
  75. {error, _Error} ->
  76. NewState;
  77. NewState ->
  78. {get_more, Cont, NewState}
  79. end;
  80. {result, Res} ->
  81. FormDataParams = process_part(Host, Arg, Res, State),
  82. case FormDataParams of
  83. {error, _Error} ->
  84. FormDataParams;
  85. FormDataParams ->
  86. Params = yaws_api:parse_query(Arg) ++ FormDataParams,
  87. {'POST', Arg#arg.pathinfo, parse_query(Params)}
  88. end
  89. end.
  90. extract(Host, Arg, State) ->
  91. Request = Arg#arg.req,
  92. case Request#http_request.method of
  93. 'GET' ->
  94. {'GET', Arg#arg.pathinfo, parse_query(yaws_api:parse_query(Arg))};
  95. _ ->
  96. case Arg#arg.headers#headers.content_type of
  97. "multipart/form-data;"++ _Boundary ->
  98. parse_multipart(Host, Arg, State);
  99. _ContentType ->
  100. OriginalMethod = Request#http_request.method,
  101. NewArg = Arg#arg{req = Arg#arg.req#http_request{method = 'POST'}},
  102. Query = yaws_api:parse_post(NewArg) ++ yaws_api:parse_query(NewArg),
  103. Method = case utils:get(Query, ["_method"]) of
  104. [none] ->
  105. OriginalMethod;
  106. [StringMethod] ->
  107. list_to_atom(string:to_upper(StringMethod))
  108. end,
  109. {Method, Arg#arg.pathinfo, parse_query(Query)}
  110. end
  111. end.
  112. parse(Host, #arg{} = Arg)
  113. when Arg#arg.state == undefined ->
  114. extract(Host, Arg, []);
  115. parse(Host, #arg{} = Arg) ->
  116. extract(Host, Arg, Arg#arg.state).
  117. extract_dictionary([], _) ->
  118. [];
  119. extract_dictionary([{DictElem, Value}|Tail], Name) ->
  120. Elem = case re:run(DictElem, "^(.*)\\[([^\]]+)\\]$ ?", [{capture, all, list}]) of
  121. {match, [_, Name, Key]} ->
  122. [{Key, Value}];
  123. _ ->
  124. []
  125. end,
  126. Elem ++ extract_dictionary(Tail, Name).
  127. remove_key([], _) ->
  128. [];
  129. remove_key([{Key, Value}|Tail], Name) ->
  130. ElemName = case re:run(Key, "^(.*)\\[([^\]]+)\\]$ ?", [{capture, all, list}]) of
  131. {match, [_, Name, _]} ->
  132. Name;
  133. _ ->
  134. Key
  135. end,
  136. Elem = case ElemName of
  137. Name ->
  138. [];
  139. _ ->
  140. [{Key, Value}]
  141. end,
  142. Elem ++ remove_key(Tail, Name).
  143. parse_query_elems([]) ->
  144. [];
  145. parse_query_elems([{Key, Value}|Tail]=Query) ->
  146. Elem = case re:run(Key, "^(.*)\\[([^\]]+)\\]$ ?", [{capture, all, list}]) of
  147. {match, [_, Name, _]} ->
  148. [{Name, extract_dictionary(Query, Name)}];
  149. _ ->
  150. [{Key, Value}]
  151. end,
  152. [{ToRemove, _}] = Elem,
  153. Elem ++ parse_query_elems(remove_key(Tail, ToRemove)).
  154. parse_query(AsciiDirtyQuery) ->
  155. AsciiQuery = lists:filter(fun({Key, _}) ->
  156. case Key of
  157. [] ->
  158. false;
  159. _ ->
  160. true
  161. end
  162. end,
  163. AsciiDirtyQuery),
  164. Query = lists:map(fun({Key, Value}) ->
  165. case Value of
  166. undefined ->
  167. {unicode_helpers:normalize_unicode(Key), ""};
  168. Value when is_record(Value, file_upload) ->
  169. FileName = Value#file_upload.filename,
  170. {unicode_helpers:normalize_unicode(Key), Value#file_upload{
  171. filename=unicode_helpers:normalize_unicode(FileName)
  172. }};
  173. _ ->
  174. {unicode_helpers:normalize_unicode(Key),
  175. unicode_helpers:normalize_unicode(Value)}
  176. end
  177. end,
  178. AsciiQuery),
  179. parse_query_elems(Query).
  180. -ifdef(TEST).
  181. -include_lib("eunit/include/eunit.hrl").
  182. parse_query_test() ->
  183. ?assertEqual([{"Test", "test"}], parse_query([{"Test", "test"}])),
  184. ?assertEqual([{"test", [{"to", "test"}]}], parse_query([{"test[to]", "test"}])).
  185. -endif.