blob: b36bea499053a55c699f3e098520cca1ad5c8969 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/*
* This class has been taken from Apache Harmony (http://harmony.apache.org/)
* and has been modified to work with OpenCMIS.
*/
package org.apache.chemistry.opencmis.client.bindings.spi.cookies;
import java.io.IOException;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConnectionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Cookie Manager.
*
* This implementation conforms to RFC 2965, section 3.3 with some RFC 6265
* extensions.
*/
public class CmisCookieManager implements Serializable {
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(CmisCookieManager.class.getName());
private static final String VERSION_ZERO_HEADER = "Set-cookie";
private static final String VERSION_ONE_HEADER = "Set-cookie2";
private final String sessionId;
private final CmisCookieStoreImpl store;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
/**
* Constructs a new cookie manager.
*/
public CmisCookieManager() {
this("<unknown>");
}
/**
* Constructs a new cookie manager.
*/
public CmisCookieManager(String sessionId) {
this.sessionId = sessionId;
store = new CmisCookieStoreImpl();
}
/**
* Searchs and gets all cookies in the cache by the specified uri in the
* request header.
*
* @param uri
* the specified uri to search for
* @param requestHeaders
* a list of request headers
* @return a map that record all such cookies, the map is unchangeable
*/
public Map<String, List<String>> get(String url, Map<String, List<String>> requestHeaders) {
if (url == null || requestHeaders == null) {
throw new IllegalArgumentException("URL or headers are null!");
}
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new CmisConnectionException(e.getMessage(), e);
}
lock.writeLock().lock();
try {
List<CmisHttpCookie> cookies = store.get(uri);
String uriPath = uri.getPath();
for (int i = 0; i < cookies.size(); i++) {
CmisHttpCookie cookie = cookies.get(i);
String cookiePath = cookie.getPath();
// if the uri's path does not path-match cookie's path, remove
// cookies from the list
if (cookiePath == null || uriPath.length() == 0 || !uriPath.startsWith(cookiePath)) {
cookies.remove(i);
}
}
Map<String, List<String>> map = getCookieMap(cookies, requestHeaders);
if (LOG.isDebugEnabled()) {
if (map != null && !map.isEmpty()) {
LOG.debug("Session {}: Setting cookies for URL {}: {}", sessionId, url,
map.get("Cookie") == null ? "" : map.get("Cookie").toString());
}
}
return map;
} finally {
lock.writeLock().unlock();
}
}
private static Map<String, List<String>> getCookieMap(List<CmisHttpCookie> cookies,
Map<String, List<String>> requestHeaders) {
if (cookies.isEmpty()) {
return Collections.emptyMap();
}
StringBuilder cookieHeaderStr = new StringBuilder();
for (CmisHttpCookie cookie : cookies) {
if (cookieHeaderStr.length() > 0) {
cookieHeaderStr.append("; ");
}
cookieHeaderStr.append(cookie.getName());
cookieHeaderStr.append('=');
cookieHeaderStr.append(cookie.getValue());
}
return Collections.singletonMap("Cookie", Collections.singletonList(cookieHeaderStr.toString()));
}
/**
* Sets cookies according to uri and responseHeaders
*
* @param uri
* the specified uri
* @param responseHeaders
* a list of request headers
* @throws IOException
* if some error of I/O operation occurs
*/
public void put(String url, Map<String, List<String>> responseHeaders) {
if (url == null || responseHeaders == null) {
throw new IllegalArgumentException("URL or headers are null!");
}
URI uri;
try {
uri = new URI(url);
} catch (URISyntaxException e) {
throw new CmisConnectionException(e.getMessage(), e);
}
lock.writeLock().lock();
try {
// parse and construct cookies according to the map
List<CmisHttpCookie> cookies = parseCookie(responseHeaders);
for (CmisHttpCookie cookie : cookies) {
if (cookie.getDomain() == null) {
cookie.setDomain(uri.getHost());
}
if (cookie.getPath() == null) {
cookie.setPath("/");
}
store.add(uri, cookie);
}
if (LOG.isDebugEnabled()) {
if (!cookies.isEmpty()) {
LOG.debug("Session {}: Retrieved cookies for URL {}: {}", sessionId, url, cookies.toString());
}
}
} finally {
lock.writeLock().unlock();
}
}
private static List<CmisHttpCookie> parseCookie(Map<String, List<String>> responseHeaders) {
List<CmisHttpCookie> cookies = new ArrayList<CmisHttpCookie>();
for (Map.Entry<String, List<String>> entry : responseHeaders.entrySet()) {
String key = entry.getKey();
// Only "Set-cookie" and "Set-cookie2" pair will be parsed
if (key != null && (key.equalsIgnoreCase(VERSION_ZERO_HEADER) || key.equalsIgnoreCase(VERSION_ONE_HEADER))) {
// parse list elements one by one
for (String cookieStr : entry.getValue()) {
try {
for (CmisHttpCookie cookie : CmisHttpCookie.parse(cookieStr)) {
cookies.add(cookie);
}
} catch (IllegalArgumentException e) {
// this string is invalid, jump to the next one.
}
}
}
}
return cookies;
}
/**
* Gets current cookie store.
*
* @return the cookie store currently used by cookie manager.
*/
public CmisCookieStoreImpl getCookieStore() {
return store;
}
}