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-2014 ForgeRock AS. 016 */ 017 018package org.forgerock.openig.header; 019 020import java.io.IOException; 021import java.io.InputStream; 022import java.io.UnsupportedEncodingException; 023import java.util.ArrayList; 024import java.util.List; 025import java.util.ListIterator; 026 027import org.forgerock.openig.decoder.Decoder; 028import org.forgerock.openig.http.Message; 029 030/** 031 * Processes the <strong>{@code Content-Encoding}</strong> message header. For more information, see 032 * <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a> §14.11. 033 */ 034public class ContentEncodingHeader implements Header { 035 036 /** The name of the header that this object represents. */ 037 public static final String NAME = "Content-Encoding"; 038 039 /** The content-coding(s), in the order they are applied to the entity. */ 040 private final List<String> codings = new ArrayList<String>(); 041 042 /** 043 * Constructs a new empty header. 044 */ 045 public ContentEncodingHeader() { 046 } 047 048 /** 049 * Constructs a new header, initialized from the specified message. 050 * 051 * @param message the message to initialize the header from. 052 */ 053 public ContentEncodingHeader(Message<?> message) { 054 fromMessage(message); 055 } 056 057 /** 058 * Constructs a new header, initialized from the specified string value. 059 * 060 * @param string the value to initialize the header from. 061 */ 062 public ContentEncodingHeader(String string) { 063 fromString(string); 064 } 065 066 /** 067 * Returns an input stream that decodes the specified input stream, given the 068 * content-codings that are specified in the {@code codings} list. 069 * 070 * @param in the input stream to decode. 071 * @return an input stream that provides the decoded content. 072 * @throws IOException if an I/O exception occurs. 073 * @throws UnsupportedEncodingException if an unsupported content-encoding is specified. 074 */ 075 public InputStream decode(InputStream in) throws IOException, UnsupportedEncodingException { 076 // decode in the reverse order that encoding was applied 077 for (ListIterator<String> i = codings.listIterator(codings.size()); i.hasPrevious();) { 078 String name = i.previous(); 079 Decoder decoder = Decoder.SERVICES.get(name); 080 if (decoder == null) { 081 throw new UnsupportedEncodingException(name); 082 } 083 in = decoder.decode(in); 084 } 085 return in; 086 } 087 088 private void clear() { 089 codings.clear(); 090 } 091 092 /** 093 * Returns the content-coding(s). 094 * 095 * @return The list of the content-coding(s). 096 */ 097 public List<String> getCodings() { 098 return codings; 099 } 100 101 @Override 102 public String getKey() { 103 return NAME; 104 } 105 106 @Override 107 public void fromMessage(Message<?> message) { 108 if (message != null && message.getHeaders() != null) { 109 fromString(HeaderUtil.join(message.getHeaders().get(NAME), ',')); 110 } 111 } 112 113 @Override 114 public void fromString(String string) { 115 clear(); 116 if (string != null) { 117 codings.addAll(HeaderUtil.split(string, ',')); 118 } 119 } 120 121 @Override 122 public void toMessage(Message<?> message) { 123 String value = toString(); 124 if (value != null) { 125 message.getHeaders().putSingle(NAME, value); 126 } 127 } 128 129 @Override 130 public String toString() { 131 // will return null if empty 132 return HeaderUtil.join(codings, ','); 133 } 134 135 @Override 136 public boolean equals(Object o) { 137 return o == this 138 || (o instanceof ContentEncodingHeader 139 && codings.equals(((ContentEncodingHeader) o).codings)); 140 } 141 142 @Override 143 public int hashCode() { 144 return codings.hashCode(); 145 } 146}