8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.webkit.network; 27 28 import java.net.URI; 29 import java.text.ParseException; 30 import java.util.logging.Level; 31 import java.util.logging.Logger; 32 import java.util.regex.Matcher; 33 import java.util.regex.Pattern; 34 35 /** 36 * An RFC 6265-compliant cookie. 37 */ 38 final class Cookie { 39 40 private static final Logger logger = 41 Logger.getLogger(Cookie.class.getName()); 42 private static final Pattern IP_ADDRESS_PATTERN = Pattern.compile( 43 "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"); 44 45 46 private final String name; 47 private final String value; 48 private final long expiryTime; 49 private String domain; 50 private String path; 51 private ExtendedTime creationTime; 52 private long lastAccessTime; 53 private final boolean persistent; 54 private boolean hostOnly; 55 private final boolean secureOnly; 56 private final boolean httpOnly; 57 58 59 /** 60 * Creates a new {@code Cookie}. 61 */ 66 { 67 this.name = name; 68 this.value = value; 69 this.expiryTime = expiryTime; 70 this.domain = domain; 71 this.path = path; 72 this.creationTime = creationTime; 73 this.lastAccessTime = lastAccessTime; 74 this.persistent = persistent; 75 this.hostOnly = hostOnly; 76 this.secureOnly = secureOnly; 77 this.httpOnly = httpOnly; 78 } 79 80 81 /** 82 * Parses a {@code Set-Cookie} header string into a {@code Cookie} 83 * object. 84 */ 85 static Cookie parse(String setCookieString, ExtendedTime currentTime) { 86 logger.log(Level.FINEST, "setCookieString: [{0}]", setCookieString); 87 88 String[] items = setCookieString.split(";", -1); 89 90 String[] nameValuePair = items[0].split("=", 2); 91 if (nameValuePair.length != 2) { 92 logger.log(Level.FINEST, "Name-value pair string lacks '=', " 93 + "ignoring cookie"); 94 return null; 95 } 96 String name = nameValuePair[0].trim(); 97 String value = nameValuePair[1].trim(); 98 if (name.length() == 0) { 99 logger.log(Level.FINEST, "Name string is empty, ignoring cookie"); 100 return null; 101 } 102 103 Long expires = null; 104 Long maxAge = null; 105 String domain = null; 106 String path = null; 107 boolean secure = false; 108 boolean httpOnly = false; 109 110 for (int i = 1; i < items.length; i++) { 111 String[] terms = items[i].split("=", 2); 112 String attrName = terms[0].trim(); 113 String attrValue = (terms.length > 1 ? terms[1] : "").trim(); 114 115 try { 116 if ("Expires".equalsIgnoreCase(attrName)) { 117 expires = parseExpires(attrValue); 118 } else if ("Max-Age".equalsIgnoreCase(attrName)) { 119 maxAge = parseMaxAge(attrValue, currentTime.baseTime()); 120 } else if ("Domain".equalsIgnoreCase(attrName)) { 121 domain = parseDomain(attrValue); 122 } else if ("Path".equalsIgnoreCase(attrName)) { 123 path = parsePath(attrValue); 124 } else if ("Secure".equalsIgnoreCase(attrName)) { 125 secure = true; 126 } else if ("HttpOnly".equalsIgnoreCase(attrName)) { 127 httpOnly = true; 128 } else { 129 logger.log(Level.FINEST, "Unknown attribute: [{0}], " 130 + "ignoring", attrName); 131 } 132 } catch (ParseException ex) { 133 logger.log(Level.FINEST, "{0}, ignoring", ex.getMessage()); 134 } 135 } 136 137 long expiryTime; 138 boolean persistent; 139 if (maxAge != null) { 140 persistent = true; 141 expiryTime = maxAge; 142 } else if (expires != null) { 143 persistent = true; 144 expiryTime = expires; 145 } else { 146 persistent = false; 147 expiryTime = Long.MAX_VALUE; 148 } 149 150 if (domain == null) { 151 domain = ""; 152 } 153 154 Cookie result = new Cookie(name, value, expiryTime, domain, path, 155 currentTime, currentTime.baseTime(), persistent, false, 156 secure, httpOnly); 157 logger.log(Level.FINEST, "result: {0}", result); 158 return result; 159 } 160 161 /** 162 * Parses the value of the {@code Expires} attribute. 163 */ 164 private static long parseExpires(String attributeValue) 165 throws ParseException 166 { 167 try { 168 return Math.max(DateParser.parse(attributeValue), 0); 169 } catch (ParseException ex) { 170 throw new ParseException("Error parsing Expires attribute", 0); 171 } 172 } 173 174 /** 175 * Parses the value of the {@code Max-Age} attribute. 176 */ 177 private static long parseMaxAge(String attributeValue, long currentTime) | 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.webkit.network; 27 28 import com.sun.javafx.logging.PlatformLogger; 29 30 import java.net.URI; 31 import java.text.ParseException; 32 import java.util.regex.Matcher; 33 import java.util.regex.Pattern; 34 35 /** 36 * An RFC 6265-compliant cookie. 37 */ 38 final class Cookie { 39 40 private static final PlatformLogger logger = 41 PlatformLogger.getLogger(Cookie.class.getName()); 42 private static final Pattern IP_ADDRESS_PATTERN = Pattern.compile( 43 "(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})\\.(\\d{1,3})"); 44 45 46 private final String name; 47 private final String value; 48 private final long expiryTime; 49 private String domain; 50 private String path; 51 private ExtendedTime creationTime; 52 private long lastAccessTime; 53 private final boolean persistent; 54 private boolean hostOnly; 55 private final boolean secureOnly; 56 private final boolean httpOnly; 57 58 59 /** 60 * Creates a new {@code Cookie}. 61 */ 66 { 67 this.name = name; 68 this.value = value; 69 this.expiryTime = expiryTime; 70 this.domain = domain; 71 this.path = path; 72 this.creationTime = creationTime; 73 this.lastAccessTime = lastAccessTime; 74 this.persistent = persistent; 75 this.hostOnly = hostOnly; 76 this.secureOnly = secureOnly; 77 this.httpOnly = httpOnly; 78 } 79 80 81 /** 82 * Parses a {@code Set-Cookie} header string into a {@code Cookie} 83 * object. 84 */ 85 static Cookie parse(String setCookieString, ExtendedTime currentTime) { 86 logger.finest("setCookieString: [{0}]", setCookieString); 87 88 String[] items = setCookieString.split(";", -1); 89 90 String[] nameValuePair = items[0].split("=", 2); 91 if (nameValuePair.length != 2) { 92 logger.finest("Name-value pair string lacks '=', " 93 + "ignoring cookie"); 94 return null; 95 } 96 String name = nameValuePair[0].trim(); 97 String value = nameValuePair[1].trim(); 98 if (name.length() == 0) { 99 logger.finest("Name string is empty, ignoring cookie"); 100 return null; 101 } 102 103 Long expires = null; 104 Long maxAge = null; 105 String domain = null; 106 String path = null; 107 boolean secure = false; 108 boolean httpOnly = false; 109 110 for (int i = 1; i < items.length; i++) { 111 String[] terms = items[i].split("=", 2); 112 String attrName = terms[0].trim(); 113 String attrValue = (terms.length > 1 ? terms[1] : "").trim(); 114 115 try { 116 if ("Expires".equalsIgnoreCase(attrName)) { 117 expires = parseExpires(attrValue); 118 } else if ("Max-Age".equalsIgnoreCase(attrName)) { 119 maxAge = parseMaxAge(attrValue, currentTime.baseTime()); 120 } else if ("Domain".equalsIgnoreCase(attrName)) { 121 domain = parseDomain(attrValue); 122 } else if ("Path".equalsIgnoreCase(attrName)) { 123 path = parsePath(attrValue); 124 } else if ("Secure".equalsIgnoreCase(attrName)) { 125 secure = true; 126 } else if ("HttpOnly".equalsIgnoreCase(attrName)) { 127 httpOnly = true; 128 } else { 129 logger.finest("Unknown attribute: [{0}], " 130 + "ignoring", attrName); 131 } 132 } catch (ParseException ex) { 133 logger.finest("{0}, ignoring", ex.getMessage()); 134 } 135 } 136 137 long expiryTime; 138 boolean persistent; 139 if (maxAge != null) { 140 persistent = true; 141 expiryTime = maxAge; 142 } else if (expires != null) { 143 persistent = true; 144 expiryTime = expires; 145 } else { 146 persistent = false; 147 expiryTime = Long.MAX_VALUE; 148 } 149 150 if (domain == null) { 151 domain = ""; 152 } 153 154 Cookie result = new Cookie(name, value, expiryTime, domain, path, 155 currentTime, currentTime.baseTime(), persistent, false, 156 secure, httpOnly); 157 logger.finest("result: {0}", result); 158 return result; 159 } 160 161 /** 162 * Parses the value of the {@code Expires} attribute. 163 */ 164 private static long parseExpires(String attributeValue) 165 throws ParseException 166 { 167 try { 168 return Math.max(DateParser.parse(attributeValue), 0); 169 } catch (ParseException ex) { 170 throw new ParseException("Error parsing Expires attribute", 0); 171 } 172 } 173 174 /** 175 * Parses the value of the {@code Max-Age} attribute. 176 */ 177 private static long parseMaxAge(String attributeValue, long currentTime) |