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.Handlers;
22 import io.undertow.server.HandlerWrapper;
23 import io.undertow.server.HttpHandler;
24 import io.undertow.server.HttpServerExchange;
25 import io.undertow.server.handlers.ResponseCodeHandler;
26 import io.undertow.server.handlers.builder.HandlerBuilder;
27
28 import java.util.Collections;
29 import java.util.Map;
30 import java.util.Set;
31
32 /**
33  * Handler that serves as the basis for content encoding implementations.
34  * <p>
35  * Encoding handlers are added as delegates to this handler, with a specified server side priority.
36  * <p>
37  * If a request comes in with no q value then then server will pick the handler with the highest priority
38  * as the encoding to use, otherwise the q value will be used to determine the correct handler.
39  * <p>
40  * If no handler matches then the identity encoding is assumed. If the identity encoding has been
41  * specifically disallowed due to a q value of 0 then the handler will set the response code
42  * 406 (Not Acceptable) and return.
43  *
44  * @author Stuart Douglas
45  */

46 public class EncodingHandler implements HttpHandler {
47
48     private volatile HttpHandler next = ResponseCodeHandler.HANDLE_404;
49     private volatile HttpHandler noEncodingHandler = ResponseCodeHandler.HANDLE_406;
50
51     private final ContentEncodingRepository contentEncodingRepository;
52
53     public EncodingHandler(final HttpHandler next, ContentEncodingRepository contentEncodingRepository) {
54         this.next = next;
55         this.contentEncodingRepository = contentEncodingRepository;
56     }
57
58     public EncodingHandler(ContentEncodingRepository contentEncodingRepository) {
59         this.contentEncodingRepository = contentEncodingRepository;
60     }
61
62     @Override
63     public void handleRequest(final HttpServerExchange exchange) throws Exception {
64         AllowedContentEncodings encodings = contentEncodingRepository.getContentEncodings(exchange);
65         if (encodings == null || !exchange.isResponseChannelAvailable()) {
66             next.handleRequest(exchange);
67         } else if (encodings.isNoEncodingsAllowed()) {
68             noEncodingHandler.handleRequest(exchange);
69         } else {
70             exchange.addResponseWrapper(encodings);
71             exchange.putAttachment(AllowedContentEncodings.ATTACHMENT_KEY, encodings);
72             next.handleRequest(exchange);
73         }
74     }
75
76
77     public HttpHandler getNext() {
78         return next;
79     }
80
81     public EncodingHandler setNext(final HttpHandler next) {
82         Handlers.handlerNotNull(next);
83         this.next = next;
84         return this;
85     }
86
87
88     public HttpHandler getNoEncodingHandler() {
89         return noEncodingHandler;
90     }
91
92     public EncodingHandler setNoEncodingHandler(HttpHandler noEncodingHandler) {
93         Handlers.handlerNotNull(noEncodingHandler);
94         this.noEncodingHandler = noEncodingHandler;
95         return this;
96     }
97
98     public static class Builder  implements HandlerBuilder {
99
100         @Override
101         public String name() {
102             return "compress";
103         }
104
105         @Override
106         public Map<String, Class<?>> parameters() {
107             return Collections.emptyMap();
108         }
109
110         @Override
111         public Set<String> requiredParameters() {
112             return Collections.emptySet();
113         }
114
115         @Override
116         public String defaultParameter() {
117             return null;
118         }
119
120         @Override
121         public HandlerWrapper build(Map<String, Object> config) {
122             return new HandlerWrapper() {
123                 @Override
124                 public HttpHandler wrap(HttpHandler handler) {
125                     return new EncodingHandler(handler, new ContentEncodingRepository()
126                             .addEncodingHandler("gzip"new GzipEncodingProvider(), 100)
127                             .addEncodingHandler("deflate"new DeflateEncodingProvider(), 10));
128                 }
129             };
130         }
131     }
132
133 }
134