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
30package sun.net.www;
31
32import java.io.*;
33import java.util.Collections;
34import java.util.Map;
35import java.util.HashMap;
36import java.util.List;
37import java.util.ArrayList;
38import java.util.Set;
39import java.util.Iterator;
40import 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). */
49public
50class 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}