001: /*
002: * This file is part of PFIXCORE.
003: *
004: * PFIXCORE is free software; you can redistribute it and/or modify
005: * it under the terms of the GNU Lesser General Public License as published by
006: * the Free Software Foundation; either version 2 of the License, or
007: * (at your option) any later version.
008: *
009: * PFIXCORE is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU Lesser General Public License for more details.
013: *
014: * You should have received a copy of the GNU Lesser General Public License
015: * along with PFIXCORE; if not, write to the Free Software
016: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
017: *
018: */
019:
020: package de.schlund.pfixxml.multipart;
021:
022: import java.io.ByteArrayOutputStream;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.io.UnsupportedEncodingException;
026: import java.util.HashMap;
027: import java.util.Set;
028:
029: /**
030: * This class is a parser for message headers (as defined in RFC 822),
031: * especially for headers from form-based file uploads (as defined in RFC 1867).
032: * Due to the fact that current browsers don't encode non-ASCII characters
033: * (as they should do and as defined in RFC 1522), but send the raw bytes in
034: * the encoding of the page, this class decodes the bytes according to the specified
035: * encoding. Parsing is done by reading from an input stream and stopping
036: * when the end of the header section is reached or the stream ends.
037: *
038: * @author mleidig@schlund.de
039: */
040: public class RFC822Headers {
041:
042: static final byte CR = 0x0D;
043: static final byte LF = 0x0A;
044: static final byte[] CRLF = { CR, LF };
045:
046: static final String DEFAULT_ENCODING = "ISO-8859-1";
047:
048: String encoding;
049: HashMap<String, String[]> headers;
050:
051: public RFC822Headers(InputStream in, String encoding)
052: throws IOException {
053: this .encoding = encoding;
054: if (encoding == null)
055: this .encoding = DEFAULT_ENCODING;
056: headers = new HashMap<String, String[]>();
057: read(in);
058: }
059:
060: public Set<String> getHeaderNames() {
061: return headers.keySet();
062: }
063:
064: public String[] getHeader(String name) {
065: return headers.get(name);
066: }
067:
068: private void read(InputStream in) throws IOException {
069: ByteArrayOutputStream out = new ByteArrayOutputStream();
070: byte[] name = null;
071: boolean inName = true;
072: boolean eol = false;
073: boolean eoh = false;
074: int b = -1;
075: while (!eoh && (b = in.read()) != -1) {
076: if (b == CR) {
077: b = in.read();
078: if (b != LF)
079: throw new IOException(
080: "RFC822 clash: CR has to be followed by a LF.");
081: if (eol) {
082: if (name != null)
083: addHeader(name, out.toByteArray());
084: eoh = true;
085: }
086: eol = true;
087: } else {
088: if (eol) {
089: if (b == ' ' || b == '\t') {
090: out.write(CRLF);
091: out.write(b);
092: } else {
093: addHeader(name, out.toByteArray());
094: out.reset();
095: inName = true;
096: out.write(b);
097: }
098: } else if (inName) {
099: if (b == ':') {
100: name = out.toByteArray();
101: out.reset();
102: inName = false;
103: } else {
104: out.write(b);
105: }
106: } else {
107: out.write(b);
108: }
109: eol = false;
110: }
111: }
112: }
113:
114: private void addHeader(byte[] name, byte[] value)
115: throws UnsupportedEncodingException {
116: String nameStr = new String(name, encoding);
117: nameStr = nameStr.trim();
118: String valueStr = new String(value, encoding);
119: valueStr = valueStr.trim();
120: addHeader(nameStr, valueStr);
121: }
122:
123: public void addHeader(String name, String value) {
124: if (headers.containsKey(name)) {
125: String[] oldVals = headers.get(name);
126: String[] vals = new String[oldVals.length + 1];
127: for (int i = 0; i < oldVals.length; i++)
128: vals[i] = oldVals[i];
129: vals[vals.length - 1] = value;
130: headers.put(name, vals);
131: } else {
132: String[] vals = new String[] { value };
133: headers.put(name, vals);
134: }
135: }
136:
137: }
|