aboutsummaryrefslogblamecommitdiffstats
path: root/lib/dialyzer/test/r9c_SUITE_data/src/inets/mod_responsecontrol.erl
blob: a997db68807638ffdc03b65a378da70e5ac3bd62 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11


                                                                    
  






                                                                           
  


                                                                         
  

































                                                                         

                                                                  



                                                                            
                                                            




                                                
                                                                       




                                                                        
                                                             




                                                                            
                                     




                  
                                                                   

















































                                                                            

                                                     






                                                                                       
 








                                                                        

                                                                         





















                                                                         
                                                                     

                                                                        
                                                   
                                                                                  
                   

                      
                                                              
                                           
                      




























                                                                        
                                                                      







                                                                                        
                     






                                                                                                  
                            



                                                                        
                                                               

                                                            
                                                                        



                                                       
                                                              
                                                                                 
                   







                                                                        
                                




                                                                                      
                      




                                                            
                                    






                                                                        
                              












































                                                                                      
%% ``Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
%% You may obtain a copy of the License at
%%
%%     http://www.apache.org/licenses/LICENSE-2.0
%%
%% Unless required by applicable law or agreed to in writing, software
%% distributed under the License is distributed on an "AS IS" BASIS,
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
%% See the License for the specific language governing permissions and
%% limitations under the License.
%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
%%
%%     $Id: mod_responsecontrol.erl,v 1.1 2008/12/17 09:53:35 mikpe Exp $
%%

-module(mod_responsecontrol).
-export([do/1]).

-include("httpd.hrl").


do(Info) ->
    ?DEBUG("do -> response_control",[]),
    case httpd_util:key1search(Info#mod.data,status) of
	%% A status code has been generated!
	{StatusCode,PhraseArgs,Reason} ->
	    {proceed,Info#mod.data};
	%% No status code has been generated!
	undefined ->
	    case httpd_util:key1search(Info#mod.data,response) of
		%% No response has been generated!
		undefined ->
		    case do_responsecontrol(Info) of
			continue ->
			    {proceed,Info#mod.data};
			Response ->
			    {proceed,[Response|Info#mod.data]}
		    end;
		%% A response has been generated or sent!
		Response ->
		    {proceed,Info#mod.data}
	    end
    end.


%%----------------------------------------------------------------------
%%Control that the request header did not contains any limitations
%%whether a response shall be created or not
%%----------------------------------------------------------------------

do_responsecontrol(Info) ->
    ?DEBUG("do_response_control -> Request URI: ~p",[Info#mod.request_uri]),
    Path = mod_alias:path(Info#mod.data, Info#mod.config_db,
			  Info#mod.request_uri),
    case file:read_file_info(Path) of
	{ok, FileInfo} ->
	    control(Path,Info,FileInfo);
	_ ->
	    %% The requested asset is not a plain file and then it must
	    %% be generated everytime its requested
	    continue
    end.

%%----------------------------------------------------------------------
%%Control the If-Match, If-None-Match,  and If-Modified-Since
%%----------------------------------------------------------------------


%% If a client sends more then one of the if-XXXX fields in a request
%% The standard says it does not specify the behaviuor so I specified it :-)
%% The priority between the fields is
%% 1.If-modified
%% 2.If-Unmodified
%% 3.If-Match
%% 4.If-Nomatch

%% This means if more than one of the fields are in the request the
%% field with highest priority will be used

%%If the request is a range request the If-Range field will be the winner.

control(Path,Info,FileInfo)->
    case control_range(Path,Info,FileInfo) of
	undefined ->
	    case control_Etag(Path,Info,FileInfo) of
		undefined ->
		    case control_modification(Path,Info,FileInfo) of
			continue ->
			    continue;
			ReturnValue ->
			    send_return_value(ReturnValue,FileInfo)
		    end;
		continue ->
		    continue;
		ReturnValue ->
		    send_return_value(ReturnValue,FileInfo)
	    end;
	Response->
	    Response
    end.

%%----------------------------------------------------------------------
%%If there are both a range and an if-range field control if
%%----------------------------------------------------------------------
control_range(Path,Info,FileInfo) ->
    case httpd_util:key1search(Info#mod.parsed_header,"range") of
	undefined->
	    undefined;
	_Range ->
	    case httpd_util:key1search(Info#mod.parsed_header,"if-range") of
		undefined ->
		    undefined;
		EtagOrDate ->
		    control_if_range(Path,Info,FileInfo,EtagOrDate)
	    end
    end.

control_if_range(Path,Info,FileInfo,EtagOrDate) ->
    case httpd_util:convert_request_date(strip_date(EtagOrDate)) of
	bad_date ->
	    FileEtag=httpd_util:create_etag(FileInfo),
	    case FileEtag of
		EtagOrDate ->
		    continue;
		_ ->
		    {if_range,send_file}
	    end;
	ErlDate ->
	    %%We got the date in the request if it is
	    case control_modification_data(Info,FileInfo#file_info.mtime,"if-range") of
		modified ->
		    {if_range,send_file};
		_UnmodifiedOrUndefined->
		    continue
	    end
    end.

%%----------------------------------------------------------------------
%%Controls the values of the If-Match and I-None-Mtch
%%----------------------------------------------------------------------
control_Etag(Path,Info,FileInfo)->
    FileEtag=httpd_util:create_etag(FileInfo),
    %%Control if the E-Tag for the resource  matches one of the Etags in
    %%the -if-match header field
    case control_match(Info,FileInfo,"if-match",FileEtag) of
	nomatch ->
	    %%None of the Etags in the if-match field matched the current
	    %%Etag for the resource return a 304
	    {412,Info,Path};
	match ->
	    continue;
	undefined ->
	    case control_match(Info,FileInfo,"if-none-match",FileEtag) of
		nomatch ->
		    continue;
		match ->
		    case  Info#mod.method of
			"GET" ->
			    {304,Info,Path};
			"HEAD" ->
			    {304,Info,Path};
			_OtherrequestMethod ->
			    {412,Info,Path}
		    end;
		undefined ->
		    undefined
	    end
    end.

%%----------------------------------------------------------------------
%%Control if there are any Etags for HeaderField in the request if so
%%Control if they match the Etag for the requested file
%%----------------------------------------------------------------------
control_match(Info,FileInfo,HeaderField,FileEtag)->
    case split_etags(httpd_util:key1search(Info#mod.parsed_header,HeaderField)) of
	undefined->
	    undefined;
        Etags->
	    %%Control that the match any star not is availible
	    case lists:member("*",Etags) of
		true->
		    match;
		false->
		    compare_etags(FileEtag,Etags)
	    end
    end.

%%----------------------------------------------------------------------
%%Split the etags from the request
%%----------------------------------------------------------------------
split_etags(undefined)->
    undefined;
split_etags(Tags) ->
    string:tokens(Tags,", ").

%%----------------------------------------------------------------------
%%Control if the etag for the file is in the list
%%----------------------------------------------------------------------
compare_etags(Tag,Etags) ->
    case lists:member(Tag,Etags) of
	true ->
	    match;
	_ ->
	    nomatch
    end.

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%                                                                   %%
%%Control if the file is modificated                                 %%
%%                                                                   %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%%----------------------------------------------------------------------
%%Control the If-Modified-Since and If-Not-Modified-Since header fields
%%----------------------------------------------------------------------
control_modification(Path,Info,FileInfo)->
    ?DEBUG("control_modification() -> entry",[]),
    case control_modification_data(Info,FileInfo#file_info.mtime,"if-modified-since") of
	modified->
	    continue;
	unmodified->
	    {304,Info,Path};
	undefined ->
	    case control_modification_data(Info,FileInfo#file_info.mtime,"if-unmodified-since") of
		modified  ->
		    {412,Info,Path};
		_ContinueUndefined ->
		    continue
	    end
    end.

%%----------------------------------------------------------------------
%%Controls the date from the http-request if-modified-since and
%%if-not-modified-since against the modification data of the
%%File
%%----------------------------------------------------------------------
%%Info is the record about the request
%%ModificationTime is the time the file was edited last
%%Header Field is the name of the field  to control

control_modification_data(Info,ModificationTime,HeaderField)->
    case strip_date(httpd_util:key1search(Info#mod.parsed_header,HeaderField)) of
	undefined->
	    undefined;
	LastModified0 ->
	    LastModified=httpd_util:convert_request_date(LastModified0),
	    ?DEBUG("control_modification_data() -> "
		   "~n   Request-Field:    ~s"
		   "~n   FileLastModified: ~p"
		   "~n   FieldValue:       ~p",
		   [HeaderField,ModificationTime,LastModified]),
	    case LastModified of
		bad_date ->
		    undefined;
		_ ->
		    FileTime=calendar:datetime_to_gregorian_seconds(ModificationTime),
		    FieldTime=calendar:datetime_to_gregorian_seconds(LastModified),
		    if
			FileTime=<FieldTime ->
			    ?DEBUG("File unmodified~n", []),
			    unmodified;
			FileTime>=FieldTime ->
			    ?DEBUG("File modified~n", []),
			    modified
		    end
	    end
    end.

%%----------------------------------------------------------------------
%%Compare to dates on the form {{YYYY,MM,DD},{HH,MIN,SS}}
%%If the first date is the biggest returns biggest1 (read biggestFirst)
%%If the first date is smaller
% compare_date(Date,bad_date)->
%     bad_date;

% compare_date({D1,T1},{D2,T2})->
%     case compare_date1(D1,D2) of
%       	equal ->
% 	    compare_date1(T1,T2);
% 	GTorLT->
% 	    GTorLT
%     end.

% compare_date1({T1,T2,T3},{T12,T22,T32}) when T1>T12 ->
%     bigger1;
% compare_date1({T1,T2,T3},{T1,T22,T32}) when T2>T22 ->
%     bigger1;
% compare_date1({T1,T2,T3},{T1,T2,T32}) when T3>T32 ->
%     bigger1;
% compare_date1({T1,T2,T3},{T1,T2,T3})->
%     equal;
% compare_date1(_D1,_D2)->
%     smaller1.


%% IE4 & NS4 sends an extra '; length=xxxx' string at the end of the If-Modified-Since
%% header, we detect this and ignore it (the RFCs does not mention this).
strip_date(undefined) ->
    undefined;
strip_date([]) ->
    [];
strip_date([$;,$ |Rest]) ->
    [];
strip_date([C|Rest]) ->
    [C|strip_date(Rest)].

send_return_value({412,_,_},FileInfo)->
    {status,{412,none,"Precondition Failed"}};

send_return_value({304,Info,Path},FileInfo)->
    Suffix=httpd_util:suffix(Path),
    MimeType = httpd_util:lookup_mime_default(Info#mod.config_db,Suffix,"text/plain"),
    Header = [{code,304},
	      {etag,httpd_util:create_etag(FileInfo)},
	      {content_length,0},
	      {last_modified,httpd_util:rfc1123_date(FileInfo#file_info.mtime)}],
    {response,{response,Header,nobody}}.