001: package com.meterware.pseudoserver;
002:
003: /********************************************************************************************************************
004: * $Id: WebResource.java,v 1.10 2005/03/06 20:20:10 russgold Exp $
005: *
006: * Copyright (c) 2000-2005, 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 com.meterware.httpunit.HttpUnitUtils;
024:
025: import java.io.OutputStream;
026: import java.io.IOException;
027: import java.io.InputStream;
028: import java.io.UnsupportedEncodingException;
029: import java.net.HttpURLConnection;
030: import java.util.Vector;
031:
032: /**
033: * A resource to be returned from the simulated server.
034: **/
035: public class WebResource {
036:
037: final static String DEFAULT_CONTENT_TYPE = "text/html";
038:
039: final static String DEFAULT_CHARACTER_SET = "iso-8859-1";
040: private boolean _closesConnection;
041:
042: public WebResource(String contents) {
043: this (contents, DEFAULT_CONTENT_TYPE);
044: }
045:
046: public WebResource(String contents, String contentType) {
047: this (contents, contentType, HttpURLConnection.HTTP_OK);
048: }
049:
050: public WebResource(byte[] contents, String contentType) {
051: this (contents, contentType, HttpURLConnection.HTTP_OK);
052: }
053:
054: public void addHeader(String header) {
055: _headers.addElement(header);
056: if (header.toLowerCase().startsWith("content-type"))
057: _hasExplicitContentTypeHeader = true;
058: if (header.toLowerCase().startsWith("content-length"))
059: _hasExplicitContentLengthHeader = true;
060: if (header.trim().toLowerCase().startsWith("connection")
061: && header.trim().toLowerCase().endsWith("close"))
062: _closesConnection = true;
063: if (header.trim().toLowerCase().startsWith("transfer-encoding")
064: && header.trim().toLowerCase().endsWith("chunked"))
065: _isChunked = true;
066: }
067:
068: public void setCharacterSet(String characterSet) {
069: _characterSet = characterSet;
070: }
071:
072: public void setSendCharacterSet(boolean enabled) {
073: _sendCharacterSet = enabled;
074: }
075:
076: public void suppressAutomaticLengthHeader() {
077: _hasExplicitContentLengthHeader = true;
078: }
079:
080: public WebResource(String contents, int responseCode) {
081: this (contents, DEFAULT_CONTENT_TYPE, responseCode);
082: }
083:
084: public WebResource(String contents, String contentType,
085: int responseCode) {
086: _string = contents;
087: _contentType = contentType;
088: _responseCode = responseCode;
089: }
090:
091: public WebResource(byte[] contents, String contentType,
092: int responseCode) {
093: _contents = contents;
094: _contentType = contentType;
095: _responseCode = responseCode;
096: }
097:
098: public WebResource(InputStream stream, String contentType,
099: int responseCode) {
100: _stream = stream;
101: _contentType = contentType;
102: _responseCode = responseCode;
103: addHeader("Connection: close");
104: }
105:
106: String[] getHeaders() throws UnsupportedEncodingException {
107: final Vector effectiveHeaders = (Vector) _headers.clone();
108: if (!_hasExplicitContentTypeHeader)
109: effectiveHeaders.add(getContentTypeHeader());
110: if (_stream == null && !_hasExplicitContentLengthHeader
111: && !isChunked())
112: effectiveHeaders.add(getContentLengthHeader());
113: String[] headers = new String[effectiveHeaders.size()];
114: effectiveHeaders.copyInto(headers);
115: return headers;
116: }
117:
118: private boolean isChunked() {
119: return _isChunked;
120: }
121:
122: boolean closesConnection() {
123: return _closesConnection;
124: }
125:
126: void writeTo(OutputStream outputStream) throws IOException {
127: if (_stream == null) {
128: outputStream.write(getContentsAsBytes());
129: } else if (_stream != null) {
130: byte[] buffer = new byte[8 * 1024];
131: int count = 0;
132: do {
133: outputStream.write(buffer, 0, count);
134: count = _stream.read(buffer, 0, buffer.length);
135: } while (count != -1);
136: }
137: }
138:
139: static String toString(byte[] contentsAsBytes) {
140: StringBuffer sb = new StringBuffer();
141: for (int i = 0; i < contentsAsBytes.length; i++) {
142: byte contentsAsByte = contentsAsBytes[i];
143: sb.append(Integer.toHexString(contentsAsByte)).append(' ');
144: }
145: return sb.toString();
146: }
147:
148: private byte[] getContentsAsBytes()
149: throws UnsupportedEncodingException {
150: if (_contents != null) {
151: return _contents;
152: } else if (_string != null) {
153: return _string.getBytes(getCharacterSet());
154: } else {
155: throw new IllegalStateException(
156: "Cannot get bytes from stream");
157: }
158: }
159:
160: private String getContentTypeHeader() {
161: return "Content-Type: " + _contentType
162: + getCharacterSetParameter();
163: }
164:
165: private String getContentLengthHeader()
166: throws UnsupportedEncodingException {
167: return "Content-Length: " + getContentsAsBytes().length;
168: }
169:
170: String getCharacterSet() {
171: return HttpUnitUtils.stripQuotes(_characterSet);
172: }
173:
174: String getCharacterSetParameter() {
175: if (!_sendCharacterSet) {
176: return "";
177: } else {
178: return "; charset=" + _characterSet;
179: }
180: }
181:
182: int getResponseCode() {
183: return _responseCode;
184: }
185:
186: public String toString() {
187: return "WebResource [code=" + _responseCode + "; type = "
188: + _contentType + "; charset = " + _characterSet + "]\n"
189: + getContentsAsString();
190: }
191:
192: private String getContentsAsString() {
193: if (_string != null) {
194: return _string;
195: } else {
196: return "<< hex bytes >>";
197: }
198: }
199:
200: private byte[] _contents;
201: private String _string;
202: private InputStream _stream;
203:
204: private int _responseCode;
205: private boolean _sendCharacterSet;
206: private String _contentType = DEFAULT_CONTENT_TYPE;
207: private String _characterSet = DEFAULT_CHARACTER_SET;
208: private boolean _hasExplicitContentTypeHeader;
209: private boolean _hasExplicitContentLengthHeader;
210: private Vector _headers = new Vector();
211: private boolean _isChunked;
212: }
|