Wed, 31 Dec 2014 07:22:50 +0100
Correct previous dual key logic pending first delivery installment.
1 /*
2 * ====================================================================
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 * ====================================================================
20 *
21 * This software consists of voluntary contributions made by many
22 * individuals on behalf of the Apache Software Foundation. For more
23 * information on the Apache Software Foundation, please see
24 * <http://www.apache.org/>.
25 *
26 */
28 package ch.boye.httpclientandroidlib.impl.cookie;
30 import java.util.StringTokenizer;
32 import ch.boye.httpclientandroidlib.annotation.Immutable;
34 import ch.boye.httpclientandroidlib.cookie.ClientCookie;
35 import ch.boye.httpclientandroidlib.cookie.Cookie;
36 import ch.boye.httpclientandroidlib.cookie.CookieAttributeHandler;
37 import ch.boye.httpclientandroidlib.cookie.CookieOrigin;
38 import ch.boye.httpclientandroidlib.cookie.CookieRestrictionViolationException;
39 import ch.boye.httpclientandroidlib.cookie.MalformedCookieException;
40 import ch.boye.httpclientandroidlib.cookie.SetCookie;
41 import ch.boye.httpclientandroidlib.cookie.SetCookie2;
43 /**
44 * <tt>"Port"</tt> cookie attribute handler for RFC 2965 cookie spec.
45 *
46 * @since 4.0
47 */
48 @Immutable
49 public class RFC2965PortAttributeHandler implements CookieAttributeHandler {
51 public RFC2965PortAttributeHandler() {
52 super();
53 }
55 /**
56 * Parses the given Port attribute value (e.g. "8000,8001,8002")
57 * into an array of ports.
58 *
59 * @param portValue port attribute value
60 * @return parsed array of ports
61 * @throws MalformedCookieException if there is a problem in
62 * parsing due to invalid portValue.
63 */
64 private static int[] parsePortAttribute(final String portValue)
65 throws MalformedCookieException {
66 StringTokenizer st = new StringTokenizer(portValue, ",");
67 int[] ports = new int[st.countTokens()];
68 try {
69 int i = 0;
70 while(st.hasMoreTokens()) {
71 ports[i] = Integer.parseInt(st.nextToken().trim());
72 if (ports[i] < 0) {
73 throw new MalformedCookieException ("Invalid Port attribute.");
74 }
75 ++i;
76 }
77 } catch (NumberFormatException e) {
78 throw new MalformedCookieException ("Invalid Port "
79 + "attribute: " + e.getMessage());
80 }
81 return ports;
82 }
84 /**
85 * Returns <tt>true</tt> if the given port exists in the given
86 * ports list.
87 *
88 * @param port port of host where cookie was received from or being sent to.
89 * @param ports port list
90 * @return true returns <tt>true</tt> if the given port exists in
91 * the given ports list; <tt>false</tt> otherwise.
92 */
93 private static boolean portMatch(int port, int[] ports) {
94 boolean portInList = false;
95 for (int i = 0, len = ports.length; i < len; i++) {
96 if (port == ports[i]) {
97 portInList = true;
98 break;
99 }
100 }
101 return portInList;
102 }
104 /**
105 * Parse cookie port attribute.
106 */
107 public void parse(final SetCookie cookie, final String portValue)
108 throws MalformedCookieException {
109 if (cookie == null) {
110 throw new IllegalArgumentException("Cookie may not be null");
111 }
112 if (cookie instanceof SetCookie2) {
113 SetCookie2 cookie2 = (SetCookie2) cookie;
114 if (portValue != null && portValue.trim().length() > 0) {
115 int[] ports = parsePortAttribute(portValue);
116 cookie2.setPorts(ports);
117 }
118 }
119 }
121 /**
122 * Validate cookie port attribute. If the Port attribute was specified
123 * in header, the request port must be in cookie's port list.
124 */
125 public void validate(final Cookie cookie, final CookieOrigin origin)
126 throws MalformedCookieException {
127 if (cookie == null) {
128 throw new IllegalArgumentException("Cookie may not be null");
129 }
130 if (origin == null) {
131 throw new IllegalArgumentException("Cookie origin may not be null");
132 }
133 int port = origin.getPort();
134 if (cookie instanceof ClientCookie
135 && ((ClientCookie) cookie).containsAttribute(ClientCookie.PORT_ATTR)) {
136 if (!portMatch(port, cookie.getPorts())) {
137 throw new CookieRestrictionViolationException(
138 "Port attribute violates RFC 2965: "
139 + "Request port not found in cookie's port list.");
140 }
141 }
142 }
144 /**
145 * Match cookie port attribute. If the Port attribute is not specified
146 * in header, the cookie can be sent to any port. Otherwise, the request port
147 * must be in the cookie's port list.
148 */
149 public boolean match(final Cookie cookie, final CookieOrigin origin) {
150 if (cookie == null) {
151 throw new IllegalArgumentException("Cookie may not be null");
152 }
153 if (origin == null) {
154 throw new IllegalArgumentException("Cookie origin may not be null");
155 }
156 int port = origin.getPort();
157 if (cookie instanceof ClientCookie
158 && ((ClientCookie) cookie).containsAttribute(ClientCookie.PORT_ATTR)) {
159 if (cookie.getPorts() == null) {
160 // Invalid cookie state: port not specified
161 return false;
162 }
163 if (!portMatch(port, cookie.getPorts())) {
164 return false;
165 }
166 }
167 return true;
168 }
170 }