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 java.util.List;
22
23 import io.undertow.server.ConduitWrapper;
24 import io.undertow.server.HttpServerExchange;
25 import io.undertow.util.AttachmentKey;
26 import io.undertow.util.ConduitFactory;
27 import io.undertow.util.Headers;
28 import io.undertow.util.Methods;
29 import io.undertow.util.StatusCodes;
30 import org.xnio.conduits.StreamSinkConduit;
31
32 /**
33  * An attachment that provides information about the current content encoding that will be chosen for the response
34  *
35  * @author Stuart Douglas
36  */

37 public class AllowedContentEncodings implements ConduitWrapper<StreamSinkConduit> {
38
39     public static final AttachmentKey<AllowedContentEncodings> ATTACHMENT_KEY = AttachmentKey.create(AllowedContentEncodings.class);
40
41     private final HttpServerExchange exchange;
42     private final List<EncodingMapping> encodings;
43
44
45     public AllowedContentEncodings(final HttpServerExchange exchange, final List<EncodingMapping> encodings) {
46         this.exchange = exchange;
47         this.encodings = encodings;
48     }
49
50     /**
51      * @return The content encoding that will be set, given the current state of the HttpServerExchange
52      */

53     public String getCurrentContentEncoding() {
54         for (EncodingMapping encoding : encodings) {
55             if (encoding.getAllowed() == null || encoding.getAllowed().resolve(exchange)) {
56                 return encoding.getName();
57             }
58         }
59         return Headers.IDENTITY.toString();
60     }
61
62     public EncodingMapping getEncoding() {
63         for (EncodingMapping encoding : encodings) {
64             if (encoding.getAllowed() == null || encoding.getAllowed().resolve(exchange)) {
65                 return encoding;
66             }
67         }
68         return null;
69     }
70
71     public boolean isIdentity() {
72         return getCurrentContentEncoding().equals(Headers.IDENTITY.toString());
73     }
74
75     /**
76      * If the list of allowed encodings was empty then it means that no encodings were allowed, and
77      * identity was explicitly prohibited with a q value of 0.
78      */

79     public boolean isNoEncodingsAllowed() {
80         return encodings.isEmpty();
81     }
82
83     @Override
84     public StreamSinkConduit wrap(final ConduitFactory<StreamSinkConduit> factory, final HttpServerExchange exchange) {
85         if (exchange.getResponseHeaders().contains(Headers.CONTENT_ENCODING)) {
86             //already encoded
87             return factory.create();
88         }
89         //if this is a zero length response we don't want to encode
90         if (exchange.getResponseContentLength() != 0
91                 && exchange.getStatusCode() != StatusCodes.NO_CONTENT
92                 && exchange.getStatusCode() != StatusCodes.NOT_MODIFIED) {
93             EncodingMapping encoding = getEncoding();
94             if (encoding != null) {
95                 exchange.getResponseHeaders().put(Headers.CONTENT_ENCODING, encoding.getName());
96                 if (exchange.getRequestMethod().equals(Methods.HEAD)) {
97                     //we don't create an actual encoder for HEAD requests, but we set the header
98                     return factory.create();
99                 } else {
100                     return encoding.getEncoding().getResponseWrapper().wrap(factory, exchange);
101                 }
102             }
103         }
104         return factory.create();
105     }
106 }
107