History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/net/www/MessageHeader.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/net/www/MessageHeader.java+479−0
@@ -0,0 +1,479 @@
1+/*
2+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
3+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+ *
5+ * This code is free software; you can redistribute it and/or modify it
6+ * under the terms of the GNU General Public License version 2 only, as
7+ * published by the Free Software Foundation. Oracle designates this
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+/*-
27+ * news stream opener
28+ */
29+
30+package sun.net.www;
31+
32+import java.io.*;
33+import java.util.Collections;
34+import java.util.Map;
35+import java.util.HashMap;
36+import java.util.List;
37+import java.util.ArrayList;
38+import java.util.Set;
39+import java.util.Iterator;
40+import java.util.NoSuchElementException;
41+
42+/** An RFC 844 or MIME message header. Includes methods
43+ for parsing headers from incoming streams, fetching
44+ values, setting values, and printing headers.
45+ Key values of null are legal: they indicate lines in
46+ the header that don't have a valid key, but do have
47+ a value (this isn't legal according to the standard,
48+ but lines like this are everywhere). */
49+public
50+class MessageHeader {
51+ private String keys[];
52+ private String values[];
53+ private int nkeys;
54+
55+ public MessageHeader () {
56+ grow();
57+ }
58+
59+ public MessageHeader (InputStream is) throws java.io.IOException {
60+ parseHeader(is);
61+ }
62+
63+ /**
64+ * Reset a message header (all key/values removed)
65+ */
66+ public synchronized void reset() {
67+ keys = null;
68+ values = null;
69+ nkeys = 0;
70+ grow();
71+ }
72+
73+ /**
74+ * Find the value that corresponds to this key.
75+ * It finds only the first occurrence of the key.
76+ * @param k the key to find.
77+ * @return null if not found.
78+ */
79+ public synchronized String findValue(String k) {
80+ if (k == null) {
81+ for (int i = nkeys; --i >= 0;)
82+ if (keys[i] == null)
83+ return values[i];
84+ } else
85+ for (int i = nkeys; --i >= 0;) {
86+ if (k.equalsIgnoreCase(keys[i]))
87+ return values[i];
88+ }
89+ return null;
90+ }
91+
92+ // return the location of the key
93+ public synchronized int getKey(String k) {
94+ for (int i = nkeys; --i >= 0;)
95+ if ((keys[i] == k) ||
96+ (k != null && k.equalsIgnoreCase(keys[i])))
97+ return i;
98+ return -1;
99+ }
100+
101+ public synchronized String getKey(int n) {
102+ if (n < 0 || n >= nkeys) return null;
103+ return keys[n];
104+ }
105+
106+ public synchronized String getValue(int n) {
107+ if (n < 0 || n >= nkeys) return null;
108+ return values[n];
109+ }
110+
111+ /** Deprecated: Use multiValueIterator() instead.
112+ *
113+ * Find the next value that corresponds to this key.
114+ * It finds the first value that follows v. To iterate
115+ * over all the values of a key use:
116+ * <pre>
117+ * for(String v=h.findValue(k); v!=null; v=h.findNextValue(k, v)) {
118+ * ...
119+ * }
120+ * </pre>
121+ */
122+ public synchronized String findNextValue(String k, String v) {
123+ boolean foundV = false;
124+ if (k == null) {
125+ for (int i = nkeys; --i >= 0;)
126+ if (keys[i] == null)
127+ if (foundV)
128+ return values[i];
129+ else if (values[i] == v)
130+ foundV = true;
131+ } else
132+ for (int i = nkeys; --i >= 0;)
133+ if (k.equalsIgnoreCase(keys[i]))
134+ if (foundV)
135+ return values[i];
136+ else if (values[i] == v)
137+ foundV = true;
138+ return null;
139+ }
140+
141+ class HeaderIterator implements Iterator<String> {
142+ int index = 0;
143+ int next = -1;
144+ String key;
145+ boolean haveNext = false;
146+ Object lock;
147+
148+ public HeaderIterator (String k, Object lock) {
149+ key = k;
150+ this.lock = lock;
151+ }
152+ public boolean hasNext () {
153+ synchronized (lock) {
154+ if (haveNext) {
155+ return true;
156+ }
157+ while (index < nkeys) {
158+ if (key.equalsIgnoreCase (keys[index])) {
159+ haveNext = true;
160+ next = index++;
161+ return true;
162+ }
163+ index ++;
164+ }
165+ return false;
166+ }
167+ }
168+ public String next() {
169+ synchronized (lock) {
170+ if (haveNext) {
171+ haveNext = false;
172+ return values [next];
173+ }
174+ if (hasNext()) {
175+ return next();
176+ } else {
177+ throw new NoSuchElementException ("No more elements");
178+ }
179+ }
180+ }
181+ public void remove () {
182+ throw new UnsupportedOperationException ("remove not allowed");
183+ }
184+ }
185+
186+ /**
187+ * return an Iterator that returns all values of a particular
188+ * key in sequence
189+ */
190+ public Iterator<String> multiValueIterator (String k) {
191+ return new HeaderIterator (k, this);
192+ }
193+
194+ public synchronized Map<String, List<String>> getHeaders() {
195+ return getHeaders(null);
196+ }
197+
198+ public synchronized Map<String, List<String>> getHeaders(String[] excludeList) {
199+ return filterAndAddHeaders(excludeList, null);
200+ }
201+
202+ public synchronized Map<String, List<String>> filterAndAddHeaders(String[] excludeList, Map<String, List<String>> include) {
203+ boolean skipIt = false;
204+ Map<String, List<String>> m = new HashMap<String, List<String>>();
205+ for (int i = nkeys; --i >= 0;) {
206+ if (excludeList != null) {
207+ // check if the key is in the excludeList.
208+ // if so, don't include it in the Map.
209+ for (int j = 0; j < excludeList.length; j++) {
210+ if ((excludeList[j] != null) &&
211+ (excludeList[j].equalsIgnoreCase(keys[i]))) {
212+ skipIt = true;
213+ break;
214+ }
215+ }
216+ }
217+ if (!skipIt) {
218+ List<String> l = m.get(keys[i]);
219+ if (l == null) {
220+ l = new ArrayList<String>();
221+ m.put(keys[i], l);
222+ }
223+ l.add(values[i]);
224+ } else {
225+ // reset the flag
226+ skipIt = false;
227+ }
228+ }
229+
230+ if (include != null) {
231+ Iterator entries = include.entrySet().iterator();
232+ while (entries.hasNext()) {
233+ Map.Entry entry = (Map.Entry)entries.next();
234+ List l = (List)m.get(entry.getKey());
235+ if (l == null) {
236+ l = new ArrayList();
237+ m.put((String)entry.getKey(), l);
238+ }
239+ l.add(entry.getValue());
240+ }
241+ }
242+
243+ for (String key : m.keySet()) {
244+ m.put(key, Collections.unmodifiableList(m.get(key)));
245+ }
246+
247+ return Collections.unmodifiableMap(m);
248+ }
249+
250+ /** Prints the key-value pairs represented by this
251+ header. Also prints the RFC required blank line
252+ at the end. Omits pairs with a null key. */
253+ public synchronized void print(PrintStream p) {
254+ for (int i = 0; i < nkeys; i++)
255+ if (keys[i] != null) {
256+ p.print(keys[i] +
257+ (values[i] != null ? ": "+values[i]: "") + "\r\n");
258+ }
259+ p.print("\r\n");
260+ p.flush();
261+ }
262+
263+ /** Adds a key value pair to the end of the
264+ header. Duplicates are allowed */
265+ public synchronized void add(String k, String v) {
266+ grow();
267+ keys[nkeys] = k;
268+ values[nkeys] = v;
269+ nkeys++;
270+ }
271+
272+ /** Prepends a key value pair to the beginning of the
273+ header. Duplicates are allowed */
274+ public synchronized void prepend(String k, String v) {
275+ grow();
276+ for (int i = nkeys; i > 0; i--) {
277+ keys[i] = keys[i-1];
278+ values[i] = values[i-1];
279+ }
280+ keys[0] = k;
281+ values[0] = v;
282+ nkeys++;
283+ }
284+
285+ /** Overwrite the previous key/val pair at location 'i'
286+ * with the new k/v. If the index didn't exist before
287+ * the key/val is simply tacked onto the end.
288+ */
289+
290+ public synchronized void set(int i, String k, String v) {
291+ grow();
292+ if (i < 0) {
293+ return;
294+ } else if (i >= nkeys) {
295+ add(k, v);
296+ } else {
297+ keys[i] = k;
298+ values[i] = v;
299+ }
300+ }
301+
302+
303+ /** grow the key/value arrays as needed */
304+
305+ private void grow() {
306+ if (keys == null || nkeys >= keys.length) {
307+ String[] nk = new String[nkeys + 4];
308+ String[] nv = new String[nkeys + 4];
309+ if (keys != null)
310+ System.arraycopy(keys, 0, nk, 0, nkeys);
311+ if (values != null)
312+ System.arraycopy(values, 0, nv, 0, nkeys);
313+ keys = nk;
314+ values = nv;
315+ }
316+ }
317+
318+ /**
319+ * Remove the key from the header. If there are multiple values under
320+ * the same key, they are all removed.
321+ * Nothing is done if the key doesn't exist.
322+ * After a remove, the other pairs' order are not changed.
323+ * @param k the key to remove
324+ */
325+ public synchronized void remove(String k) {
326+ if(k == null) {
327+ for (int i = 0; i < nkeys; i++) {
328+ while (keys[i] == null && i < nkeys) {
329+ for(int j=i; j<nkeys-1; j++) {
330+ keys[j] = keys[j+1];
331+ values[j] = values[j+1];
332+ }
333+ nkeys--;
334+ }
335+ }
336+ } else {
337+ for (int i = 0; i < nkeys; i++) {
338+ while (k.equalsIgnoreCase(keys[i]) && i < nkeys) {
339+ for(int j=i; j<nkeys-1; j++) {
340+ keys[j] = keys[j+1];
341+ values[j] = values[j+1];
342+ }
343+ nkeys--;
344+ }
345+ }
346+ }
347+ }
348+
349+ /** Sets the value of a key. If the key already
350+ exists in the header, it's value will be
351+ changed. Otherwise a new key/value pair will
352+ be added to the end of the header. */
353+ public synchronized void set(String k, String v) {
354+ for (int i = nkeys; --i >= 0;)
355+ if (k.equalsIgnoreCase(keys[i])) {
356+ values[i] = v;
357+ return;
358+ }
359+ add(k, v);
360+ }
361+
362+ /** Set's the value of a key only if there is no
363+ * key with that value already.
364+ */
365+
366+ public synchronized void setIfNotSet(String k, String v) {
367+ if (findValue(k) == null) {
368+ add(k, v);
369+ }
370+ }
371+
372+ /** Convert a message-id string to canonical form (strips off
373+ leading and trailing <>s) */
374+ public static String canonicalID(String id) {
375+ if (id == null)
376+ return "";
377+ int st = 0;
378+ int len = id.length();
379+ boolean substr = false;
380+ int c;
381+ while (st < len && ((c = id.charAt(st)) == '<' ||
382+ c <= ' ')) {
383+ st++;
384+ substr = true;
385+ }
386+ while (st < len && ((c = id.charAt(len - 1)) == '>' ||
387+ c <= ' ')) {
388+ len--;
389+ substr = true;
390+ }
391+ return substr ? id.substring(st, len) : id;
392+ }
393+
394+ /** Parse a MIME header from an input stream. */
395+ public void parseHeader(InputStream is) throws java.io.IOException {
396+ synchronized (this) {
397+ nkeys = 0;
398+ }
399+ mergeHeader(is);
400+ }
401+
402+ /** Parse and merge a MIME header from an input stream. */
403+ public void mergeHeader(InputStream is) throws java.io.IOException {
404+ if (is == null)
405+ return;
406+ char s[] = new char[10];
407+ int firstc = is.read();
408+ while (firstc != '\n' && firstc != '\r' && firstc >= 0) {
409+ int len = 0;
410+ int keyend = -1;
411+ int c;
412+ boolean inKey = firstc > ' ';
413+ s[len++] = (char) firstc;
414+ parseloop:{
415+ while ((c = is.read()) >= 0) {
416+ switch (c) {
417+ case ':':
418+ if (inKey && len > 0)
419+ keyend = len;
420+ inKey = false;
421+ break;
422+ case '\t':
423+ c = ' ';
424+ case ' ':
425+ inKey = false;
426+ break;
427+ case '\r':
428+ case '\n':
429+ firstc = is.read();
430+ if (c == '\r' && firstc == '\n') {
431+ firstc = is.read();
432+ if (firstc == '\r')
433+ firstc = is.read();
434+ }
435+ if (firstc == '\n' || firstc == '\r' || firstc > ' ')
436+ break parseloop;
437+ /* continuation */
438+ c = ' ';
439+ break;
440+ }
441+ if (len >= s.length) {
442+ char ns[] = new char[s.length * 2];
443+ System.arraycopy(s, 0, ns, 0, len);
444+ s = ns;
445+ }
446+ s[len++] = (char) c;
447+ }
448+ firstc = -1;
449+ }
450+ while (len > 0 && s[len - 1] <= ' ')
451+ len--;
452+ String k;
453+ if (keyend <= 0) {
454+ k = null;
455+ keyend = 0;
456+ } else {
457+ k = String.copyValueOf(s, 0, keyend);
458+ if (keyend < len && s[keyend] == ':')
459+ keyend++;
460+ while (keyend < len && s[keyend] <= ' ')
461+ keyend++;
462+ }
463+ String v;
464+ if (keyend >= len)
465+ v = new String();
466+ else
467+ v = String.copyValueOf(s, keyend, len - keyend);
468+ add(k, v);
469+ }
470+ }
471+
472+ public synchronized String toString() {
473+ String result = super.toString() + nkeys + " pairs: ";
474+ for (int i = 0; i < keys.length && i < nkeys; i++) {
475+ result += "{"+keys[i]+": "+values[i]+"}";
476+ }
477+ return result;
478+ }
479+}