Skip to content
Newer
Older
100644 169 lines (147 sloc) 6.14 KB
b8d8838 @klacke ""
authored Apr 12, 2005
1 -module(yaws_content_negotiation).
2 -export([compute_rsva/2, parse_accept_field/1, match_media_type/2]).
3
6cf3ece @klacke ""
authored Nov 20, 2005
4 -include("../include/yaws_api.hrl").
b8d8838 @klacke ""
authored Apr 12, 2005
5
6 %% TODO: analyze impact of spaces in headers; when/where to strip?
7
8 %% RFC 2296
9 compute_rsva(Arg, VariantList) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
10 Headers = Arg#arg.headers,
11 Accept = parse_accept_field(Headers#headers.accept),
12 % move these into #headers{} !
13 AcceptCharset = parse_accept_field(
14 get_other_header('Accept-Charset', Headers)),
15 AcceptLanguage = parse_accept_field(
16 get_other_header('Accept-Language', Headers)),
17 AcceptFeatures = [], % yet to be implemented
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 19, 2011
18 RankedVariants = overall_quality(VariantList, Accept,
19 AcceptCharset, AcceptLanguage,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
20 AcceptFeatures),
21 case determine_result(RankedVariants) of
22 none ->
23 %% TODO: build Alternates: header field
24 VariantList;
25 URI ->
26 %% TODO: must be neighbour variant (same root as request)
27 URI
28 end.
29
df47d9c @klacke compile bug
authored Feb 25, 2011
30 get_other_header(Name, Headers) ->
31 case lists:keysearch(Name, 3, Headers#headers.other) of
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
32 {value, {_,_,Name,_,Field}} -> Field;
33 false -> undefined
34 end.
b8d8838 @klacke ""
authored Apr 12, 2005
35
36 determine_result(V) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
37 determine_result(V, {[], {0,1}}).
b8d8838 @klacke ""
authored Apr 12, 2005
38
39 determine_result([{URI,{Q,X}}|T], {_,{AccQ,_}}) when Q > AccQ ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
40 determine_result(T, {URI,{Q,X}});
b8d8838 @klacke ""
authored Apr 12, 2005
41 determine_result([_|T], Acc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
42 determine_result(T, Acc);
b8d8838 @klacke ""
authored Apr 12, 2005
43 determine_result([], {URI,{_,0}}) -> URI;
44 determine_result([], _) -> none.
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
45
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
46 overall_quality(VariantList, Accept, AcceptCharset, AcceptLanguage,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
47 AcceptFeatures) ->
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
48 overall_quality(VariantList, Accept, AcceptCharset,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
49 AcceptLanguage, AcceptFeatures, []).
50
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
51 overall_quality([{URI,Qs,Attributes}|T], Accept, AcceptCharset,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
52 AcceptLanguage, AcceptFeatures, Acc) ->
53 %% QX = {Qvalue, [0=definitive, >0=speculative]}
54 Qt = case {lists:keysearch(type, 1, Attributes), Accept} of
55 {false, _} -> {1000, 0};
56 {_, []} -> {1000, 1};
57 {{value, {type, MediaType}}, Accept} ->
58 match_media_type(MediaType, Accept)
59 end,
60 Qc = case {lists:keysearch(charset, 1, Attributes), AcceptCharset} of
61 {false, _} -> {1000, 0};
62 {_, []} -> {1000, 1};
63 {{value, {charset, Charset}}, AcceptCharset} ->
64 match_charset(Charset, AcceptCharset)
65 end,
66 Ql = case {lists:keysearch(language, 1, Attributes), AcceptLanguage} of
67 {false, _} -> {1000, 0};
68 {_, []} -> {1000, 1};
69 {{value, {language, Languages}}, AcceptLanguage} ->
70 match_language(Languages, AcceptLanguage)
71 end,
72 Qf = {1000, 0}, % Accept-Features: not yet implemented
73 Q = round5(Qs, Qt, Qc, Ql, Qf),
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
74 overall_quality(T, Accept, AcceptCharset, AcceptLanguage,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
75 AcceptFeatures, [{URI, Q}|Acc]);
76 %% fallback-variant
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
77 overall_quality([URI|T], Accept, AcceptCharset, AcceptLanguage,
78 AcceptFeatures, Acc)
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
79 when is_list(URI) ->
80 Q = {1, 0}, % {0.000001, definitive}
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
81 overall_quality(T, Accept, AcceptCharset, AcceptLanguage,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
82 AcceptFeatures, [{URI, Q}|Acc]);
455578a @vinoski major trailing whitespace cleanup
vinoski authored Apr 20, 2011
83 overall_quality([], _Accept, _AcceptCharset, _AcceptLanguage,
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
84 _AcceptFeatures, Acc) -> Acc.
85
86 %% this functions rounds to five decimal places but to avoid
87 %% using floats we have 1 represent 0.000001 and 1000000 = 1.0
b8d8838 @klacke ""
authored Apr 12, 2005
88 round5(Qs, {Qt, A}, {Qc, B}, {Ql, C}, {Qf, D}) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
89 Q = ((Qs * 1000) * (Qt * 1000) * (Qc * 1000) * (Ql * 1000) * (Qf * 1000)),
90 {((Q div 10000000000000000000000000) * 10), (A+B+C+D)}.
91
b8d8838 @klacke ""
authored Apr 12, 2005
92 match_media_type(MediaType, AcceptRanges) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
93 case lists:keysearch(MediaType, 1, AcceptRanges) of
94 {ok, {_, Q}} -> {Q, 0};
95 false ->
96 [SimpleMediaType|_] = yaws:split_sep(MediaType, $;),
97 match_media_type_simple(SimpleMediaType, AcceptRanges)
98 end.
b8d8838 @klacke ""
authored Apr 12, 2005
99
100 match_media_type_simple(SimpleMediaType, AcceptRanges) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
101 case lists:keysearch(SimpleMediaType, 1, AcceptRanges) of
102 {ok, {_, Q}} -> {Q, 0};
103 false ->
104 [Type|_] = yaws:split_sep(SimpleMediaType, $/),
105 match_media_type_only(Type, AcceptRanges)
106 end.
b8d8838 @klacke ""
authored Apr 12, 2005
107
108 match_media_type_only(Type, AcceptRanges) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
109 case lists:keysearch(Type++"/*", 1, AcceptRanges) of
110 {ok, {_, Q}} -> {Q, 1};
111 false ->
112 case lists:keysearch("*/*", 1, AcceptRanges) of
113 {ok, {_, Q}} -> {Q, 1};
114 false -> {0, 0}
115 end
116 end.
b8d8838 @klacke ""
authored Apr 12, 2005
117
118 match_charset(Charset, AcceptCharset) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
119 case lists:keysearch(Charset, 1, AcceptCharset) of
120 {ok, {_, Q}} -> {Q, 0};
121 false -> {0, 0}
122 end.
b8d8838 @klacke ""
authored Apr 12, 2005
123
124 match_language(Languages, AcceptLanguage) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
125 match_language(Languages, AcceptLanguage, 0).
b8d8838 @klacke ""
authored Apr 12, 2005
126
127 match_language([Language|T], AcceptLanguage, Qacc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
128 Qacc1 = case lists:keysearch(Language, 1, AcceptLanguage) of
129 {ok, {_, Q1}} when Q1 > Qacc -> Q1;
130 _ -> Qacc
131 end,
132 Qacc2 = case yaws:split_sep(Language, $-) of
133 [H|T] when length(T) > 0 ->
134 case lists:keysearch(H, 1, AcceptLanguage) of
135 {ok, {_, Q2}} when Q2 > Qacc1 -> Q2;
136 _ -> Qacc1
137 end;
138 [Language] -> Qacc1
139 end,
140 match_language(T, AcceptLanguage, Qacc2);
b8d8838 @klacke ""
authored Apr 12, 2005
141 match_language([], AcceptLanguage, Qacc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
142 case lists:keysearch("*", 1, AcceptLanguage) of
143 {ok, {_, Q}} when Q > Qacc -> {Q, 1};
144 _ -> {Qacc, 0}
145 end.
b8d8838 @klacke ""
authored Apr 12, 2005
146
147 parse_accept_field(undefined) -> [];
148 parse_accept_field(Field) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
149 parse_accept_field(yaws:split_sep(Field, $,), []).
b8d8838 @klacke ""
authored Apr 12, 2005
150
151 parse_accept_field([H|T], Acc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
152 R = parse_accept_element(yaws:split_sep(H, $;)),
153 parse_accept_field(T, Acc ++ [R]);
b8d8838 @klacke ""
authored Apr 12, 2005
154 parse_accept_field([], Acc) -> Acc.
155
156 parse_accept_element(L) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
157 parse_accept_element(L, []).
b8d8838 @klacke ""
authored Apr 12, 2005
158
159 parse_accept_element(["q="++Q|_], Acc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
160 {Acc, yaws:parse_qvalue(Q)};
b8d8838 @klacke ""
authored Apr 12, 2005
161 parse_accept_element([H|T], []) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
162 parse_accept_element(T, H);
b8d8838 @klacke ""
authored Apr 12, 2005
163 parse_accept_element([H|T], Acc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
164 parse_accept_element(T, Acc++";"++H);
b8d8838 @klacke ""
authored Apr 12, 2005
165 parse_accept_element([], Acc) ->
0be3c7e @klacke untabified all of yaws
authored Feb 14, 2008
166 {Acc, 1000}.
167
b8d8838 @klacke ""
authored Apr 12, 2005
168
Something went wrong with that request. Please try again.