1%%
2%% %CopyrightBegin%
3%%
4%% Copyright Ericsson AB 1997-2016. All Rights Reserved.
5%%
6%% Licensed under the Apache License, Version 2.0 (the "License");
7%% you may not use this file except in compliance with the License.
8%% You may obtain a copy of the License at
9%%
10%%     http://www.apache.org/licenses/LICENSE-2.0
11%%
12%% Unless required by applicable law or agreed to in writing, software
13%% distributed under the License is distributed on an "AS IS" BASIS,
14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15%% See the License for the specific language governing permissions and
16%% limitations under the License.
17%%
18%% %CopyrightEnd%
19%%
20%%
21-module(mod_get).
22
23-export([do/1]).
24
25-include("httpd.hrl").
26-include("httpd_internal.hrl").
27-include("inets_internal.hrl").
28
29-define(VMODULE,"GET").
30
31
32%% do
33
34do(Info) ->
35    case Info#mod.method of
36	"GET" ->
37	    case proplists:get_value(status, Info#mod.data) of
38		%% A status code has been generated!
39		{_StatusCode, _PhraseArgs, _Reason} ->
40		    {proceed,Info#mod.data};
41		%% No status code has been generated!
42		undefined ->
43		    case proplists:get_value(response, Info#mod.data) of
44			%% No response has been generated!
45			undefined ->
46			    do_get(Info);
47			%% A response has been generated or sent!
48			_Response ->
49			    {proceed,Info#mod.data}
50		    end
51	    end;
52	%% Not a GET method!
53	_ ->
54	    {proceed,Info#mod.data}
55    end.
56
57
58do_get(Info) ->
59    Path = mod_alias:path(Info#mod.data, Info#mod.config_db,
60			  Info#mod.request_uri),
61
62    send_response(Info#mod.socket,Info#mod.socket_type, Path, Info).
63
64
65%% The common case when no range is specified
66send_response(_Socket, _SocketType, Path, Info)->
67    %% Send the file!
68    %% Find the modification date of the file
69    case file:open(Path,[raw,binary]) of
70	{ok, FileDescriptor} ->
71	    {FileInfo, LastModified} = get_modification_date(Path),
72	    Suffix = httpd_util:suffix(Path),
73	    MimeType = httpd_util:lookup_mime_default(Info#mod.config_db,
74						      Suffix,"text/plain"),
75	    %% FileInfo = file:read_file_info(Path),
76	    Size = integer_to_list(FileInfo#file_info.size),
77	    Headers = case Info#mod.http_version of
78			 "HTTP/1.1" ->
79			      [{content_type, MimeType},
80			       {etag, httpd_util:create_etag(FileInfo)},
81			       {content_length, Size}|LastModified];
82			  %% OTP-4935
83			 _ ->
84			     %% i.e http/1.0 and http/0.9
85			      [{content_type, MimeType},
86			       {content_length, Size}|LastModified]
87			  end,
88	    send(Info, 200, Headers, FileDescriptor),
89	    file:close(FileDescriptor),
90	    {proceed,[{response,{already_sent,200,
91				 FileInfo#file_info.size}},
92		      {mime_type,MimeType} | Info#mod.data]};
93	{error, Reason} ->
94	    Status = httpd_file:handle_error(Reason, "open", Info, Path),
95	    {proceed, [{status, Status} | Info#mod.data]}
96    end.
97
98%% send
99
100send(#mod{socket = Socket, socket_type = SocketType} = Info,
101     StatusCode, Headers, FileDescriptor) ->
102    httpd_response:send_header(Info, StatusCode, Headers),
103    send_body(SocketType,Socket,FileDescriptor).
104
105
106send_body(SocketType,Socket,FileDescriptor) ->
107    case file:read(FileDescriptor,?FILE_CHUNK_SIZE) of
108	{ok,Binary} ->
109	    case httpd_socket:deliver(SocketType,Socket,Binary) of
110		socket_closed ->
111		    socket_close;
112		_ ->
113		    send_body(SocketType,Socket,FileDescriptor)
114	    end;
115	eof ->
116	    eof
117    end.
118
119get_modification_date(Path)->
120    {ok, FileInfo0} = file:read_file_info(Path),
121    LastModified =
122	case catch httpd_util:rfc1123_date(FileInfo0#file_info.mtime) of
123	    Date when is_list(Date) -> [{last_modified, Date}];
124	    _ -> []
125	end,
126    {FileInfo0, LastModified}.
127