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

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

      
    
Rootfs path

      
    
Size
17445 (17.0 KB)
MD5
2eb313e80c40e0518013e4e9008ba73c
SHA1
60b8aad24b40258b32a0e5ac3c41373e104c266f
SHA256
899590575b31947c28751fc5c02bc8628289896ea3d2fd05517fb6406d7aabc5
SHA512

      
    
SHA1_git
d61be6ac4deedbfc1f024869f22dee28ddd4ceb8
Is binary

      
    
Is text
True
Is archive

      
    
Is media

      
    
Is legal

      
    
Is manifest

      
    
Is readme

      
    
Is top level

      
    
Is key file

      
    
MimeHeaders.java | 17.0 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; import java.io.IOException; import java.io.PrintWriter; import java.io.StringWriter; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; import java.util.Locale; import java.util.Map; import java.util.Set; import org.apache.tomcat.util.buf.MessageBytes; import org.apache.tomcat.util.buf.StringUtils; import org.apache.tomcat.util.res.StringManager; /** * Memory-efficient repository for Mime Headers. When the object is recycled, it will keep the allocated headers[] and * all the MimeHeaderField - no GC is generated. * <p> * For input headers it is possible to use the MessageByte for Fields - so no GC will be generated. * <p> * The only garbage is generated when using the String for header names/values - this can't be avoided when the servlet * calls header methods, but is easy to avoid inside tomcat. The goal is to use _only_ MessageByte-based Fields, and * reduce to 0 the memory overhead of tomcat. * <p> * This class is used to contain standard internet message headers, used for SMTP (RFC822) and HTTP (RFC2068) messages * as well as for MIME (RFC 2045) applications such as transferring typed data and grouping related items in multipart * message bodies. * <p> * Message headers, as specified in RFC822, include a field name and a field body. Order has no semantic significance, * and several fields with the same name may exist. However, most fields do not (and should not) exist more than once in * a header. * <p> * Many kinds of field body must conform to a specified syntax, including the standard parenthesized comment syntax. * This class supports only two simple syntaxes, for dates and integers. * <p> * When processing headers, care must be taken to handle the case of multiple same-name fields correctly. The values of * such fields are only available as strings. They may be accessed by index (treating the header as an array of fields), * or by name (returning an array of string values). * <p> * Headers are first parsed and stored in the order they are received. This is based on the fact that most servlets will * not directly access all headers, and most headers are single-valued. (the alternative - a hash or similar data * structure - will add an overhead that is not needed in most cases) * <p> * Apache seems to be using a similar method for storing and manipulating headers. */ public class MimeHeaders { /** * Initial size - should be == average number of headers per request */ public static final int DEFAULT_HEADER_SIZE = 8; private static final StringManager sm = StringManager.getManager("org.apache.tomcat.util.http"); /** * The header fields. */ private MimeHeaderField[] headers = new MimeHeaderField[DEFAULT_HEADER_SIZE]; /** * The current number of header fields. */ private int count; /** * The limit on the number of header fields. */ private int limit = -1; /** * Creates a new MimeHeaders object using a default buffer size. */ public MimeHeaders() { // NO-OP } /** * Set limit on the number of header fields. * * @param limit The new limit */ public void setLimit(int limit) { this.limit = limit; if (limit > 0 && headers.length > limit && count < limit) { // shrink header list array MimeHeaderField[] tmp = new MimeHeaderField[limit]; System.arraycopy(headers, 0, tmp, 0, count); headers = tmp; } } /** * Clears all header fields. */ public void recycle() { for (int i = 0; i < count; i++) { headers[i].recycle(); } count = 0; } @Override public String toString() { StringWriter sw = new StringWriter(); PrintWriter pw = new PrintWriter(sw); pw.println("=== MimeHeaders ==="); Enumeration<String> e = names(); while (e.hasMoreElements()) { String n = e.nextElement(); Enumeration<String> ev = values(n); while (ev.hasMoreElements()) { pw.print(n); pw.print(" = "); pw.println(ev.nextElement()); } } return sw.toString(); } public Map<String,String> toMap() { if (count == 0) { return Collections.emptyMap(); } Map<String,String> result = new HashMap<>(); for (int i = 0; i < count; i++) { String name = headers[i].getName().toStringType(); String value = headers[i].getValue().toStringType(); result.merge(name, value, StringUtils::join); } return result; } public void filter(Set<String> allowedHeaders) { int j = -1; for (int i = 0; i < count; i++) { String name = headers[i].getName().toStringType(); if (allowedHeaders.contains(name.trim().toLowerCase(Locale.ENGLISH))) { ++j; if (j != i) { headers[j] = headers[i]; } } } count = ++j; } public void duplicate(MimeHeaders source) throws IOException { for (int i = 0; i < source.size(); i++) { MimeHeaderField mhf = createHeader(); mhf.getName().duplicate(source.getName(i)); mhf.getValue().duplicate(source.getValue(i)); } } // -------------------- Idx access to headers ---------- /** * @return the current number of header fields. */ public int size() { return count; } /** * @param n The header index * * @return the Nth header name, or null if there is no such header. This may be used to iterate through all header * fields. */ public MessageBytes getName(int n) { return n >= 0 && n < count ? headers[n].getName() : null; } /** * @param n The header index * * @return the Nth header value, or null if there is no such header. This may be used to iterate through all header * fields. */ public MessageBytes getValue(int n) { return n >= 0 && n < count ? headers[n].getValue() : null; } /** * Find the index of a header with the given name. * * @param name The header name * @param starting Index on which to start looking * * @return the header index */ public int findHeader(String name, int starting) { // We can use a hash - but it's not clear how much // benefit you can get - there is an overhead // and the number of headers is small (4-5 ?) // Another problem is that we'll pay the overhead // of constructing the hashtable // A custom search tree may be better for (int i = starting; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { return i; } } return -1; } // -------------------- -------------------- /** * Returns an enumeration of strings representing the header field names. Field names may appear multiple times in * this enumeration, indicating that multiple fields with that name exist in this header. * * @return the enumeration */ public Enumeration<String> names() { return new NamesEnumerator(this); } public Enumeration<String> values(String name) { return new ValuesEnumerator(this, name); } // -------------------- Adding headers -------------------- /** * Adds a partially constructed field to the header. This field has not had its name or value initialized. */ private MimeHeaderField createHeader() { if (limit > -1 && count >= limit) { throw new IllegalStateException(sm.getString("headers.maxCountFail", Integer.valueOf(limit))); } MimeHeaderField mh; int len = headers.length; if (count >= len) { // expand header list array int newLength = count * 2; if (limit > 0 && newLength > limit) { newLength = limit; } MimeHeaderField[] tmp = new MimeHeaderField[newLength]; System.arraycopy(headers, 0, tmp, 0, len); headers = tmp; } if ((mh = headers[count]) == null) { headers[count] = mh = new MimeHeaderField(); } count++; return mh; } /** * Create a new named header , return the MessageBytes container for the new value * * @param name The header name * * @return the message bytes container for the value */ public MessageBytes addValue(String name) { MimeHeaderField mh = createHeader(); mh.getName().setString(name); return mh.getValue(); } /** * Create a new named header using un-translated byte[]. The conversion to chars can be delayed until encoding is * known. * * @param b The header name bytes * @param startN Offset * @param len Length * * @return the message bytes container for the value */ public MessageBytes addValue(byte[] b, int startN, int len) { MimeHeaderField mhf = createHeader(); mhf.getName().setBytes(b, startN, len); return mhf.getValue(); } /** * Allow "set" operations, which removes all current values for this header. * * @param name The header name * * @return the message bytes container for the value */ public MessageBytes setValue(String name) { for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { for (int j = i + 1; j < count; j++) { if (headers[j].getName().equalsIgnoreCase(name)) { removeHeader(j--); } } return headers[i].getValue(); } } MimeHeaderField mh = createHeader(); mh.getName().setString(name); return mh.getValue(); } // -------------------- Getting headers -------------------- /** * Finds and returns a header field with the given name. If no such field exists, null is returned. If more than one * such field is in the header, an arbitrary one is returned. * * @param name The header name * * @return the value */ public MessageBytes getValue(String name) { for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { return headers[i].getValue(); } } return null; } /** * Finds and returns a unique header field with the given name. If no such field exists, null is returned. If the * specified header field is not unique then an {@link IllegalArgumentException} is thrown. * * @param name The header name * * @return the value if unique * * @throws IllegalArgumentException if the header has multiple values */ public MessageBytes getUniqueValue(String name) { MessageBytes result = null; for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { if (result == null) { result = headers[i].getValue(); } else { throw new IllegalArgumentException(); } } } return result; } public String getHeader(String name) { MessageBytes mh = getValue(name); return mh != null ? mh.toStringType() : null; } // -------------------- Removing -------------------- /** * Removes a header field with the specified name. Does nothing if such a field could not be found. * * @param name the name of the header field to be removed */ public void removeHeader(String name) { for (int i = 0; i < count; i++) { if (headers[i].getName().equalsIgnoreCase(name)) { removeHeader(i--); } } } /** * Reset, move to the end and then reduce count by 1. * * @param idx the index of the header to remove. */ public void removeHeader(int idx) { // Implementation note. This method must not change the order of the // remaining headers because, if there are multiple header values for // the same name, the order of those headers is significant. It is // simpler to retain order for all values than try to determine if there // are multiple header values for the same name. // Clear the header to remove MimeHeaderField mh = headers[idx]; mh.recycle(); // Move the remaining headers System.arraycopy(headers, idx + 1, headers, idx, count - idx - 1); // Place the removed header at the end headers[count - 1] = mh; // Reduce the count count--; } } /** * Enumerate the distinct header names. Each nextElement() is O(n) ( a comparison is done with all previous elements ). * This is less frequent than add() - we want to keep add O(1). */ class NamesEnumerator implements Enumeration<String> { private int pos; private final int size; private String next; private final MimeHeaders headers; NamesEnumerator(MimeHeaders headers) { this.headers = headers; pos = 0; size = headers.size(); findNext(); } private void findNext() { next = null; for (; pos < size; pos++) { next = headers.getName(pos).toStringType(); for (int j = 0; j < pos; j++) { if (headers.getName(j).equalsIgnoreCase(next)) { // duplicate. next = null; break; } } if (next != null) { // it's not a duplicate break; } } // next time findNext is called it will try the // next element pos++; } @Override public boolean hasMoreElements() { return next != null; } @Override public String nextElement() { String current = next; findNext(); return current; } } /** * Enumerate the values for a (possibly ) multiple value element. */ class ValuesEnumerator implements Enumeration<String> { private int pos; private final int size; private MessageBytes next; private final MimeHeaders headers; private final String name; ValuesEnumerator(MimeHeaders headers, String name) { this.name = name; this.headers = headers; pos = 0; size = headers.size(); findNext(); } private void findNext() { next = null; for (; pos < size; pos++) { MessageBytes n1 = headers.getName(pos); if (n1.equalsIgnoreCase(name)) { next = headers.getValue(pos); break; } } pos++; } @Override public boolean hasMoreElements() { return next != null; } @Override public String nextElement() { MessageBytes current = next; findNext(); return current.toStringType(); } } class MimeHeaderField { private final MessageBytes nameB = MessageBytes.newInstance(); private final MessageBytes valueB = MessageBytes.newInstance(); /** * Creates a new, uninitialized header field. */ MimeHeaderField() { // NO-OP } public void recycle() { nameB.recycle(); valueB.recycle(); } public MessageBytes getName() { return nameB; } public MessageBytes getValue() { return valueB; } @Override public String toString() { return nameB + ": " + valueB; } }
Detected license expression
apache-2.0
Detected license expression (SPDX)
Apache-2.0
Percentage of license text
6.28
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