Skip to content

Package: Hdr

Hdr

nameinstructionbranchcomplexitylinemethod
Hdr(String)
M: 5 C: 19
79%
M: 1 C: 1
50%
M: 1 C: 1
50%
M: 1 C: 6
86%
M: 0 C: 1
100%
Hdr(String, String)
M: 11 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
getName()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getValue()
M: 29 C: 46
61%
M: 14 C: 8
36%
M: 10 C: 2
17%
M: 5 C: 8
62%
M: 0 C: 1
100%

Coverage

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