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 org.forgerock.http.header.HeaderUtil.*; 021 022import java.nio.charset.Charset; 023import java.util.Collections; 024import java.util.List; 025import java.util.Map; 026 027import org.forgerock.http.protocol.Header; 028import org.forgerock.http.protocol.Message; 029 030/** 031 * Processes the <strong>{@code Content-Type}</strong> message header. For more 032 * information, see <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a> 033 * §14.17. 034 */ 035public class ContentTypeHeader extends Header { 036 037 /** 038 * Constructs a new header, initialized from the specified message. 039 * 040 * @param message 041 * The message to initialize the header from. 042 * @return The parsed header. 043 */ 044 public static ContentTypeHeader valueOf(final Message message) { 045 return valueOf(parseSingleValuedHeader(message, NAME)); 046 } 047 048 /** 049 * Constructs a new header, initialized from the specified string value. 050 * 051 * @param string 052 * The value to initialize the header from. 053 * @return The parsed header. 054 */ 055 public static ContentTypeHeader valueOf(final String string) { 056 List<String> parts = HeaderUtil.split(string, ';'); 057 if (parts.size() > 0) { 058 String type = parts.get(0); 059 final Map<String, String> parameters = HeaderUtil.parseParameters(parts); 060 String charset = parameters.get("charset"); 061 String boundary = parameters.get("boundary"); 062 return new ContentTypeHeader(type, charset, boundary); 063 } else { 064 return new ContentTypeHeader(null, null, null); 065 } 066 } 067 068 /** The name of this header. */ 069 public static final String NAME = "Content-Type"; 070 071 /** The type/sub-type of the message. */ 072 private final String type; 073 074 /** The character set used in encoding the message. */ 075 private final String charset; 076 077 /** The boundary value provided in multipart messages. */ 078 private final String boundary; 079 080 /** 081 * Constructs a new empty header whose type, charset, and boundary are all 082 * {@code null}. 083 */ 084 public ContentTypeHeader() { 085 this(null, null, null); 086 } 087 088 /** 089 * Constructs a new header with the provided parameters. 090 * 091 * @param type 092 * The type/sub-type of the message. 093 * @param charset 094 * The character set used in encoding the message. 095 * @param boundary 096 * The boundary value provided in multipart messages. 097 */ 098 public ContentTypeHeader(String type, String charset, String boundary) { 099 this.type = type; 100 this.charset = charset; 101 this.boundary = boundary; 102 } 103 104 /** 105 * Returns the media type of the underlying data or {@code null} if none 106 * specified. 107 * 108 * @return The media type of the underlying data or {@code null} if none 109 * specified. 110 */ 111 public String getType() { 112 return type; 113 } 114 115 /** 116 * Returns the character set encoding used to encode the message, or 117 * {@code null} if no character set was specified. 118 * 119 * @return The character set encoding used to encode the message or 120 * {@code null} if empty. 121 * @throws java.nio.charset.IllegalCharsetNameException 122 * if the given charset name is illegal. 123 * @throws java.nio.charset.UnsupportedCharsetException 124 * if no support for the named charset is available. 125 */ 126 public Charset getCharset() { 127 return charset != null ? Charset.forName(charset) : null; 128 } 129 130 /** 131 * Returns the encapsulation boundary or {@code null} if none specified. 132 * 133 * @return The encapsulation boundary or {@code null} if none specified. 134 */ 135 public String getBoundary() { 136 return boundary; 137 } 138 139 @Override 140 public String getName() { 141 return NAME; 142 } 143 144 @Override 145 public List<String> getValues() { 146 if (type == null || type.isEmpty()) { 147 return null; 148 } 149 StringBuilder sb = new StringBuilder(); 150 sb.append(type); 151 if (charset != null) { 152 sb.append("; charset=").append(charset); 153 } 154 if (boundary != null) { 155 sb.append("; boundary=").append(boundary); 156 } 157 return sb.length() > 0 ? Collections.singletonList(sb.toString()) : Collections.<String>emptyList(); 158 } 159 160 static class Factory extends AbstractSingleValuedHeaderFactory<ContentTypeHeader> { 161 162 @Override 163 public ContentTypeHeader parse(String value) { 164 return valueOf(value); 165 } 166 } 167}