001/* 002 * The contents of this file are subject to the terms of the Common Development and 003 * Distribution License (the License). You may not use this file except in compliance with the 004 * License. 005 * 006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007 * specific language governing permission and limitations under the License. 008 * 009 * When distributing Covered Software, include this CDDL Header Notice in each file and include 010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011 * Header, with the fields enclosed by brackets [] replaced by your own identifying 012 * information: "Portions Copyright [year] [name of copyright owner]". 013 * 014 * Copyright 2010–2011 ApexIdentity Inc. 015 * Portions Copyright 2011-2015 ForgeRock AS. 016 */ 017 018package org.forgerock.http.header; 019 020import static java.util.Collections.*; 021import static org.forgerock.http.header.HeaderUtil.*; 022 023import java.io.IOException; 024import java.io.InputStream; 025import java.io.UnsupportedEncodingException; 026import java.util.ArrayList; 027import java.util.Collections; 028import java.util.List; 029import java.util.ListIterator; 030 031import org.forgerock.http.decoder.Decoder; 032import org.forgerock.http.protocol.Header; 033import org.forgerock.http.protocol.Message; 034 035/** 036 * Processes the <strong>{@code Content-Encoding}</strong> message header. For 037 * more information, see <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 038 * 2616</a> §14.11. 039 */ 040public class ContentEncodingHeader extends Header { 041 /** The name of this header. */ 042 public static final String NAME = "Content-Encoding"; 043 044 /** The content coding, in the order they are applied to the entity. */ 045 private final List<String> codings; 046 047 /** 048 * Constructs a new empty header. 049 */ 050 public ContentEncodingHeader() { 051 this(new ArrayList<String>(1)); 052 } 053 054 /** 055 * Constructs a new header with the provided content encodings. 056 * 057 * @param codings 058 * The content encodings. 059 */ 060 public ContentEncodingHeader(final List<String> codings) { 061 this.codings = codings; 062 } 063 064 /** 065 * Constructs a new header, initialized from the specified message. 066 * 067 * @param message 068 * The message to initialize the header from. 069 * @return The parsed header. 070 */ 071 public static ContentEncodingHeader valueOf(final Message message) { 072 return new ContentEncodingHeader(parseMultiValuedHeader(message, NAME)); 073 } 074 075 /** 076 * Constructs a new header, initialized from the specified string value. 077 * 078 * @param string 079 * The value to initialize the header from. 080 * @return The parsed header. 081 */ 082 public static ContentEncodingHeader valueOf(final String string) { 083 return new ContentEncodingHeader(parseMultiValuedHeader(string)); 084 } 085 086 /** 087 * Returns an input stream that decodes the specified input stream, given 088 * the content-codings that are specified in the {@code codings} list. 089 * 090 * @param in 091 * the input stream to decode. 092 * @return an input stream that provides the decoded content. 093 * @throws IOException 094 * if an I/O exception occurs. 095 * @throws UnsupportedEncodingException 096 * if an unsupported content-encoding is specified. 097 */ 098 public InputStream decode(InputStream in) throws IOException { 099 // decode in the reverse order that encoding was applied 100 for (ListIterator<String> i = codings.listIterator(codings.size()); i.hasPrevious();) { 101 String name = i.previous(); 102 Decoder decoder = Decoder.SERVICES.get(name); 103 if (decoder == null) { 104 throw new UnsupportedEncodingException(name); 105 } 106 in = decoder.decode(in); 107 } 108 return in; 109 } 110 111 /** 112 * Returns the list of content codings. 113 * 114 * @return The list of content codings. 115 */ 116 public List<String> getCodings() { 117 return codings; 118 } 119 120 @Override 121 public String getName() { 122 return NAME; 123 } 124 125 @Override 126 public List<String> getValues() { 127 // will return null if empty 128 final String joined = HeaderUtil.join(codings, ','); 129 return joined == null ? Collections.<String>emptyList() : singletonList(joined); 130 } 131 132 static class Factory extends HeaderFactory<ContentEncodingHeader> { 133 134 @Override 135 public ContentEncodingHeader parse(String value) { 136 return valueOf(value); 137 } 138 139 @Override 140 public ContentEncodingHeader parse(List<String> values) { 141 return valueOf(join(values, ',')); 142 } 143 } 144}