001: package de.jwic.upload;
002:
003: import java.io.IOException;
004: import java.util.Enumeration;
005: import java.util.Vector;
006: import javax.servlet.http.HttpServletRequest;
007: import javax.servlet.ServletInputStream;
008:
009: /**
010: * Parst den Inhalt einer Multipart / Data Form
011: */
012:
013: public class ContentParser {
014:
015: private ServletInputStream in;
016: private String boundary;
017: private byte[] buf = new byte[8 * 1024];
018: private Content content;
019:
020: /**
021: * Parst den Inhalt einer Multipart/Data Form
022: */
023: public ContentParser(HttpServletRequest req, long maxSize)
024: throws IOException {
025:
026: // Überprüfe Inhalt auf enctype="multipart/form-data"
027: // Zugriff erfolgt auf zwei Wegen
028:
029: String sType = null;
030: String sType1 = req.getHeader("Content-Type");
031: String sType2 = req.getContentType();
032:
033: // Wenn einer von beiden Werten NULL ist, einfach den anderen nehmen.
034: if (sType1 == null && sType2 != null) {
035: sType = sType2;
036: } else if (sType2 == null && sType1 != null) {
037: sType = sType1;
038: }
039: // Wenn keiner von beiden NULL ist, den längeren nehmen.
040: else if (sType1 != null && sType2 != null) {
041: sType = (sType1.length() > sType2.length() ? sType1
042: : sType2);
043: }
044:
045: // Wenn beide NULL sind handelt es sich vermutlich um kein enctype="multipart/form-date"
046: if (sType == null
047: || !sType.toLowerCase().startsWith(
048: "multipart/form-data")) {
049: throw new IOException(
050: "Posted content type isn't multipart/form-data");
051: }
052:
053: // Überprüfen der Größe des Inhaltes.
054: int length = req.getContentLength();
055: if (length > maxSize) {
056: throw new IOException("Posted content length of " + length
057: + " exceeds limit of " + maxSize);
058: }
059:
060: // Ermitteln der Grenzlinie
061: boundary = extractBoundary(sType);
062: if (boundary == null) {
063: throw new IOException(
064: "Separation boundary was not specified");
065: }
066:
067: in = req.getInputStream();
068:
069: // Erste Zeile einlesen
070: String line = readLine();
071: if (line == null) {
072: throw new IOException("Corrupt form data: premature ending");
073: }
074:
075: // Ergebnis überprüfen ob boundary = Erstezeile
076: if (!line.startsWith(boundary)) {
077: throw new IOException(
078: "Corrupt form data: no leading boundary: " + line
079: + " != " + boundary);
080: }
081: }
082:
083: /**
084: * Ermittelt die Grenzlinie die die einzelnen Felder begrenzt
085: * Erstellungsdatum: (08.03.01 19:41:46)
086: * @param line java.lang.String
087: */
088: private String extractBoundary(String line) {
089:
090: int index = line.lastIndexOf("boundary=");
091: if (index == -1) {
092: return null;
093: }
094:
095: String bound = line.substring(index + 9);
096: if (bound.charAt(0) == '"') {
097: index = bound.lastIndexOf('"');
098: bound = bound.substring(1, index);
099: }
100:
101: bound = "--" + bound;
102:
103: return bound;
104: }
105:
106: /**
107: * Gibt den ContentType zurück
108: * Erstellungsdatum: (08.03.01 19:41:46)
109: * @param line java.lang.String
110: */
111: private String extractContentType(String line) throws IOException {
112: String contentType = null;
113: String origline = line;
114: line = origline.toLowerCase();
115:
116: if (line.startsWith("content-type")) {
117: int start = line.indexOf(" ");
118: if (start == -1) {
119: throw new IOException("Content type corrupt: "
120: + origline);
121: }
122: contentType = line.substring(start + 1);
123: } else if (line.length() != 0) {
124: throw new IOException("Malformed line after disposition: "
125: + origline);
126: }
127:
128: return contentType;
129: }
130:
131: /**
132: * Gibt die Inhaltsangaben zurück
133: * Erstellungsdatum: (08.03.01 19:41:46)
134: * @param line java.lang.String
135: */
136: private String[] extractDispositionInfo(String line)
137: throws IOException {
138:
139: String[] retval = new String[4];
140:
141: String origline = line;
142: line = origline.toLowerCase();
143:
144: // Lese "content disposition" und "form-data" ein.
145: int start = line.indexOf("content-disposition: ");
146: int end = line.indexOf(";");
147: if (start == -1 || end == -1) {
148: throw new IOException("Content disposition corrupt: "
149: + origline);
150: }
151: String disposition = line.substring(start + 21, end);
152: if (!disposition.equals("form-data")) {
153: throw new IOException("Invalid content disposition: "
154: + disposition);
155: }
156:
157: // Lese "name" ein.
158: start = line.indexOf("name=\"", end);
159: end = line.indexOf("\"", start + 7);
160: if (start == -1 || end == -1) {
161: throw new IOException("Content disposition corrupt: "
162: + origline);
163: }
164: String name = origline.substring(start + 6, end);
165:
166: // Lese "filename" ein, wenn vorhanden.
167: String filename = null;
168: String origname = null;
169: start = line.indexOf("filename=\"", end + 2);
170: end = line.indexOf("\"", start + 10);
171: if (start != -1 && end != -1) {
172: filename = origline.substring(start + 10, end);
173: origname = filename;
174: int slash = Math.max(filename.lastIndexOf('/'), filename
175: .lastIndexOf('\\'));
176: if (slash > -1) {
177: filename = filename.substring(slash + 1);
178: }
179: }
180:
181: //Befülle Rückgabe Array
182: retval[0] = disposition;
183: retval[1] = name;
184: retval[2] = filename;
185: retval[3] = origname;
186: return retval;
187: }
188:
189: /**
190: * Liest die nächste Zeile ein
191: * Erstellungsdatum: (08.03.01 19:41:46)
192: * @return java.lang.String
193: */
194: private String readLine() throws IOException {
195:
196: StringBuffer sbuf = new StringBuffer();
197: int result;
198: //String line;
199:
200: do {
201: result = in.readLine(buf, 0, buf.length);
202: if (result != -1) {
203: sbuf.append(new String(buf, 0, result, "ISO-8859-1"));
204: }
205:
206: } while (result == buf.length);
207:
208: if (sbuf.length() == 0) {
209: return null;
210: }
211:
212: sbuf.setLength(sbuf.length() - 2); // die letzten beiden Zeichen abschneiden \r\n
213: return sbuf.toString();
214: }
215:
216: /**
217: * Gibt den nächsten Inhalt / Feld zurück
218: * Erstellungsdatum: (08.03.01 19:41:46)
219: * @exception java.io.IOException
220: */
221:
222: public Content readNextContent() throws IOException {
223:
224: if (content != null) {
225: content.close();
226: content = null;
227: }
228:
229: Vector headers = new Vector();
230:
231: String line = readLine();
232: if (line == null) {
233: return null;
234: } else if (line.length() == 0) {
235: return null;
236: }
237:
238: headers.addElement(line);
239:
240: while ((line = readLine()) != null && (line.length() > 0)) {
241: headers.addElement(line);
242: }
243:
244: if (line == null) {
245: return null;
246: }
247:
248: String name = null;
249: String filename = null;
250: //String origname = null;
251: //String contentType = "text/plain"; // rfc1867 says this is the default
252:
253: //Content-Disposition und Content-Type auswerten
254: Enumeration en = headers.elements();
255: while (en.hasMoreElements()) {
256: String headerline = (String) en.nextElement();
257: if (headerline.toLowerCase().startsWith(
258: "content-disposition:")) {
259: String[] dispInfo = extractDispositionInfo(headerline);
260: name = dispInfo[1];
261: filename = dispInfo[2];
262: //origname = dispInfo[3];
263: } else if (headerline.toLowerCase().startsWith(
264: "content-type:")) {
265: String type = extractContentType(headerline);
266: if (type != null) {
267: //contentType = type;
268: }
269: }
270: }
271:
272: // Inhalt einlesen
273: if (filename == null) {
274: content = new Content(in, boundary, filename, name);
275: } else {
276: if (filename.equals(""))
277: filename = null;
278: content = new Content(in, boundary, filename, name);
279: }
280: return content;
281: }
282: }
|