ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/tomcat/util/http/parser/Cookie.java

Path
ttomcat-1778514358873.zip-extract/apache-tomcat-11.0.18-src/java/org/apache/tomcat/util/http/parser/Cookie.java
Status
scanned
Type
file
Name
Cookie.java
Extension
.java
Programming language
Java
Mime type
text/plain
File type
ASCII text, with CRLF line terminators
Tag

      
    
Rootfs path

      
    
Size
10747 (10.5 KB)
MD5
da31eabd645c41b88460485a56ad6b80
SHA1
77d7fc1da987dec91c99b24767bbb1e885ccca9c
SHA256
107f423a5606f94a69834789e1b5e8a3012a8b4a2aa22f18188daa5b5dcb38ec
SHA512

      
    
SHA1_git
a64c41a859e3889aa707b9a4297bfa6b32b5c89a
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
Cookie.java | 10.5 KB |

/* * 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. */ package org.apache.tomcat.util.http.parser; import java.nio.charset.StandardCharsets; import org.apache.juli.logging.Log; import org.apache.juli.logging.LogFactory; import org.apache.tomcat.util.http.CookiesWithoutEquals; import org.apache.tomcat.util.http.ServerCookie; import org.apache.tomcat.util.http.ServerCookies; import org.apache.tomcat.util.log.UserDataHelper; import org.apache.tomcat.util.res.StringManager; /** * <p> * Cookie header parser based on RFC6265 * </p> * <p> * The parsing of cookies using RFC6265 is more relaxed that the specification in the following ways: * </p> * <ul> * <li>Values 0x80 to 0xFF are permitted in cookie-octet to support the use of UTF-8 in cookie values as used by HTML * 5.</li> * <li>For cookies without a value, the '=' is not required after the name as some browsers do not sent it.</li> * </ul> * <p> * Implementation note:<br> * This class has been carefully tuned. Before committing any changes, ensure that the TesterCookiePerformance unit test * continues to give results within 1% for the old and new parsers. * </p> */ public class Cookie { private static final Log log = LogFactory.getLog(Cookie.class); private static final UserDataHelper invalidCookieLog = new UserDataHelper(log); private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.http.parser"); private static final boolean[] isCookieOctet = new boolean[256]; private static final boolean[] isText = new boolean[256]; private static final byte[] EMPTY_BYTES = new byte[0]; private static final byte TAB_BYTE = (byte) 0x09; private static final byte SPACE_BYTE = (byte) 0x20; private static final byte QUOTE_BYTE = (byte) 0x22; private static final byte COMMA_BYTE = (byte) 0x2C; private static final byte SEMICOLON_BYTE = (byte) 0x3B; private static final byte EQUALS_BYTE = (byte) 0x3D; private static final byte SLASH_BYTE = (byte) 0x5C; private static final byte DEL_BYTE = (byte) 0x7F; static { // %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E (RFC6265) // %x80 to %xFF (UTF-8) for (int i = 0; i < 256; i++) { isCookieOctet[i] = !(i < 0x21 || i == QUOTE_BYTE || i == COMMA_BYTE || i == SEMICOLON_BYTE || i == SLASH_BYTE || i == DEL_BYTE); } for (int i = 0; i < 256; i++) { isText[i] = !(i < TAB_BYTE || (i > TAB_BYTE && i < SPACE_BYTE) || i == DEL_BYTE); } } private Cookie() { // Hide default constructor } /** * Parse byte array as cookie header. * * @param bytes Source * @param offset Start point in array * @param len Number of bytes to read * @param serverCookies Structure to store results * @param cookiesWithoutEquals How to handle a cookie name-value-pair that does not contain an equals character */ public static void parseCookie(byte[] bytes, int offset, int len, ServerCookies serverCookies, CookiesWithoutEquals cookiesWithoutEquals) { // ByteBuffer is used throughout this parser as it allows the byte[] // and position information to be easily passed between parsing methods ByteBuffer bb = new ByteBuffer(bytes, offset, len); boolean moreToProcess = true; while (moreToProcess) { skipLWS(bb); int start = bb.position(); ByteBuffer name = readToken(bb); ByteBuffer value = null; skipLWS(bb); SkipResult skipResult = skipByte(bb, EQUALS_BYTE); if (skipResult == SkipResult.FOUND) { skipLWS(bb); value = readCookieValueRfc6265(bb); if (value == null) { // Invalid cookie value. Skip to the next semicolon skipUntilSemiColon(bb); logInvalidHeader(start, bb); continue; } skipLWS(bb); } skipResult = skipByte(bb, SEMICOLON_BYTE); if (skipResult == SkipResult.FOUND) { // NO-OP } else if (skipResult == SkipResult.NOT_FOUND) { // Invalid cookie. Ignore it and skip to the next semicolon skipUntilSemiColon(bb); logInvalidHeader(start, bb); continue; } else { // SkipResult.EOF moreToProcess = false; } if (name.hasRemaining()) { if (value == null) { switch (cookiesWithoutEquals) { case IGNORE: { // This name-value-pair is a NO-OP break; } case NAME: { ServerCookie sc = serverCookies.addCookie(); sc.getName().setBytes(name.array(), name.position(), name.remaining()); sc.getValue().setBytes(EMPTY_BYTES, 0, EMPTY_BYTES.length); break; } } } else { ServerCookie sc = serverCookies.addCookie(); sc.getName().setBytes(name.array(), name.position(), name.remaining()); sc.getValue().setBytes(value.array(), value.position(), value.remaining()); } } } } private static void skipLWS(ByteBuffer bb) { while (bb.hasRemaining()) { byte b = bb.get(); if (b != TAB_BYTE && b != SPACE_BYTE) { bb.rewind(); break; } } } private static void skipUntilSemiColon(ByteBuffer bb) { while (bb.hasRemaining()) { if (bb.get() == SEMICOLON_BYTE) { break; } } } private static SkipResult skipByte(ByteBuffer bb, byte target) { if (!bb.hasRemaining()) { return SkipResult.EOF; } if (bb.get() == target) { return SkipResult.FOUND; } bb.rewind(); return SkipResult.NOT_FOUND; } /** * Similar to readCookieValue() but treats a comma as part of an invalid value. */ private static ByteBuffer readCookieValueRfc6265(ByteBuffer bb) { boolean quoted = false; int start = bb.position(); int end = bb.limit(); while (bb.hasRemaining()) { byte b = bb.get(); if (isCookieOctet[(b & 0xFF)]) { // NO-OP } else if (b == SEMICOLON_BYTE || b == SPACE_BYTE || b == TAB_BYTE) { end = bb.position() - 1; bb.position(end); break; } else if (b == QUOTE_BYTE && start == bb.position() - 1) { quoted = true; } else if (quoted && b == QUOTE_BYTE) { end = bb.position(); break; } else { // Invalid cookie return null; } } return new ByteBuffer(bb.bytes, start, end - start); } private static ByteBuffer readToken(ByteBuffer bb) { final int start = bb.position(); int end = bb.limit(); while (bb.hasRemaining()) { if (!HttpParser.isToken(bb.get())) { end = bb.position() - 1; bb.position(end); break; } } return new ByteBuffer(bb.bytes, start, end - start); } private static void logInvalidHeader(int start, ByteBuffer bb) { UserDataHelper.Mode logMode = invalidCookieLog.getNextMode(); if (logMode != null) { String headerValue = new String(bb.array(), start, bb.position() - start, StandardCharsets.UTF_8); String message = sm.getString("cookie.invalidCookieValue", headerValue); switch (logMode) { case INFO_THEN_DEBUG: message += sm.getString("cookie.fallToDebug"); //$FALL-THROUGH$ case INFO: log.info(message); break; case DEBUG: log.debug(message); } } } /** * Custom implementation that skips many of the safety checks in {@link java.nio.ByteBuffer}. */ private static class ByteBuffer { private final byte[] bytes; private final int limit; private int position; ByteBuffer(byte[] bytes, int offset, int len) { this.bytes = bytes; this.position = offset; this.limit = offset + len; } public int position() { return position; } public void position(int position) { this.position = position; } public int limit() { return limit; } public int remaining() { return limit - position; } public boolean hasRemaining() { return position < limit; } public byte get() { return bytes[position++]; } public void rewind() { position--; } public byte[] array() { return bytes; } // For debug purposes @Override public String toString() { return "position [" + position + "], limit [" + limit + "]"; } } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
11.23
Copyrights

      
    
Holders

      
    
Authors

      
    
License detections License expression License expression SPDX
apache_2_0-4bde3f57-78aa-4201-96bf-531cba09e7de apache-2.0 Apache-2.0
URL Start line End line
http://www.apache.org/licenses/LICENSE-2.0 9 9