001/*
002 * Copyright 2008-2011 Thomas Nichols.  http://blog.thomnichols.org
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * You are receiving this code free of charge, which represents many hours of
017 * effort from other individuals and corporations.  As a responsible member
018 * of the community, you are encouraged (but not required) to donate any
019 * enhancements or improvements back to the community under a similar open
020 * source license.  Thank you. -TMN
021 */
022package groovyx.net.http;
023
024import java.io.IOException;
025
026import org.apache.http.Header;
027import org.apache.http.HeaderElement;
028import org.apache.http.HttpEntity;
029import org.apache.http.HttpException;
030import org.apache.http.HttpRequest;
031import org.apache.http.HttpRequestInterceptor;
032import org.apache.http.HttpResponse;
033import org.apache.http.HttpResponseInterceptor;
034import org.apache.http.protocol.HttpContext;
035
036/**
037 * Base class for handing content-encoding.
038 * @author <a href='mailto:tomstrummer+httpbuilder@gmail.com'>Tom Nichols</a>
039 */
040public abstract class ContentEncoding {
041
042    public static final String ACCEPT_ENC_HDR = "Accept-Encoding";
043    public static final String CONTENT_ENC_HDR = "Content-Encoding";
044
045    protected abstract String getContentEncoding();
046    protected abstract HttpEntity wrapResponseEntity( HttpEntity raw );
047
048    public HttpRequestInterceptor getRequestInterceptor() {
049        return new RequestInterceptor();
050    }
051
052    public HttpResponseInterceptor getResponseInterceptor() {
053        return new ResponseInterceptor();
054    }
055
056    /**
057     * Enumeration of common content-encodings.
058     */
059    public static enum Type {
060        GZIP,
061        COMPRESS,
062        DEFLATE;
063
064        /** Prints the value as it should appear in an HTTP header */
065        @Override public String toString() {
066            return this.name().toLowerCase();
067        }
068    }
069
070    /**
071     * Request interceptor that adds the correct <code>Accept</code> header
072     * to the outgoing request.
073     * @author <a href='mailto:tomstrummer+httpbuilder@gmail.com'>Tom Nichols</a>
074     */
075    protected class RequestInterceptor implements HttpRequestInterceptor {
076        public void process( final HttpRequest req,
077                final HttpContext context ) throws HttpException, IOException {
078
079            // set the Accept-Encoding header:
080            String encoding = getContentEncoding();
081            if ( !req.containsHeader( ACCEPT_ENC_HDR ) )
082                req.addHeader( ACCEPT_ENC_HDR, encoding );
083
084            else {
085                StringBuilder values = new StringBuilder();
086                for ( Header h : req.getHeaders( ACCEPT_ENC_HDR ) )
087                    values.append( h.getValue() ).append( "," );
088
089                String encList = (!values.toString().contains( encoding )) ? values
090                        .append( encoding ).toString()
091                        : values.toString().substring( 0, values.lastIndexOf( "," ) );
092
093                req.setHeader( ACCEPT_ENC_HDR, encList );
094            }
095
096            //TODO compress request and add content-encoding header.
097        }
098    }
099
100    /**
101     * Response interceptor that filters the response stream to decode the
102     * compressed content before it is passed on to the parser.
103     * @author <a href='mailto:tomstrummer+httpbuilder@gmail.com'>Tom Nichols</a>
104     */
105    protected class ResponseInterceptor implements HttpResponseInterceptor {
106        public void process( final HttpResponse response, final HttpContext context )
107                throws HttpException, IOException {
108
109            if ( hasEncoding( response, getContentEncoding() ) )
110                response.setEntity( wrapResponseEntity( response.getEntity() ) );
111        }
112
113        protected boolean hasEncoding( final HttpResponse response, final String encoding ) {
114            HttpEntity entity = response.getEntity();
115            if ( entity == null ) return false;
116            Header ceHeader = entity.getContentEncoding();
117            if ( ceHeader == null ) return false;
118
119            HeaderElement[] codecs = ceHeader.getElements();
120            for ( int i = 0; i < codecs.length; i++ )
121                if ( encoding.equalsIgnoreCase( codecs[i].getName() ) )
122                    return true;
123
124            return false;
125        }
126    }
127}