1 /*
2  * JBoss, Home of Professional Open Source.
3  * Copyright 2014 Red Hat, Inc., and individual contributors
4  * as indicated by the @author tags.
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
19 package io.undertow.server.handlers.encoding;
20
21 import io.undertow.predicate.Predicate;
22 import io.undertow.predicate.Predicates;
23 import io.undertow.server.HttpServerExchange;
24 import io.undertow.util.CopyOnWriteMap;
25 import io.undertow.util.Headers;
26 import io.undertow.util.QValueParser;
27
28 import java.util.ArrayList;
29 import java.util.Collections;
30 import java.util.List;
31 import java.util.Map;
32
33 /**
34  *
35  *
36  * @author Stuart Douglas
37  */

38 public class ContentEncodingRepository {
39
40     public static final String IDENTITY = "identity";
41     public static final EncodingMapping IDENTITY_ENCODING = new EncodingMapping(IDENTITY, ContentEncodingProvider.IDENTITY, 0, Predicates.truePredicate());
42
43     private final Map<String, EncodingMapping> encodingMap = new CopyOnWriteMap<>();
44
45
46     public AllowedContentEncodings getContentEncodings(final HttpServerExchange exchange) {
47         final List<String> res = exchange.getRequestHeaders().get(Headers.ACCEPT_ENCODING);
48         if (res == null || res.isEmpty()) {
49             return null;
50         }
51         final List<EncodingMapping> resultingMappings = new ArrayList<>();
52         final List<List<QValueParser.QValueResult>> found = QValueParser.parse(res);
53         for (List<QValueParser.QValueResult> result : found) {
54             List<EncodingMapping> available = new ArrayList<>();
55             boolean includesIdentity = false;
56             boolean isQValue0 = false;
57
58             for (final QValueParser.QValueResult value : result) {
59                 EncodingMapping encoding;
60                 if (value.getValue().equals("*")) {
61                     includesIdentity = true;
62                     encoding = IDENTITY_ENCODING;
63                 } else {
64                     encoding = encodingMap.get(value.getValue());
65                     if(encoding == null && IDENTITY.equals(value.getValue())) {
66                         encoding = IDENTITY_ENCODING;
67                     }
68                 }
69                 if (value.isQValueZero()) {
70                     isQValue0 = true;
71                 }
72                 if (encoding != null) {
73                     available.add(encoding);
74                 }
75             }
76             if (isQValue0) {
77                 if (resultingMappings.isEmpty()) {
78                     if (includesIdentity) {
79                         return new AllowedContentEncodings(exchange, Collections.<EncodingMapping>emptyList());
80                     } else {
81                         return null;
82                     }
83                 }
84             } else if (!available.isEmpty()) {
85                 Collections.sort(available, Collections.reverseOrder());
86                 resultingMappings.addAll(available);
87             }
88         }
89         if (!resultingMappings.isEmpty()) {
90             return new AllowedContentEncodings(exchange, resultingMappings);
91         }
92         return null;
93     }
94
95     public synchronized ContentEncodingRepository addEncodingHandler(final String encoding, final ContentEncodingProvider encoder, int priority) {
96         addEncodingHandler(encoding, encoder, priority, Predicates.truePredicate());
97         return this;
98     }
99
100     public synchronized ContentEncodingRepository addEncodingHandler(final String encoding, final ContentEncodingProvider encoder, int priority, final Predicate enabledPredicate) {
101         this.encodingMap.put(encoding, new EncodingMapping(encoding, encoder, priority, enabledPredicate));
102         return this;
103     }
104
105     public synchronized ContentEncodingRepository removeEncodingHandler(final String encoding) {
106         encodingMap.remove(encoding);
107         return this;
108     }
109
110 }
111