001: // Copyright (C) 2003,2004,2005 by Object Mentor, Inc. All rights reserved.
002: // Released under the terms of the GNU General Public License version 2 or later.
003: package fitnesse.http;
004:
005: import java.util.*;
006: import java.net.URLEncoder;
007: import java.io.*;
008: import fitnesse.components.Base64;
009: import fitnesse.util.StreamReader;
010:
011: public class RequestBuilder {
012: private static final byte[] ENDL = "\r\n".getBytes();
013:
014: private String resource;
015:
016: private String method = "GET";
017:
018: private List bodyParts = new LinkedList();
019:
020: private HashMap headers = new HashMap();
021:
022: private HashMap inputs = new HashMap();
023:
024: private String host;
025:
026: private int port;
027:
028: private String boundary;
029:
030: private boolean isMultipart = false;
031:
032: private int bodyLength = 0;
033:
034: public RequestBuilder(String resource) {
035: this .resource = resource;
036: }
037:
038: public void setMethod(String method) {
039: this .method = method;
040: }
041:
042: public void addHeader(String key, String value) {
043: headers.put(key, value);
044: }
045:
046: public String getText() throws Exception {
047: ByteArrayOutputStream output = new ByteArrayOutputStream();
048: send(output);
049: return output.toString();
050: }
051:
052: private String buildRequestLine() throws Exception {
053: StringBuffer text = new StringBuffer();
054: text.append(method).append(" ").append(resource);
055: if (isGet()) {
056: String inputString = inputString();
057: if (inputString.length() > 0)
058: text.append("?").append(inputString);
059: }
060: text.append(" HTTP/1.1");
061: return text.toString();
062: }
063:
064: private boolean isGet() {
065: return method.equals("GET");
066: }
067:
068: public void send(OutputStream output) throws Exception {
069: output.write(buildRequestLine().getBytes("UTF-8"));
070: output.write(ENDL);
071: buildBody();
072: sendHeaders(output);
073: output.write(ENDL);
074: sendBody(output);
075: }
076:
077: private void sendHeaders(OutputStream output) throws Exception {
078: addHostHeader();
079: for (Iterator iterator = headers.keySet().iterator(); iterator
080: .hasNext();) {
081: String key = (String) iterator.next();
082: output.write((key + ": " + headers.get(key))
083: .getBytes("UTF-8"));
084: output.write(ENDL);
085: }
086: }
087:
088: private void buildBody() throws Exception {
089: if (!isMultipart) {
090: byte[] bytes = inputString().getBytes("UTF-8");
091: bodyParts.add(new ByteArrayInputStream(bytes));
092: bodyLength += bytes.length;
093: } else {
094: for (Iterator iterator = inputs.keySet().iterator(); iterator
095: .hasNext();) {
096: String name = (String) iterator.next();
097: Object value = inputs.get(name);
098: StringBuffer partBuffer = new StringBuffer();
099: partBuffer.append("--").append(getBoundary()).append(
100: "\r\n");
101: partBuffer.append(
102: "Content-Disposition: form-data; name=\"")
103: .append(name).append("\"").append("\r\n");
104: if (value instanceof InputStreamPart) {
105: InputStreamPart part = (InputStreamPart) value;
106: partBuffer.append("Content-Type: ").append(
107: part.contentType).append("\r\n");
108: partBuffer.append("\r\n");
109: addBodyPart(partBuffer.toString());
110: bodyParts.add(part.input);
111: bodyLength += part.size;
112: addBodyPart("\r\n");
113: } else {
114: partBuffer.append("Content-Type: text/plain")
115: .append("\r\n");
116: partBuffer.append("\r\n");
117: partBuffer.append(value);
118: partBuffer.append("\r\n");
119: addBodyPart(partBuffer.toString());
120: }
121: }
122: StringBuffer tail = new StringBuffer();
123: tail.append("--").append(getBoundary()).append("--")
124: .append("\r\n");
125: addBodyPart(tail.toString());
126: }
127: addHeader("Content-Length", bodyLength + "");
128: }
129:
130: private void addBodyPart(String input) throws Exception {
131: byte[] bytes = input.toString().getBytes("UTF-8");
132: bodyParts.add(new ByteArrayInputStream(bytes));
133: bodyLength += bytes.length;
134: }
135:
136: private void sendBody(OutputStream output) throws Exception {
137: for (Iterator iterator = bodyParts.iterator(); iterator
138: .hasNext();) {
139: InputStream input = (InputStream) iterator.next();
140:
141: StreamReader reader = new StreamReader(input);
142: while (!reader.isEof()) {
143: byte[] bytes = reader.readBytes(1000);
144: output.write(bytes);
145: }
146: }
147: }
148:
149: private void addHostHeader() {
150: if (host != null)
151: addHeader("Host", host + ":" + port);
152: else
153: addHeader("Host", "");
154: }
155:
156: public void addInput(String key, Object value) throws Exception {
157: inputs.put(key, value);
158: }
159:
160: public String inputString() throws Exception {
161: StringBuffer buffer = new StringBuffer();
162: boolean first = true;
163: for (Iterator iterator = inputs.keySet().iterator(); iterator
164: .hasNext();) {
165: String key = (String) iterator.next();
166: String value = (String) inputs.get(key);
167: if (!first)
168: buffer.append("&");
169: buffer.append(key).append("=").append(
170: URLEncoder.encode(value, "UTF-8"));
171: first = false;
172: }
173: return buffer.toString();
174: }
175:
176: public void addCredentials(String username, String password)
177: throws Exception {
178: String rawUserpass = username + ":" + password;
179: String userpass = Base64.encode(rawUserpass);
180: addHeader("Authorization", "Basic " + userpass);
181: }
182:
183: public void setHostAndPort(String host, int port) {
184: this .host = host;
185: this .port = port;
186: }
187:
188: public String getBoundary() {
189: if (boundary == null)
190: boundary = "----------" + new Random().nextInt()
191: + "BoUnDaRy";
192: return boundary;
193: }
194:
195: public void addInputAsPart(String name, Object content)
196: throws Exception {
197: multipart();
198: addInput(name, content);
199: }
200:
201: public void addInputAsPart(String name, InputStream input,
202: int size, String contentType) throws Exception {
203: addInputAsPart(name, new InputStreamPart(input, size,
204: contentType));
205: }
206:
207: private void multipart() {
208: if (!isMultipart) {
209: isMultipart = true;
210: setMethod("POST");
211: addHeader("Content-Type", "multipart/form-data; boundary="
212: + getBoundary());
213: }
214: }
215:
216: private static class InputStreamPart {
217: public InputStream input;
218:
219: public int size;
220:
221: public String contentType;
222:
223: public InputStreamPart(InputStream input, int size,
224: String contentType) {
225: this.input = input;
226: this.size = size;
227: this.contentType = contentType;
228: }
229: }
230: }
|