001: /*
002: * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/methods/multipart/MultipartRequestEntity.java,v 1.1 2004/10/06 03:39:59 mbecke Exp $
003: * $Revision: 502647 $
004: * $Date: 2007-02-02 17:22:54 +0100 (Fri, 02 Feb 2007) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030: package org.apache.commons.httpclient.methods.multipart;
031:
032: import java.io.IOException;
033: import java.io.OutputStream;
034: import java.util.Random;
035:
036: import org.apache.commons.httpclient.methods.RequestEntity;
037: import org.apache.commons.httpclient.params.HttpMethodParams;
038: import org.apache.commons.httpclient.util.EncodingUtil;
039: import org.apache.commons.logging.Log;
040: import org.apache.commons.logging.LogFactory;
041:
042: /**
043: * Implements a request entity suitable for an HTTP multipart POST method.
044: * <p>
045: * The HTTP multipart POST method is defined in section 3.3 of
046: * <a href="http://www.ietf.org/rfc/rfc1867.txt">RFC1867</a>:
047: * <blockquote>
048: * The media-type multipart/form-data follows the rules of all multipart
049: * MIME data streams as outlined in RFC 1521. The multipart/form-data contains
050: * a series of parts. Each part is expected to contain a content-disposition
051: * header where the value is "form-data" and a name attribute specifies
052: * the field name within the form, e.g., 'content-disposition: form-data;
053: * name="xxxxx"', where xxxxx is the field name corresponding to that field.
054: * Field names originally in non-ASCII character sets may be encoded using
055: * the method outlined in RFC 1522.
056: * </blockquote>
057: * </p>
058: * <p>This entity is designed to be used in conjunction with the
059: * {@link org.apache.commons.httpclient.methods.PostMethod post method} to provide
060: * multipart posts. Example usage:</p>
061: * <pre>
062: * File f = new File("/path/fileToUpload.txt");
063: * PostMethod filePost = new PostMethod("http://host/some_path");
064: * Part[] parts = {
065: * new StringPart("param_name", "value"),
066: * new FilePart(f.getName(), f)
067: * };
068: * filePost.setRequestEntity(
069: * new MultipartRequestEntity(parts, filePost.getParams())
070: * );
071: * HttpClient client = new HttpClient();
072: * int status = client.executeMethod(filePost);
073: * </pre>
074: *
075: * @since 3.0
076: */
077: public class MultipartRequestEntity implements RequestEntity {
078:
079: private static final Log log = LogFactory
080: .getLog(MultipartRequestEntity.class);
081:
082: /** The Content-Type for multipart/form-data. */
083: private static final String MULTIPART_FORM_CONTENT_TYPE = "multipart/form-data";
084:
085: /**
086: * The pool of ASCII chars to be used for generating a multipart boundary.
087: */
088: private static byte[] MULTIPART_CHARS = EncodingUtil
089: .getAsciiBytes("-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ");
090:
091: /**
092: * Generates a random multipart boundary string.
093: * @return
094: */
095: private static byte[] generateMultipartBoundary() {
096: Random rand = new Random();
097: byte[] bytes = new byte[rand.nextInt(11) + 30]; // a random size from 30 to 40
098: for (int i = 0; i < bytes.length; i++) {
099: bytes[i] = MULTIPART_CHARS[rand
100: .nextInt(MULTIPART_CHARS.length)];
101: }
102: return bytes;
103: }
104:
105: /** The MIME parts as set by the constructor */
106: protected Part[] parts;
107:
108: private byte[] multipartBoundary;
109:
110: private HttpMethodParams params;
111:
112: /**
113: * Creates a new multipart entity containing the given parts.
114: * @param parts The parts to include.
115: * @param params The params of the HttpMethod using this entity.
116: */
117: public MultipartRequestEntity(Part[] parts, HttpMethodParams params) {
118: if (parts == null) {
119: throw new IllegalArgumentException("parts cannot be null");
120: }
121: if (params == null) {
122: throw new IllegalArgumentException("params cannot be null");
123: }
124: this .parts = parts;
125: this .params = params;
126: }
127:
128: /**
129: * Returns the MIME boundary string that is used to demarcate boundaries of
130: * this part. The first call to this method will implicitly create a new
131: * boundary string. To create a boundary string first the
132: * HttpMethodParams.MULTIPART_BOUNDARY parameter is considered. Otherwise
133: * a random one is generated.
134: *
135: * @return The boundary string of this entity in ASCII encoding.
136: */
137: protected byte[] getMultipartBoundary() {
138: if (multipartBoundary == null) {
139: String temp = (String) params
140: .getParameter(HttpMethodParams.MULTIPART_BOUNDARY);
141: if (temp != null) {
142: multipartBoundary = EncodingUtil.getAsciiBytes(temp);
143: } else {
144: multipartBoundary = generateMultipartBoundary();
145: }
146: }
147: return multipartBoundary;
148: }
149:
150: /**
151: * Returns <code>true</code> if all parts are repeatable, <code>false</code> otherwise.
152: * @see org.apache.commons.httpclient.methods.RequestEntity#isRepeatable()
153: */
154: public boolean isRepeatable() {
155: for (int i = 0; i < parts.length; i++) {
156: if (!parts[i].isRepeatable()) {
157: return false;
158: }
159: }
160: return true;
161: }
162:
163: /* (non-Javadoc)
164: * @see org.apache.commons.httpclient.methods.RequestEntity#writeRequest(java.io.OutputStream)
165: */
166: public void writeRequest(OutputStream out) throws IOException {
167: Part.sendParts(out, parts, getMultipartBoundary());
168: }
169:
170: /* (non-Javadoc)
171: * @see org.apache.commons.httpclient.methods.RequestEntity#getContentLength()
172: */
173: public long getContentLength() {
174: try {
175: return Part.getLengthOfParts(parts, getMultipartBoundary());
176: } catch (Exception e) {
177: log
178: .error(
179: "An exception occurred while getting the length of the parts",
180: e);
181: return 0;
182: }
183: }
184:
185: /* (non-Javadoc)
186: * @see org.apache.commons.httpclient.methods.RequestEntity#getContentType()
187: */
188: public String getContentType() {
189: StringBuffer buffer = new StringBuffer(
190: MULTIPART_FORM_CONTENT_TYPE);
191: buffer.append("; boundary=");
192: buffer.append(EncodingUtil
193: .getAsciiString(getMultipartBoundary()));
194: return buffer.toString();
195: }
196:
197: }
|