001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.client.protocol; 029 030import java.io.IOException; 031import java.util.List; 032 033import org.apache.commons.logging.Log; 034import org.apache.commons.logging.LogFactory; 035import org.apache.http.Header; 036import org.apache.http.HeaderIterator; 037import org.apache.http.HttpException; 038import org.apache.http.HttpResponse; 039import org.apache.http.HttpResponseInterceptor; 040import org.apache.http.annotation.Contract; 041import org.apache.http.annotation.ThreadingBehavior; 042import org.apache.http.client.CookieStore; 043import org.apache.http.cookie.Cookie; 044import org.apache.http.cookie.CookieOrigin; 045import org.apache.http.cookie.CookieSpec; 046import org.apache.http.cookie.MalformedCookieException; 047import org.apache.http.cookie.SM; 048import org.apache.http.protocol.HttpContext; 049import org.apache.http.util.Args; 050 051/** 052 * Response interceptor that populates the current {@link CookieStore} with data 053 * contained in response cookies received in the given the HTTP response. 054 * 055 * @since 4.0 056 */ 057@Contract(threading = ThreadingBehavior.IMMUTABLE) 058public class ResponseProcessCookies implements HttpResponseInterceptor { 059 060 private final Log log = LogFactory.getLog(getClass()); 061 062 public ResponseProcessCookies() { 063 super(); 064 } 065 066 @Override 067 public void process(final HttpResponse response, final HttpContext context) 068 throws HttpException, IOException { 069 Args.notNull(response, "HTTP request"); 070 Args.notNull(context, "HTTP context"); 071 072 final HttpClientContext clientContext = HttpClientContext.adapt(context); 073 074 // Obtain actual CookieSpec instance 075 final CookieSpec cookieSpec = clientContext.getCookieSpec(); 076 if (cookieSpec == null) { 077 this.log.debug("Cookie spec not specified in HTTP context"); 078 return; 079 } 080 // Obtain cookie store 081 final CookieStore cookieStore = clientContext.getCookieStore(); 082 if (cookieStore == null) { 083 this.log.debug("Cookie store not specified in HTTP context"); 084 return; 085 } 086 // Obtain actual CookieOrigin instance 087 final CookieOrigin cookieOrigin = clientContext.getCookieOrigin(); 088 if (cookieOrigin == null) { 089 this.log.debug("Cookie origin not specified in HTTP context"); 090 return; 091 } 092 HeaderIterator it = response.headerIterator(SM.SET_COOKIE); 093 processCookies(it, cookieSpec, cookieOrigin, cookieStore); 094 095 // see if the cookie spec supports cookie versioning. 096 if (cookieSpec.getVersion() > 0) { 097 // process set-cookie2 headers. 098 // Cookie2 will replace equivalent Cookie instances 099 it = response.headerIterator(SM.SET_COOKIE2); 100 processCookies(it, cookieSpec, cookieOrigin, cookieStore); 101 } 102 } 103 104 private void processCookies( 105 final HeaderIterator iterator, 106 final CookieSpec cookieSpec, 107 final CookieOrigin cookieOrigin, 108 final CookieStore cookieStore) { 109 while (iterator.hasNext()) { 110 final Header header = iterator.nextHeader(); 111 try { 112 final List<Cookie> cookies = cookieSpec.parse(header, cookieOrigin); 113 for (final Cookie cookie : cookies) { 114 try { 115 cookieSpec.validate(cookie, cookieOrigin); 116 cookieStore.addCookie(cookie); 117 118 if (this.log.isDebugEnabled()) { 119 this.log.debug("Cookie accepted [" + formatCooke(cookie) + "]"); 120 } 121 } catch (final MalformedCookieException ex) { 122 if (this.log.isWarnEnabled()) { 123 this.log.warn("Cookie rejected [" + formatCooke(cookie) + "] " 124 + ex.getMessage()); 125 } 126 } 127 } 128 } catch (final MalformedCookieException ex) { 129 if (this.log.isWarnEnabled()) { 130 this.log.warn("Invalid cookie header: \"" 131 + header + "\". " + ex.getMessage()); 132 } 133 } 134 } 135 } 136 137 private static String formatCooke(final Cookie cookie) { 138 final StringBuilder buf = new StringBuilder(); 139 buf.append(cookie.getName()); 140 buf.append("=\""); 141 String v = cookie.getValue(); 142 if (v != null) { 143 if (v.length() > 100) { 144 v = v.substring(0, 100) + "..."; 145 } 146 buf.append(v); 147 } 148 buf.append("\""); 149 buf.append(", version:"); 150 buf.append(Integer.toString(cookie.getVersion())); 151 buf.append(", domain:"); 152 buf.append(cookie.getDomain()); 153 buf.append(", path:"); 154 buf.append(cookie.getPath()); 155 buf.append(", expiry:"); 156 buf.append(cookie.getExpiryDate()); 157 return buf.toString(); 158 } 159 160}