src/share/jaxws_classes/com/sun/xml/internal/org/jvnet/mimepull/InternetHeaders.java

changeset 286
f50545b5e2f1
child 368
0989ad8c0860
equal deleted inserted replaced
284:88b85470e72c 286:f50545b5e2f1
1 /*
2 * Copyright (c) 1997, 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 package com.sun.xml.internal.org.jvnet.mimepull;
27
28 import java.io.IOException;
29 import java.util.NoSuchElementException;
30 import java.util.List;
31
32 /**
33 * InternetHeaders is a utility class that manages RFC822 style
34 * headers. Given an RFC822 format message stream, it reads lines
35 * until the blank line that indicates end of header. The input stream
36 * is positioned at the start of the body. The lines are stored
37 * within the object and can be extracted as either Strings or
38 * {@link Header} objects. <p>
39 * <p/>
40 * This class is mostly intended for service providers. MimeMessage
41 * and MimeBody use this class for holding their headers. <p>
42 * <p/>
43 * <hr> <strong>A note on RFC822 and MIME headers</strong><p>
44 * <p/>
45 * RFC822 and MIME header fields <strong>must</strong> contain only
46 * US-ASCII characters. If a header contains non US-ASCII characters,
47 * it must be encoded as per the rules in RFC 2047. The MimeUtility
48 * class provided in this package can be used to to achieve this.
49 * Callers of the <code>setHeader</code>, <code>addHeader</code>, and
50 * <code>addHeaderLine</code> methods are responsible for enforcing
51 * the MIME requirements for the specified headers. In addition, these
52 * header fields must be folded (wrapped) before being sent if they
53 * exceed the line length limitation for the transport (1000 bytes for
54 * SMTP). Received headers may have been folded. The application is
55 * responsible for folding and unfolding headers as appropriate. <p>
56 *
57 * @author John Mani
58 * @author Bill Shannon
59 */
60 final class InternetHeaders {
61
62 private final FinalArrayList<hdr> headers = new FinalArrayList<hdr>();
63
64 /**
65 * Read and parse the given RFC822 message stream till the
66 * blank line separating the header from the body. Store the
67 * header lines inside this InternetHeaders object. <p>
68 * <p/>
69 * Note that the header lines are added into this InternetHeaders
70 * object, so any existing headers in this object will not be
71 * affected.
72 *
73 * @param lis RFC822 input stream
74 */
75 InternetHeaders(MIMEParser.LineInputStream lis) {
76 // Read header lines until a blank line. It is valid
77 // to have BodyParts with no header lines.
78 String line;
79 String prevline = null; // the previous header line, as a string
80 // a buffer to accumulate the header in, when we know it's needed
81 StringBuffer lineBuffer = new StringBuffer();
82
83 try {
84 //while ((line = lis.readLine()) != null) {
85 do {
86 line = lis.readLine();
87 if (line != null &&
88 (line.startsWith(" ") || line.startsWith("\t"))) {
89 // continuation of header
90 if (prevline != null) {
91 lineBuffer.append(prevline);
92 prevline = null;
93 }
94 lineBuffer.append("\r\n");
95 lineBuffer.append(line);
96 } else {
97 // new header
98 if (prevline != null)
99 addHeaderLine(prevline);
100 else if (lineBuffer.length() > 0) {
101 // store previous header first
102 addHeaderLine(lineBuffer.toString());
103 lineBuffer.setLength(0);
104 }
105 prevline = line;
106 }
107 } while (line != null && line.length() > 0);
108 } catch (IOException ioex) {
109 throw new MIMEParsingException("Error in input stream", ioex);
110 }
111 }
112
113 /**
114 * Return all the values for the specified header. The
115 * values are String objects. Returns <code>null</code>
116 * if no headers with the specified name exist.
117 *
118 * @param name header name
119 * @return array of header values, or null if none
120 */
121 List<String> getHeader(String name) {
122 // XXX - should we just step through in index order?
123 FinalArrayList<String> v = new FinalArrayList<String>(); // accumulate return values
124
125 int len = headers.size();
126 for( int i=0; i<len; i++ ) {
127 hdr h = (hdr) headers.get(i);
128 if (name.equalsIgnoreCase(h.name)) {
129 v.add(h.getValue());
130 }
131 }
132 return (v.size() == 0) ? null : v;
133 }
134
135 /**
136 * Return all the headers as an Enumeration of
137 * {@link Header} objects.
138 *
139 * @return Header objects
140 */
141 FinalArrayList<? extends Header> getAllHeaders() {
142 return headers; // conceptually it should be read-only, but for performance reason I'm not wrapping it here
143 }
144
145 /**
146 * Add an RFC822 header line to the header store.
147 * If the line starts with a space or tab (a continuation line),
148 * add it to the last header line in the list. <p>
149 * <p/>
150 * Note that RFC822 headers can only contain US-ASCII characters
151 *
152 * @param line raw RFC822 header line
153 */
154 void addHeaderLine(String line) {
155 try {
156 char c = line.charAt(0);
157 if (c == ' ' || c == '\t') {
158 hdr h = (hdr) headers.get(headers.size() - 1);
159 h.line += "\r\n" + line;
160 } else
161 headers.add(new hdr(line));
162 } catch (StringIndexOutOfBoundsException e) {
163 // line is empty, ignore it
164 return;
165 } catch (NoSuchElementException e) {
166 // XXX - vector is empty?
167 }
168 }
169
170 }
171
172 /*
173 * A private utility class to represent an individual header.
174 */
175
176 class hdr implements Header {
177
178 String name; // the canonicalized (trimmed) name of this header
179 // XXX - should name be stored in lower case?
180 String line; // the entire RFC822 header "line"
181
182 /*
183 * Constructor that takes a line and splits out
184 * the header name.
185 */
186 hdr(String l) {
187 int i = l.indexOf(':');
188 if (i < 0) {
189 // should never happen
190 name = l.trim();
191 } else {
192 name = l.substring(0, i).trim();
193 }
194 line = l;
195 }
196
197 /*
198 * Constructor that takes a header name and value.
199 */
200 hdr(String n, String v) {
201 name = n;
202 line = n + ": " + v;
203 }
204
205 /*
206 * Return the "name" part of the header line.
207 */
208 public String getName() {
209 return name;
210 }
211
212 /*
213 * Return the "value" part of the header line.
214 */
215 public String getValue() {
216 int i = line.indexOf(':');
217 if (i < 0)
218 return line;
219
220 int j;
221 if (name.equalsIgnoreCase("Content-Description")) {
222 // Content-Description should retain the folded whitespace after header unfolding -
223 // rf. RFC2822 section 2.2.3, rf. RFC2822 section 3.2.3
224 for (j = i + 1; j < line.length(); j++) {
225 char c = line.charAt(j);
226 if (!(/*c == ' ' ||*/c == '\t' || c == '\r' || c == '\n'))
227 break;
228 }
229 } else {
230 // skip whitespace after ':'
231 for (j = i + 1; j < line.length(); j++) {
232 char c = line.charAt(j);
233 if (!(c == ' ' || c == '\t' || c == '\r' || c == '\n'))
234 break;
235 }
236 }
237 return line.substring(j);
238 }
239 }

mercurial