1b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/* 2b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Copyright 2008 Netflix, Inc. 3b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 4b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Licensed under the Apache License, Version 2.0 (the "License"); 5b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * you may not use this file except in compliance with the License. 6b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * You may obtain a copy of the License at 7b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 8b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * http://www.apache.org/licenses/LICENSE-2.0 9b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 10b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Unless required by applicable law or agreed to in writing, software 11b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * distributed under the License is distributed on an "AS IS" BASIS, 12b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * See the License for the specific language governing permissions and 14b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * limitations under the License. 15b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 16b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 17b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpackage net.oauth.http; 18b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 19b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.IOException; 20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.InputStream; 21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URL; 22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.ArrayList; 23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Iterator; 24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.List; 25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Map; 26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.regex.Matcher; 27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.regex.Pattern; 28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.client.ExcerptInputStream; 29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/** 31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * An HTTP request or response. 32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author John Kristian 34b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide 35b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 36b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic class HttpMessage 37b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien{ 38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public HttpMessage() 40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this(null, null); 42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public HttpMessage(String method, URL url) 45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this(method, url, null); 47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public HttpMessage(String method, URL url, InputStream body) 50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.method = method; 52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.url = url; 53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien this.body = body; 54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String method; 57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public URL url; 58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final List<Map.Entry<String, String>> headers = new ArrayList<Map.Entry<String, String>>(); 59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected InputStream body = null; 60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Get the value of the last header of the given name. The name is 63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * case-insensitive. 64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final String getHeader(String name) 66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String value = null; 68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Map.Entry<String, String> header : headers) { 69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (equalsIgnoreCase(name, header.getKey())) { 70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien value = header.getValue(); 71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return value; 74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** 77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Remove all headers of the given name. The name is case insensitive. 78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * 79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @return the value of the last header with that name, or null to indicate 80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * there was no such header 81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */ 82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public String removeHeaders(String name) 83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String value = null; 85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien for (Iterator<Map.Entry<String, String>> i = headers.iterator(); i.hasNext();) { 86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Map.Entry<String, String> header = i.next(); 87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (equalsIgnoreCase(name, header.getKey())) { 88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien value = header.getValue(); 89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien i.remove(); 90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return value; 93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final String getContentCharset() 96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return getCharset(getHeader(CONTENT_TYPE)); 98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public final InputStream getBody() throws IOException 101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (body == null) { 103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien InputStream raw = openBody(); 104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (raw != null) { 105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien body = new ExcerptInputStream(raw); 106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return body; 109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien protected InputStream openBody() throws IOException 112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return null; 114b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 115b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 116b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** Put a description of this message and its origins into the given Map. */ 117b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public void dump(Map<String, Object> into) throws IOException 118b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 119b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 120b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 121b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static boolean equalsIgnoreCase(String x, String y) 122b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 123b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (x == null) 124b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return y == null; 125b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien else 126b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return x.equalsIgnoreCase(y); 127b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 128b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 129b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final String getCharset(String mimeType) 130b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien { 131b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (mimeType != null) { 132b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien Matcher m = CHARSET.matcher(mimeType); 133b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (m.find()) { 134b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien String charset = m.group(1); 135b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien if (charset.length() >= 2 && charset.charAt(0) == '"' 136b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien && charset.charAt(charset.length() - 1) == '"') { 137b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien charset = charset.substring(1, charset.length() - 1); 138b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien charset = charset.replace("\\\"", "\""); 139b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 140b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return charset; 141b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 142b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 143b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien return DEFAULT_CHARSET; 144b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien } 145b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 146b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** The name of a dump entry whose value is the HTTP request. */ 147b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String REQUEST = "HTTP request"; 148b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 149b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien /** The name of a dump entry whose value is the HTTP response. */ 150b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String RESPONSE = "HTTP response"; 151b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 152b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String ACCEPT_ENCODING = "Accept-Encoding"; 153b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String CONTENT_ENCODING = "Content-Encoding"; 154b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String CONTENT_LENGTH = "Content-Length"; 155b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String CONTENT_TYPE = "Content-Type"; 156b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien public static final String DEFAULT_CHARSET = "ISO-8859-1"; 157b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 158b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien private static final Pattern CHARSET = Pattern 159b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien .compile("; *charset *= *([^;\"]*|\"([^\"]|\\\\\")*\")(;|$)"); 160b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien 161b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien} 162