1 //========================================================================
2 //Copyright 2004-2008 Mort Bay Consulting Pty. Ltd.
3 //------------------------------------------------------------------------
4 //Licensed under the Apache License, Version 2.0 (the "License");
5 //you may not use this file except in compliance with the License.
6 //You may obtain a copy of the License at
7 //http://www.apache.org/licenses/LICENSE-2.0
8 //Unless required by applicable law or agreed to in writing, software
9 //distributed under the License is distributed on an "AS IS" BASIS,
10 //WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 //See the License for the specific language governing permissions and
12 //limitations under the License.
13 //========================================================================
14
15 package org.mortbay.jetty.testing;
16
17 import java.io.IOException;
18 import java.util.Enumeration;
19
20 import javax.servlet.http.Cookie;
21
22 import org.mortbay.io.Buffer;
23 import org.mortbay.io.ByteArrayBuffer;
24 import org.mortbay.io.ByteArrayEndPoint;
25 import org.mortbay.io.SimpleBuffers;
26 import org.mortbay.io.View;
27 import org.mortbay.io.bio.StringEndPoint;
28 import org.mortbay.jetty.HttpFields;
29 import org.mortbay.jetty.HttpGenerator;
30 import org.mortbay.jetty.HttpHeaders;
31 import org.mortbay.jetty.HttpParser;
32 import org.mortbay.jetty.HttpVersions;
33 import org.mortbay.util.ByteArrayOutputStream2;
34
35 /* ------------------------------------------------------------ */
36 /** Test support class.
37 * Assist with parsing and generating HTTP requests and responses.
38 *
39 * <pre>
40 * HttpTester tester = new HttpTester();
41 *
42 * tester.parse(
43 * "GET /uri HTTP/1.1\r\n"+
44 * "Host: fakehost\r\n"+
45 * "Content-Length: 10\r\n" +
46 * "\r\n");
47 *
48 * System.err.println(tester.getMethod());
49 * System.err.println(tester.getURI());
50 * System.err.println(tester.getVersion());
51 * System.err.println(tester.getHeader("Host"));
52 * System.err.println(tester.getContent());
53 * </pre>
54 *
55 * @author gregw
56 * @see org.mortbay.jetty.testing.ServletTester
57 */
58 public class HttpTester
59 {
60 protected HttpFields _fields=new HttpFields();
61 protected String _method;
62 protected String _uri;
63 protected String _version;
64 protected int _status;
65 protected String _reason;
66 protected ByteArrayOutputStream2 _parsedContent;
67 protected byte[] _genContent;
68
69 public HttpTester()
70 {
71 }
72
73 public void reset()
74 {
75 _fields.clear();
76 _method=null;
77 _uri=null;
78 _version=null;
79 _status=0;
80 _reason=null;
81 _parsedContent=null;
82 _genContent=null;
83 }
84
85 /* ------------------------------------------------------------ */
86 /**
87 * Parse one HTTP request or response
88 * @param rawHTTP Raw HTTP to parse
89 * @return Any unparsed data in the rawHTTP (eg pipelined requests)
90 * @throws IOException
91 */
92 public String parse(String rawHTTP) throws IOException
93 {
94 ByteArrayBuffer buf = new ByteArrayBuffer(rawHTTP);
95 View view = new View(buf);
96 HttpParser parser = new HttpParser(view,new PH());
97 parser.parse();
98 return view.toString();
99 }
100
101 /* ------------------------------------------------------------ */
102 public String generate() throws IOException
103 {
104 Buffer bb=new ByteArrayBuffer(32*1024 + (_genContent!=null?_genContent.length:0));
105 Buffer sb=new ByteArrayBuffer(4*1024);
106 StringEndPoint endp = new StringEndPoint();
107 HttpGenerator generator = new HttpGenerator(new SimpleBuffers(new Buffer[]{sb,bb}),endp, sb.capacity(), bb.capacity());
108
109 if (_method!=null)
110 {
111 generator.setRequest(getMethod(),getURI());
112 if (_version==null)
113 generator.setVersion(HttpVersions.HTTP_1_1_ORDINAL);
114 else
115 generator.setVersion(HttpVersions.CACHE.getOrdinal(HttpVersions.CACHE.lookup(_version)));
116 generator.completeHeader(_fields,false);
117 if (_genContent!=null)
118 generator.addContent(new View(new ByteArrayBuffer(_genContent)),false);
119 else if (_parsedContent!=null)
120 generator.addContent(new ByteArrayBuffer(_parsedContent.toByteArray()),false);
121 }
122
123 generator.complete();
124 generator.flush();
125 return endp.getOutput();
126 }
127
128 /* ------------------------------------------------------------ */
129 /**
130 * @return the method
131 */
132 public String getMethod()
133 {
134 return _method;
135 }
136
137 /* ------------------------------------------------------------ */
138 /**
139 * @param method the method to set
140 */
141 public void setMethod(String method)
142 {
143 _method=method;
144 }
145
146 /* ------------------------------------------------------------ */
147 /**
148 * @return the reason
149 */
150 public String getReason()
151 {
152 return _reason;
153 }
154
155 /* ------------------------------------------------------------ */
156 /**
157 * @param reason the reason to set
158 */
159 public void setReason(String reason)
160 {
161 _reason=reason;
162 }
163
164 /* ------------------------------------------------------------ */
165 /**
166 * @return the status
167 */
168 public int getStatus()
169 {
170 return _status;
171 }
172
173 /* ------------------------------------------------------------ */
174 /**
175 * @param status the status to set
176 */
177 public void setStatus(int status)
178 {
179 _status=status;
180 }
181
182 /* ------------------------------------------------------------ */
183 /**
184 * @return the uri
185 */
186 public String getURI()
187 {
188 return _uri;
189 }
190
191 /* ------------------------------------------------------------ */
192 /**
193 * @param uri the uri to set
194 */
195 public void setURI(String uri)
196 {
197 _uri=uri;
198 }
199
200 /* ------------------------------------------------------------ */
201 /**
202 * @return the version
203 */
204 public String getVersion()
205 {
206 return _version;
207 }
208
209 /* ------------------------------------------------------------ */
210 /**
211 * @param version the version to set
212 */
213 public void setVersion(String version)
214 {
215 _version=version;
216 }
217
218 /* ------------------------------------------------------------ */
219 /**
220 * @param name
221 * @param value
222 * @throws IllegalArgumentException
223 * @see org.mortbay.jetty.HttpFields#add(java.lang.String, java.lang.String)
224 */
225 public void addHeader(String name, String value) throws IllegalArgumentException
226 {
227 _fields.add(name,value);
228 }
229
230 /* ------------------------------------------------------------ */
231 /**
232 * @param name
233 * @param date
234 * @see org.mortbay.jetty.HttpFields#addDateField(java.lang.String, long)
235 */
236 public void addDateHeader(String name, long date)
237 {
238 _fields.addDateField(name,date);
239 }
240
241 /* ------------------------------------------------------------ */
242 /**
243 * @param name
244 * @param value
245 * @see org.mortbay.jetty.HttpFields#addLongField(java.lang.String, long)
246 */
247 public void addLongHeader(String name, long value)
248 {
249 _fields.addLongField(name,value);
250 }
251
252 /* ------------------------------------------------------------ */
253 /**
254 * @param cookie
255 * @see org.mortbay.jetty.HttpFields#addSetCookie(javax.servlet.http.Cookie)
256 */
257 public void addSetCookie(Cookie cookie)
258 {
259 _fields.addSetCookie(cookie);
260 }
261
262 /* ------------------------------------------------------------ */
263 /**
264 * @param name
265 * @return
266 * @see org.mortbay.jetty.HttpFields#getDateField(java.lang.String)
267 */
268 public long getDateHeader(String name)
269 {
270 return _fields.getDateField(name);
271 }
272
273 /* ------------------------------------------------------------ */
274 /**
275 * @return
276 * @see org.mortbay.jetty.HttpFields#getFieldNames()
277 */
278 public Enumeration getHeaderNames()
279 {
280 return _fields.getFieldNames();
281 }
282
283 /* ------------------------------------------------------------ */
284 /**
285 * @param name
286 * @return
287 * @throws NumberFormatException
288 * @see org.mortbay.jetty.HttpFields#getLongField(java.lang.String)
289 */
290 public long getLongHeader(String name) throws NumberFormatException
291 {
292 return _fields.getLongField(name);
293 }
294
295 /* ------------------------------------------------------------ */
296 /**
297 * @param name
298 * @return
299 * @see org.mortbay.jetty.HttpFields#getStringField(java.lang.String)
300 */
301 public String getHeader(String name)
302 {
303 return _fields.getStringField(name);
304 }
305
306 /* ------------------------------------------------------------ */
307 /**
308 * @param name
309 * @return
310 * @see org.mortbay.jetty.HttpFields#getValues(java.lang.String)
311 */
312 public Enumeration getHeaderValues(String name)
313 {
314 return _fields.getValues(name);
315 }
316
317 /* ------------------------------------------------------------ */
318 /**
319 * @param name
320 * @param value
321 * @see org.mortbay.jetty.HttpFields#put(java.lang.String, java.lang.String)
322 */
323 public void setHeader(String name, String value)
324 {
325 _fields.put(name,value);
326 }
327
328 /* ------------------------------------------------------------ */
329 /**
330 * @param name
331 * @param date
332 * @see org.mortbay.jetty.HttpFields#putDateField(java.lang.String, long)
333 */
334 public void setDateHeader(String name, long date)
335 {
336 _fields.putDateField(name,date);
337 }
338
339 /* ------------------------------------------------------------ */
340 /**
341 * @param name
342 * @param value
343 * @see org.mortbay.jetty.HttpFields#putLongField(java.lang.String, long)
344 */
345 public void setLongHeader(String name, long value)
346 {
347 _fields.putLongField(name,value);
348 }
349
350 /* ------------------------------------------------------------ */
351 /**
352 * @param name
353 * @see org.mortbay.jetty.HttpFields#remove(java.lang.String)
354 */
355 public void removeHeader(String name)
356 {
357 _fields.remove(name);
358 }
359
360 /* ------------------------------------------------------------ */
361 public String getContent()
362 {
363 if (_parsedContent!=null)
364 return _parsedContent.toString();
365 if (_genContent!=null)
366 return new String(_genContent);
367 return null;
368 }
369
370 /* ------------------------------------------------------------ */
371 public void setContent(String content)
372 {
373 _parsedContent=null;
374 if (content!=null)
375 {
376 _genContent=content.getBytes();
377 setLongHeader(HttpHeaders.CONTENT_LENGTH,_genContent.length);
378 }
379 else
380 {
381 removeHeader(HttpHeaders.CONTENT_LENGTH);
382 _genContent=null;
383 }
384 }
385
386 /* ------------------------------------------------------------ */
387 private class PH extends HttpParser.EventHandler
388 {
389 public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException
390 {
391 reset();
392 _method=method.toString();
393 _uri=url.toString();
394 _version=version.toString();
395 }
396
397 public void startResponse(Buffer version, int status, Buffer reason) throws IOException
398 {
399 reset();
400 _version=version.toString();
401 _status=status;
402 _reason=reason.toString();
403 }
404
405 public void parsedHeader(Buffer name, Buffer value) throws IOException
406 {
407 _fields.add(name,value);
408 }
409
410 public void headerComplete() throws IOException
411 {
412 }
413
414 public void messageComplete(long contextLength) throws IOException
415 {
416 }
417
418 public void content(Buffer ref) throws IOException
419 {
420 if (_parsedContent==null)
421 _parsedContent=new ByteArrayOutputStream2();
422 _parsedContent.write(ref.asArray());
423 }
424 }
425
426 }