1   /*
2    * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/oac.hc3x/trunk/src/test/org/apache/commons/httpclient/server/SimpleResponse.java $
3    * $Revision: 1425331 $
4    * $Date: 2012-12-22 19:29:41 +0100 (Sat, 22 Dec 2012) $
5    *
6    * ====================================================================
7    *
8    *  Licensed to the Apache Software Foundation (ASF) under one or more
9    *  contributor license agreements.  See the NOTICE file distributed with
10   *  this work for additional information regarding copyright ownership.
11   *  The ASF licenses this file to You under the Apache License, Version 2.0
12   *  (the "License"); you may not use this file except in compliance with
13   *  the License.  You may obtain a copy of the License at
14   *
15   *      http://www.apache.org/licenses/LICENSE-2.0
16   *
17   *  Unless required by applicable law or agreed to in writing, software
18   *  distributed under the License is distributed on an "AS IS" BASIS,
19   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   *  See the License for the specific language governing permissions and
21   *  limitations under the License.
22   * ====================================================================
23   *
24   * This software consists of voluntary contributions made by many
25   * individuals on behalf of the Apache Software Foundation.  For more
26   * information on the Apache Software Foundation, please see
27   * <http://www.apache.org/>.
28   *
29   */
30  
31  package org.apache.commons.httpclient.server;
32  
33  import java.io.ByteArrayInputStream;
34  import java.io.ByteArrayOutputStream;
35  import java.io.IOException;
36  import java.io.InputStream;
37  import java.io.UnsupportedEncodingException;
38  import java.util.Iterator;
39  
40  import org.apache.commons.httpclient.ChunkedInputStream;
41  import org.apache.commons.httpclient.ContentLengthInputStream;
42  import org.apache.commons.httpclient.Header;
43  import org.apache.commons.httpclient.HeaderElement;
44  import org.apache.commons.httpclient.HeaderGroup;
45  import org.apache.commons.httpclient.HttpStatus;
46  import org.apache.commons.httpclient.HttpVersion;
47  import org.apache.commons.httpclient.NameValuePair;
48  import org.apache.commons.httpclient.StatusLine;
49  
50  /***
51   * A generic HTTP response.
52   * 
53   * @author Christian Kohlschuetter
54   * @author Oleg Kalnichevski
55   */
56  public class SimpleResponse {
57      
58      public static final String DEFAULT_CONTENT_CHARSET = "ISO-8859-1";
59      
60      private HttpVersion ver = HttpVersion.HTTP_1_1;
61      private int statuscode = HttpStatus.SC_OK;
62      private String phrase = HttpStatus.getStatusText(HttpStatus.SC_OK);
63      private HeaderGroup headers = new HeaderGroup();
64      private InputStream entity = null;
65  
66      public SimpleResponse() {
67          super();
68      }
69  
70      public SimpleResponse(
71              final StatusLine statusline, 
72              final Header[] headers, 
73              final InputStream content) 
74              throws IOException {
75          super();
76          if (statusline == null) {
77              throw new IllegalArgumentException("Status line may not be null");
78          }
79          setStatusLine(HttpVersion.parse(statusline.getHttpVersion()),
80                  statusline.getStatusCode(), statusline.getReasonPhrase());
81          setHeaders(headers);
82          if (content != null) {
83              InputStream in = content;
84              Header contentLength = this.headers.getFirstHeader("Content-Length");
85              Header transferEncoding = this.headers.getFirstHeader("Transfer-Encoding");
86  
87              if (transferEncoding != null) {
88                  if (transferEncoding.getValue().indexOf("chunked") != -1) {
89                      in = new ChunkedInputStream(in);
90                  }
91              } else if (contentLength != null) {
92                  long len = getContentLength();
93                  if (len >= 0) {
94                      in = new ContentLengthInputStream(in, len);
95                  }
96              }
97              this.entity = in;
98          }
99      }
100 
101 
102     public void setStatusLine(final HttpVersion ver, int statuscode, final String phrase) {
103         if (ver == null) {
104             throw new IllegalArgumentException("HTTP version may not be null");
105         }
106         if (statuscode <= 0) {
107             throw new IllegalArgumentException("Status code may not be negative or zero");
108         }
109         this.ver = ver;
110         this.statuscode = statuscode;
111         if (phrase != null) {
112             this.phrase = phrase;
113         } else {
114             this.phrase = HttpStatus.getStatusText(statuscode);
115         }
116     }
117 
118     public void setStatusLine(final HttpVersion ver, int statuscode) {
119         setStatusLine(ver, statuscode, null);
120     }
121 
122     public String getPhrase() {
123         return this.phrase;
124     }
125 
126     public int getStatuscode() {
127         return this.statuscode;
128     }
129 
130     public HttpVersion getHttpVersion() {
131         return this.ver;
132     }
133 
134     public String getStatusLine() {
135         StringBuffer buffer = new StringBuffer();
136         buffer.append(this.ver);
137         buffer.append(' ');
138         buffer.append(this.statuscode);
139         if (this.phrase != null) {
140             buffer.append(' ');
141             buffer.append(this.phrase);
142         }
143         return buffer.toString();
144     }
145 
146     public boolean containsHeader(final String name) {
147         return this.headers.containsHeader(name);
148     }
149 
150     public Header[] getHeaders() {
151         return this.headers.getAllHeaders();
152     }
153 
154     public Header getFirstHeader(final String name) {
155         return this.headers.getFirstHeader(name);
156     }
157 
158     public void removeHeaders(final String s) {
159         if (s == null) {
160             return;
161         }
162         Header[] headers = this.headers.getHeaders(s);
163         for (int i = 0; i < headers.length; i++) {
164             this.headers.removeHeader(headers[i]);
165         }
166     }
167 
168     public void addHeader(final Header header) {
169         if (header == null) {
170             return;
171         }
172         this.headers.addHeader(header);
173     }
174 
175     public void setHeader(final Header header) {
176         if (header == null) {
177             return;
178         }
179         removeHeaders(header.getName());
180         addHeader(header);
181     }
182 
183     public void setHeaders(final Header[] headers) {
184         if (headers == null) {
185             return;
186         }
187         this.headers.setHeaders(headers);
188     }
189 
190     public Iterator getHeaderIterator() {
191         return this.headers.getIterator();
192     }
193     
194     public String getCharset() {
195         String charset = DEFAULT_CONTENT_CHARSET;
196         Header contenttype = this.headers.getFirstHeader("Content-Type");
197         if (contenttype != null) {
198             HeaderElement values[] = contenttype.getElements();
199             if (values.length == 1) {
200                 NameValuePair param = values[0].getParameterByName("charset");
201                 if (param != null) {
202                     charset = param.getValue();
203                 }
204             }
205         }
206         return charset;
207     }
208 
209     public long getContentLength() {
210         Header contentLength = this.headers.getFirstHeader("Content-Length");
211         if (contentLength != null) {
212             try {
213                 return Long.parseLong(contentLength.getValue());
214             } catch (NumberFormatException e) {
215                 return -1;
216             }
217         } else {
218             return -1;
219         }
220     }
221     
222     public void setBodyString(final String string) {
223         if (string != null) {
224             byte[] raw = null;
225             try {
226                 raw = string.getBytes(DEFAULT_CONTENT_CHARSET);
227             } catch (UnsupportedEncodingException e) {
228                 raw = string.getBytes();
229             }
230             this.entity = new ByteArrayInputStream(raw);
231             if (!containsHeader("Content-Type")) {
232                 setHeader(new Header("Content-Type", "text/plain"));
233             }
234             setHeader(new Header("Content-Length", Long.toString(raw.length)));
235         } else {
236             this.entity = null;
237         }
238     }
239     
240     public void setBody(final InputStream instream) {
241         this.entity = instream;
242     }
243     
244     public InputStream getBody() {
245         return this.entity;
246     }
247     
248     public byte[] getBodyBytes() throws IOException {
249         InputStream in = getBody();
250         if (in != null) {
251             byte[] tmp = new byte[4096];
252             int bytesRead = 0;
253             ByteArrayOutputStream buffer = new ByteArrayOutputStream(1024);
254             while ((bytesRead = in.read(tmp)) != -1) {
255                 buffer.write(tmp, 0, bytesRead);
256             }
257             return buffer.toByteArray();
258         } else {
259             return null;
260         }
261     }
262     
263     public String getBodyString() throws IOException {
264         byte[] raw = getBodyBytes();
265         if (raw != null) {
266             return new String(raw, getCharset());
267         } else {
268             return null;
269         }
270     }
271 }