/* * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ /*- * news stream opener */ package sun.net.www; import java.io.*;import java.util.Collections;import java.util.Map;import java.util.HashMap;import java.util.List;import java.util.ArrayList;import java.util.Set;import java.util.Iterator;import java.util.NoSuchElementException; /** An RFC 844 or MIME message header. Includes methods for parsing headers from incoming streams, fetching values, setting values, and printing headers. Key values of null are legal: they indicate lines in the header that don't have a valid key, but do have a value (this isn't legal according to the standard, but lines like this are everywhere). */publicclass MessageHeader { private String keys[]; private String values[]; private int nkeys; public MessageHeader () { grow(); } public MessageHeader (InputStream is) throws java.io.IOException { parseHeader(is); } /** * Reset a message header (all key/values removed) */ public synchronized void reset() { keys = null; values = null; nkeys = 0; grow(); } /** * Find the value that corresponds to this key. * It finds only the first occurrence of the key. * @param k the key to find. * @return null if not found. */ public synchronized String findValue(String k) { if (k == null) { for (int i = nkeys; --i >= 0;) if (keys[i] == null) return values[i]; } else for (int i = nkeys; --i >= 0;) { if (k.equalsIgnoreCase(keys[i])) return values[i]; } return null; } // return the location of the key public synchronized int getKey(String k) { for (int i = nkeys; --i >= 0;) if ((keys[i] == k) || (k != null && k.equalsIgnoreCase(keys[i]))) return i; return -1; } public synchronized String getKey(int n) { if (n < 0 || n >= nkeys) return null; return keys[n]; } public synchronized String getValue(int n) { if (n < 0 || n >= nkeys) return null; return values[n]; } /** Deprecated: Use multiValueIterator() instead. * * Find the next value that corresponds to this key. * It finds the first value that follows v. To iterate * over all the values of a key use: * <pre> * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) { * ... * } * </pre> */ public synchronized String findNextValue(String k, String v) { boolean foundV = false; if (k == null) { for (int i = nkeys; --i >= 0;) if (keys[i] == null) if (foundV) return values[i]; else if (values[i] == v) foundV = true; } else for (int i = nkeys; --i >= 0;) if (k.equalsIgnoreCase(keys[i])) if (foundV) return values[i]; else if (values[i] == v) foundV = true; return null; } class HeaderIterator implements Iterator<String> { int index = 0; int next = -1; String key; boolean haveNext = false; Object lock; public HeaderIterator (String k, Object lock) { key = k; this.lock = lock; } public boolean hasNext () { synchronized (lock) { if (haveNext) { return true; } while (index < nkeys) { if (key.equalsIgnoreCase (keys[index])) { haveNext = true; next = index++; return true; } index ++; } return false; } } public String next() { synchronized (lock) { if (haveNext) { haveNext = false; return values [next]; } if (hasNext()) { return next(); } else { throw new NoSuchElementException ("No more elements"); } } } public void remove () { throw new UnsupportedOperationException ("remove not allowed"); } } /** * return an Iterator that returns all values of a particular * key in sequence */ public Iterator<String> multiValueIterator (String k) { return new HeaderIterator (k, this); } public synchronized Map<String, List<String>> getHeaders() { return getHeaders(null); } public synchronized Map<String, List<String>> getHeaders(String[] excludeList) { return filterAndAddHeaders(excludeList, null); } public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>> include) { boolean skipIt = false; Map<String, List<String>> m = new HashMap<String, List<String>>(); for (int i = nkeys; --i >= 0;) { if (excludeList != null) { // check if the key is in the excludeList. // if so, don't include it in the Map. for (int j = 0; j < excludeList.length; j++) { if ((excludeList[j] != null) && (excludeList[j].equalsIgnoreCase(keys[i]))) { skipIt = true; break; } } } if (!skipIt) { List<String> l = m.get(keys[i]); if (l == null) { l = new ArrayList<String>(); m.put(keys[i], l); } l.add(values[i]); } else { // reset the flag skipIt = false; } } if (include != null) { Iterator entries = include.entrySet().iterator(); while (entries.hasNext()) { Map.Entry entry = (Map.Entry)entries.next(); List l = (List)m.get(entry.getKey()); if (l == null) { l = new ArrayList(); m.put((String)entry.getKey(), l); } l.add(entry.getValue()); } } for (String key : m.keySet()) { m.put(key, Collections.unmodifiableList(m.get(key))); } return Collections.unmodifiableMap(m); } /** Prints the key-value pairs represented by this header. Also prints the RFC required blank line at the end. Omits pairs with a null key. */ public synchronized void print(PrintStream p) { for (int i = 0; i < nkeys; i++) if (keys[i] != null) { p.print(keys[i] + (values[i] != null ? ": "+values[i]: "") + "\r\n"); } p.print("\r\n"); p.flush(); } /** Adds a key value pair to the end of the header. Duplicates are allowed */ public synchronized void add(String k, String v) { grow(); keys[nkeys] = k; values[nkeys] = v; nkeys++; } /** Prepends a key value pair to the beginning of the header. Duplicates are allowed */ public synchronized void prepend(String k, String v) { grow(); for (int i = nkeys; i > 0; i--) { keys[i] = keys[i-1]; values[i] = values[i-1]; } keys[0] = k; values[0] = v; nkeys++; } /** Overwrite the previous key/val pair at location 'i' * with the new k/v. If the index didn't exist before * the key/val is simply tacked onto the end. */ public synchronized void set(int i, String k, String v) { grow(); if (i < 0) { return; } else if (i >= nkeys) { add(k, v); } else { keys[i] = k; values[i] = v; } } /** grow the key/value arrays as needed */ private void grow() { if (keys == null || nkeys >= keys.length) { String[] nk = new String[nkeys + 4]; String[] nv = new String[nkeys + 4]; if (keys != null) System.arraycopy(keys, 0, nk, 0, nkeys); if (values != null) System.arraycopy(values, 0, nv, 0, nkeys); keys = nk; values = nv; } } /** * Remove the key from the header. If there are multiple values under * the same key, they are all removed. * Nothing is done if the key doesn't exist. * After a remove, the other pairs' order are not changed. * @param k the key to remove */ public synchronized void remove(String k) { if(k == null) { for (int i = 0; i < nkeys; i++) { while (keys[i] == null && i < nkeys) { for(int j=i; j<nkeys-1; j++) { keys[j] = keys[j+1]; values[j] = values[j+1]; } nkeys--; } } } else { for (int i = 0; i < nkeys; i++) { while (k.equalsIgnoreCase(keys[i]) && i < nkeys) { for(int j=i; j<nkeys-1; j++) { keys[j] = keys[j+1]; values[j] = values[j+1]; } nkeys--; } } } } /** Sets the value of a key. If the key already exists in the header, it's value will be changed. Otherwise a new key/value pair will be added to the end of the header. */ public synchronized void set(String k, String v) { for (int i = nkeys; --i >= 0;) if (k.equalsIgnoreCase(keys[i])) { values[i] = v; return; } add(k, v); } /** Set's the value of a key only if there is no * key with that value already. */ public synchronized void setIfNotSet(String k, String v) { if (findValue(k) == null) { add(k, v); } } /** Convert a message-id string to canonical form (strips off leading and trailing <>s) */ public static String canonicalID(String id) { if (id == null) return ""; int st = 0; int len = id.length(); boolean substr = false; int c; while (st < len && ((c = id.charAt(st)) == '<' || c <= ' ')) { st++; substr = true; } while (st < len && ((c = id.charAt(len - 1)) == '>' || c <= ' ')) { len--; substr = true; } return substr ? id.substring(st, len) : id; } /** Parse a MIME header from an input stream. */ public void parseHeader(InputStream is) throws java.io.IOException { synchronized (this) { nkeys = 0; } mergeHeader(is); } /** Parse and merge a MIME header from an input stream. */ public void mergeHeader(InputStream is) throws java.io.IOException { if (is == null) return; char s[] = new char[10]; int firstc = is.read(); while (firstc != '\n' && firstc != '\r' && firstc >= 0) { int len = 0; int keyend = -1; int c; boolean inKey = firstc > ' '; s[len++] = (char) firstc; parseloop:{ while ((c = is.read()) >= 0) { switch (c) { case ':': if (inKey && len > 0) keyend = len; inKey = false; break; case '\t': c = ' '; case ' ': inKey = false; break; case '\r': case '\n': firstc = is.read(); if (c == '\r' && firstc == '\n') { firstc = is.read(); if (firstc == '\r') firstc = is.read(); } if (firstc == '\n' || firstc == '\r' || firstc > ' ') break parseloop; /* continuation */ c = ' '; break; } if (len >= s.length) { char ns[] = new char[s.length * 2]; System.arraycopy(s, 0, ns, 0, len); s = ns; } s[len++] = (char) c; } firstc = -1; } while (len > 0 && s[len - 1] <= ' ') len--; String k; if (keyend <= 0) { k = null; keyend = 0; } else { k = String.copyValueOf(s, 0, keyend); if (keyend < len && s[keyend] == ':') keyend++; while (keyend < len && s[keyend] <= ' ') keyend++; } String v; if (keyend >= len) v = new String(); else v = String.copyValueOf(s, keyend, len - keyend); add(k, v); } } public synchronized String toString() { String result = super.toString() + nkeys + " pairs: "; for (int i = 0; i < keys.length && i < nkeys; i++) { result += "{"+keys[i]+": "+values[i]+"}"; } return result; }}
/*
* Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*-
* news stream opener
*/
package sun.net.www;
import java.io.*;
import java.util.Collections;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Set;
import java.util.Iterator;
import java.util.NoSuchElementException;
/** An RFC 844 or MIME message header. Includes methods
for parsing headers from incoming streams, fetching
values, setting values, and printing headers.
Key values of null are legal: they indicate lines in
the header that don't have a valid key, but do have
a value (this isn't legal according to the standard,
but lines like this are everywhere). */
public
class MessageHeader {
private String keys[];
private String values[];
private int nkeys;
public MessageHeader () {
grow();
}
public MessageHeader (InputStream is) throws java.io.IOException {
parseHeader(is);
}
/**
* Reset a message header (all key/values removed)
*/
public synchronized void reset() {
keys = null;
values = null;
nkeys = 0;
grow();
}
/**
* Find the value that corresponds to this key.
* It finds only the first occurrence of the key.
* @param k the key to find.
* @return null if not found.
*/
public synchronized String findValue(String k) {
if (k == null) {
for (int i = nkeys; --i >= 0;)
if (keys[i] == null)
return values[i];
} else
for (int i = nkeys; --i >= 0;) {
if (k.equalsIgnoreCase(keys[i]))
return values[i];
}
return null;
}
// return the location of the key
public synchronized int getKey(String k) {
for (int i = nkeys; --i >= 0;)
if ((keys[i] == k) ||
(k != null && k.equalsIgnoreCase(keys[i])))
return i;
return -1;
}
public synchronized String getKey(int n) {
if (n < 0 || n >= nkeys) return null;
return keys[n];
}
public synchronized String getValue(int n) {
if (n < 0 || n >= nkeys) return null;
return values[n];
}
/** Deprecated: Use multiValueIterator() instead.
*
* Find the next value that corresponds to this key.
* It finds the first value that follows v. To iterate
* over all the values of a key use:
* <pre>
* for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
* ...
* }
* </pre>
*/
public synchronized String findNextValue(String k, String v) {
boolean foundV = false;
if (k == null) {
for (int i = nkeys; --i >= 0;)
if (keys[i] == null)
if (foundV)
return values[i];
else if (values[i] == v)
foundV = true;
} else
for (int i = nkeys; --i >= 0;)
if (k.equalsIgnoreCase(keys[i]))
if (foundV)
return values[i];
else if (values[i] == v)
foundV = true;
return null;
}
class HeaderIterator implements Iterator<String> {
int index = 0;
int next = -1;
String key;
boolean haveNext = false;
Object lock;
public HeaderIterator (String k, Object lock) {
key = k;
this.lock = lock;
}
public boolean hasNext () {
synchronized (lock) {
if (haveNext) {
return true;
}
while (index < nkeys) {
if (key.equalsIgnoreCase (keys[index])) {
haveNext = true;
next = index++;
return true;
}
index ++;
}
return false;
}
}
public String next() {
synchronized (lock) {
if (haveNext) {
haveNext = false;
return values [next];
}
if (hasNext()) {
return next();
} else {
throw new NoSuchElementException ("No more elements");
}
}
}
public void remove () {
throw new UnsupportedOperationException ("remove not allowed");
}
}
/**
* return an Iterator that returns all values of a particular
* key in sequence
*/
public Iterator<String> multiValueIterator (String k) {
return new HeaderIterator (k, this);
}
public synchronized Map<String, List<String>> getHeaders() {
return getHeaders(null);
}
public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
return filterAndAddHeaders(excludeList, null);
}
public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>> include) {
boolean skipIt = false;
Map<String, List<String>> m = new HashMap<String, List<String>>();
for (int i = nkeys; --i >= 0;) {
if (excludeList != null) {
// check if the key is in the excludeList.
// if so, don't include it in the Map.
for (int j = 0; j < excludeList.length; j++) {
if ((excludeList[j] != null) &&
(excludeList[j].equalsIgnoreCase(keys[i]))) {
skipIt = true;
break;
}
}
}
if (!skipIt) {
List<String> l = m.get(keys[i]);
if (l == null) {
l = new ArrayList<String>();
m.put(keys[i], l);
}
l.add(values[i]);
} else {
// reset the flag
skipIt = false;
}
}
if (include != null) {
Iterator entries = include.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry)entries.next();
List l = (List)m.get(entry.getKey());
if (l == null) {
l = new ArrayList();
m.put((String)entry.getKey(), l);
}
l.add(entry.getValue());
}
}
for (String key : m.keySet()) {
m.put(key, Collections.unmodifiableList(m.get(key)));
}
return Collections.unmodifiableMap(m);
}
/** Prints the key-value pairs represented by this
header. Also prints the RFC required blank line
at the end. Omits pairs with a null key. */
public synchronized void print(PrintStream p) {
for (int i = 0; i < nkeys; i++)
if (keys[i] != null) {
p.print(keys[i] +
(values[i] != null ? ": "+values[i]: "") + "\r\n");
}
p.print("\r\n");
p.flush();
}
/** Adds a key value pair to the end of the
header. Duplicates are allowed */
public synchronized void add(String k, String v) {
grow();
keys[nkeys] = k;
values[nkeys] = v;
nkeys++;
}
/** Prepends a key value pair to the beginning of the
header. Duplicates are allowed */
public synchronized void prepend(String k, String v) {
grow();
for (int i = nkeys; i > 0; i--) {
keys[i] = keys[i-1];
values[i] = values[i-1];
}
keys[0] = k;
values[0] = v;
nkeys++;
}
/** Overwrite the previous key/val pair at location 'i'
* with the new k/v. If the index didn't exist before
* the key/val is simply tacked onto the end.
*/
public synchronized void set(int i, String k, String v) {
grow();
if (i < 0) {
return;
} else if (i >= nkeys) {
add(k, v);
} else {
keys[i] = k;
values[i] = v;
}
}
/** grow the key/value arrays as needed */
private void grow() {
if (keys == null || nkeys >= keys.length) {
String[] nk = new String[nkeys + 4];
String[] nv = new String[nkeys + 4];
if (keys != null)
System.arraycopy(keys, 0, nk, 0, nkeys);
if (values != null)
System.arraycopy(values, 0, nv, 0, nkeys);
keys = nk;
values = nv;
}
}
/**
* Remove the key from the header. If there are multiple values under
* the same key, they are all removed.
* Nothing is done if the key doesn't exist.
* After a remove, the other pairs' order are not changed.
* @param k the key to remove
*/
public synchronized void remove(String k) {
if(k == null) {
for (int i = 0; i < nkeys; i++) {
while (keys[i] == null && i < nkeys) {
for(int j=i; j<nkeys-1; j++) {
keys[j] = keys[j+1];
values[j] = values[j+1];
}
nkeys--;
}
}
} else {
for (int i = 0; i < nkeys; i++) {
while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
for(int j=i; j<nkeys-1; j++) {
keys[j] = keys[j+1];
values[j] = values[j+1];
}
nkeys--;
}
}
}
}
/** Sets the value of a key. If the key already
exists in the header, it's value will be
changed. Otherwise a new key/value pair will
be added to the end of the header. */
public synchronized void set(String k, String v) {
for (int i = nkeys; --i >= 0;)
if (k.equalsIgnoreCase(keys[i])) {
values[i] = v;
return;
}
add(k, v);
}
/** Set's the value of a key only if there is no
* key with that value already.
*/
public synchronized void setIfNotSet(String k, String v) {
if (findValue(k) == null) {
add(k, v);
}
}
/** Convert a message-id string to canonical form (strips off
leading and trailing <>s) */
public static String canonicalID(String id) {
if (id == null)
return "";
int st = 0;
int len = id.length();
boolean substr = false;
int c;
while (st < len && ((c = id.charAt(st)) == '<' ||
c <= ' ')) {
st++;
substr = true;
}
while (st < len && ((c = id.charAt(len - 1)) == '>' ||
c <= ' ')) {
len--;
substr = true;
}
return substr ? id.substring(st, len) : id;
}
/** Parse a MIME header from an input stream. */
public void parseHeader(InputStream is) throws java.io.IOException {
synchronized (this) {
nkeys = 0;
}
mergeHeader(is);
}
/** Parse and merge a MIME header from an input stream. */
public void mergeHeader(InputStream is) throws java.io.IOException {
if (is == null)
return;
char s[] = new char[10];
int firstc = is.read();
while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
int len = 0;
int keyend = -1;
int c;
boolean inKey = firstc > ' ';
s[len++] = (char) firstc;
parseloop:{
while ((c = is.read()) >= 0) {
switch (c) {
case ':':
if (inKey && len > 0)
keyend = len;
inKey = false;
break;
case '\t':
c = ' ';
case ' ':
inKey = false;
break;
case '\r':
case '\n':
firstc = is.read();
if (c == '\r' && firstc == '\n') {
firstc = is.read();
if (firstc == '\r')
firstc = is.read();
}
if (firstc == '\n' || firstc == '\r' || firstc > ' ')
break parseloop;
/* continuation */
c = ' ';
break;
}
if (len >= s.length) {
char ns[] = new char[s.length * 2];
System.arraycopy(s, 0, ns, 0, len);
s = ns;
}
s[len++] = (char) c;
}
firstc = -1;
}
while (len > 0 && s[len - 1] <= ' ')
len--;
String k;
if (keyend <= 0) {
k = null;
keyend = 0;
} else {
k = String.copyValueOf(s, 0, keyend);
if (keyend < len && s[keyend] == ':')
keyend++;
while (keyend < len && s[keyend] <= ' ')
keyend++;
}
String v;
if (keyend >= len)
v = new String();
else
v = String.copyValueOf(s, keyend, len - keyend);
add(k, v);
}
}
public synchronized String toString() {
String result = super.toString() + nkeys + " pairs: ";
for (int i = 0; i < keys.length && i < nkeys; i++) {
result += "{"+keys[i]+": "+values[i]+"}";
}
return result;
}
}