001: package com.meterware.httpunit;
002:
003: /********************************************************************************************************************
004: * $Id: MimeEncodedMessageBody.java,v 1.15 2002/11/15 02:53:59 russgold Exp $
005: *
006: * Copyright (c) 2000-2001, Russell Gold
007: *
008: * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
009: * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
010: * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
011: * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
012: *
013: * The above copyright notice and this permission notice shall be included in all copies or substantial portions
014: * of the Software.
015: *
016: * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
017: * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
018: * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
019: * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
020: * DEALINGS IN THE SOFTWARE.
021: *
022: *******************************************************************************************************************/
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.io.OutputStream;
026:
027: /**
028: * A POST-method message body which is MIME-encoded. This is used when uploading files, and is selected when the enctype
029: * parameter of a form is set to "multi-part/form-data".
030: **/
031: class MimeEncodedMessageBody extends MessageBody {
032:
033: public MimeEncodedMessageBody(PostMethodWebRequest request) {
034: super (request);
035: }
036:
037: /**
038: * Returns the content type of this message body.
039: **/
040: String getContentType() {
041: return "multipart/form-data; boundary=" + BOUNDARY;
042: }
043:
044: /**
045: * Returns the request associated with this message body, cast to a POST request.
046: **/
047: PostMethodWebRequest getPostRequest() {
048: return (PostMethodWebRequest) getRequest();
049: }
050:
051: /**
052: * Transmits the body of this request as a sequence of bytes.
053: **/
054: void writeTo(OutputStream outputStream) throws IOException {
055: MimeEncoding encoding = new MimeEncoding(outputStream);
056: getRequest().getParameterHolder().recordParameters(encoding);
057: encoding.sendClose();
058: }
059:
060: private final static String BOUNDARY = "--HttpUnit-part0-aSgQ2M";
061: private final static byte[] CRLF = { 0x0d, 0x0A };
062:
063: private String encode(String string) {
064: char[] chars = string.toCharArray();
065: StringBuffer sb = new StringBuffer(chars.length + 20);
066: for (int i = 0; i < chars.length; i++) {
067: if (chars[i] == '\\') {
068: sb.append("\\\\"); // accomodate MS-DOS file paths ??? is this safe??
069: } else {
070: sb.append(chars[i]);
071: }
072: }
073: return sb.toString();
074: }
075:
076: private void writeLn(OutputStream os, String value, String encoding)
077: throws IOException {
078: os.write(value.getBytes(encoding));
079: os.write(CRLF);
080: }
081:
082: private void writeLn(OutputStream os, String value)
083: throws IOException {
084: writeLn(os, value, getRequest().getCharacterSet());
085: }
086:
087: class MimeEncoding implements ParameterProcessor {
088:
089: public MimeEncoding(OutputStream outputStream) {
090: _outputStream = outputStream;
091: }
092:
093: public void sendClose() throws IOException {
094: writeLn(_outputStream, "--" + BOUNDARY + "--");
095: }
096:
097: public void addParameter(String name, String value,
098: String characterSet) throws IOException {
099: if (name == null || name.length() == 0)
100: return;
101:
102: writeLn(_outputStream, "--" + BOUNDARY);
103: writeLn(_outputStream,
104: "Content-Disposition: form-data; name=\"" + name
105: + '"'); // XXX need to handle non-ascii names here
106: writeLn(_outputStream, "Content-Type: text/plain; charset="
107: + getRequest().getCharacterSet());
108: writeLn(_outputStream, "");
109: writeLn(_outputStream, fixLineEndings(value), getRequest()
110: .getCharacterSet());
111: }
112:
113: private final static char CR = 0x0D;
114: private final static char LF = 0x0A;
115:
116: private String fixLineEndings(String value) {
117: StringBuffer sb = new StringBuffer();
118: char[] chars = value.toCharArray();
119: for (int i = 0; i < chars.length; i++) {
120: if (chars[i] == CR
121: || (chars[i] == LF && (i == 0 || chars[i - 1] != CR))) {
122: sb.append(CR).append(LF);
123: } else {
124: sb.append(chars[i]);
125: }
126: }
127: return sb.toString();
128: }
129:
130: public void addFile(String name, UploadFileSpec spec)
131: throws IOException {
132: byte[] buffer = new byte[8 * 1024];
133:
134: writeLn(_outputStream, "--" + BOUNDARY);
135: writeLn(_outputStream,
136: "Content-Disposition: form-data; name=\""
137: + encode(name) + "\"; filename=\""
138: + encode(spec.getFileName()) + '"'); // XXX need to handle non-ascii names here
139: writeLn(_outputStream, "Content-Type: "
140: + spec.getContentType());
141: writeLn(_outputStream, "");
142:
143: InputStream in = spec.getInputStream();
144: int count = 0;
145: do {
146: _outputStream.write(buffer, 0, count);
147: count = in.read(buffer, 0, buffer.length);
148: } while (count != -1);
149:
150: in.close();
151: writeLn(_outputStream, "");
152: }
153:
154: private OutputStream _outputStream;
155: }
156:
157: }
|