View Javadoc

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.jetty.MimeTypes;
34  import org.mortbay.util.ByteArrayOutputStream2;
35  
36  /* ------------------------------------------------------------ */
37  /** Test support class.
38   * Assist with parsing and generating HTTP requests and responses.
39   * 
40   * <pre>
41   *      HttpTester tester = new HttpTester();
42   *      
43   *      tester.parse(
44   *          "GET /uri HTTP/1.1\r\n"+
45   *          "Host: fakehost\r\n"+
46   *          "Content-Length: 10\r\n" +
47   *          "\r\n");
48   *     
49   *      System.err.println(tester.getMethod());
50   *      System.err.println(tester.getURI());
51   *      System.err.println(tester.getVersion());
52   *      System.err.println(tester.getHeader("Host"));
53   *      System.err.println(tester.getContent());
54   * </pre>      
55   * 
56   * @author gregw
57   * @see org.mortbay.jetty.testing.ServletTester
58   */
59  public class HttpTester
60  {
61      protected HttpFields _fields=new HttpFields();
62      protected String _method;
63      protected String _uri;
64      protected String _version;
65      protected int _status;
66      protected String _reason;
67      protected ByteArrayOutputStream2 _parsedContent;
68      protected byte[] _genContent;
69      
70      private String _charset, _defaultCharset;
71      private Buffer _contentType;
72      
73      public HttpTester()
74      {
75          this("UTF-8");
76      }
77      
78      public HttpTester(String charset)
79      {
80          _defaultCharset = charset;
81      }
82      
83      public void reset()
84      {
85          _fields.clear();
86           _method=null;
87           _uri=null;
88           _version=null;
89           _status=0;
90           _reason=null;
91           _parsedContent=null;
92           _genContent=null;
93      }
94      
95      private String getString(Buffer buffer)
96      {
97          return getString(buffer.asArray());
98      }
99      
100     private String getString(byte[] b)
101     {
102         if(_charset==null)
103             return new String(b);
104         try
105         {
106             return new String(b, _charset);
107         }
108         catch(Exception e)
109         {
110             return new String(b);
111         }
112     }
113     
114     private byte[] getByteArray(String str)
115     {
116         if(_charset==null)
117             return str.getBytes();
118         try
119         {
120             return str.getBytes(_charset);
121         }
122         catch(Exception e)
123         {
124             return str.getBytes();
125         }
126     }
127 
128     /* ------------------------------------------------------------ */
129     /**
130      * Parse one HTTP request or response
131      * @param rawHTTP Raw HTTP to parse
132      * @return Any unparsed data in the rawHTTP (eg pipelined requests)
133      * @throws IOException
134      */
135     public String parse(String rawHTTP) throws IOException
136     {
137         _charset = _defaultCharset;
138         ByteArrayBuffer buf = new ByteArrayBuffer(getByteArray(rawHTTP));
139         View view = new View(buf);
140         HttpParser parser = new HttpParser(view,new PH());
141         parser.parse();
142         return getString(view.asArray());
143     }
144 
145     /* ------------------------------------------------------------ */
146     public String generate() throws IOException
147     {
148         _charset = _defaultCharset;
149         _contentType = _fields.get(HttpHeaders.CONTENT_TYPE_BUFFER);
150         if(_contentType!=null)
151         {
152             String charset = MimeTypes.getCharsetFromContentType(_contentType);
153             if(charset!=null)
154                 _charset = charset;
155         }
156         Buffer bb=new ByteArrayBuffer(32*1024 + (_genContent!=null?_genContent.length:0));
157         Buffer sb=new ByteArrayBuffer(4*1024);
158         StringEndPoint endp = new StringEndPoint(_charset);
159         HttpGenerator generator = new HttpGenerator(new SimpleBuffers(new Buffer[]{sb,bb}),endp, sb.capacity(), bb.capacity());
160         
161         if (_method!=null)
162         {
163             generator.setRequest(getMethod(),getURI());
164             if (_version==null)
165                 generator.setVersion(HttpVersions.HTTP_1_1_ORDINAL);
166             else
167                 generator.setVersion(HttpVersions.CACHE.getOrdinal(HttpVersions.CACHE.lookup(_version)));
168             generator.completeHeader(_fields,false);
169             if (_genContent!=null)
170                 generator.addContent(new View(new ByteArrayBuffer(_genContent)),false);
171             else if (_parsedContent!=null)
172                 generator.addContent(new ByteArrayBuffer(_parsedContent.toByteArray()),false);
173         }
174         
175         generator.complete();
176         generator.flush();
177         return endp.getOutput();
178     }
179     
180     /* ------------------------------------------------------------ */
181     /**
182      * @return the method
183      */
184     public String getMethod()
185     {
186         return _method;
187     }
188 
189     /* ------------------------------------------------------------ */
190     /**
191      * @param method the method to set
192      */
193     public void setMethod(String method)
194     {
195         _method=method;
196     }
197 
198     /* ------------------------------------------------------------ */
199     /**
200      * @return the reason
201      */
202     public String getReason()
203     {
204         return _reason;
205     }
206 
207     /* ------------------------------------------------------------ */
208     /**
209      * @param reason the reason to set
210      */
211     public void setReason(String reason)
212     {
213         _reason=reason;
214     }
215 
216     /* ------------------------------------------------------------ */
217     /**
218      * @return the status
219      */
220     public int getStatus()
221     {
222         return _status;
223     }
224 
225     /* ------------------------------------------------------------ */
226     /**
227      * @param status the status to set
228      */
229     public void setStatus(int status)
230     {
231         _status=status;
232     }
233 
234     /* ------------------------------------------------------------ */
235     /**
236      * @return the uri
237      */
238     public String getURI()
239     {
240         return _uri;
241     }
242 
243     /* ------------------------------------------------------------ */
244     /**
245      * @param uri the uri to set
246      */
247     public void setURI(String uri)
248     {
249         _uri=uri;
250     }
251 
252     /* ------------------------------------------------------------ */
253     /**
254      * @return the version
255      */
256     public String getVersion()
257     {
258         return _version;
259     }
260 
261     /* ------------------------------------------------------------ */
262     /**
263      * @param version the version to set
264      */
265     public void setVersion(String version)
266     {
267         _version=version;
268     }
269     
270     /* ------------------------------------------------------------ */
271     public String getContentType()
272     {
273         return getString(_contentType);
274     }
275     
276     /* ------------------------------------------------------------ */
277     public String getCharacterEncoding()
278     {
279         return _charset;
280     }
281 
282     /* ------------------------------------------------------------ */
283     /**
284      * @param name
285      * @param value
286      * @throws IllegalArgumentException
287      * @see org.mortbay.jetty.HttpFields#add(java.lang.String, java.lang.String)
288      */
289     public void addHeader(String name, String value) throws IllegalArgumentException
290     {
291         _fields.add(name,value);
292     }
293 
294     /* ------------------------------------------------------------ */
295     /**
296      * @param name
297      * @param date
298      * @see org.mortbay.jetty.HttpFields#addDateField(java.lang.String, long)
299      */
300     public void addDateHeader(String name, long date)
301     {
302         _fields.addDateField(name,date);
303     }
304 
305     /* ------------------------------------------------------------ */
306     /**
307      * @param name
308      * @param value
309      * @see org.mortbay.jetty.HttpFields#addLongField(java.lang.String, long)
310      */
311     public void addLongHeader(String name, long value)
312     {
313         _fields.addLongField(name,value);
314     }
315 
316     /* ------------------------------------------------------------ */
317     /**
318      * @param cookie
319      * @see org.mortbay.jetty.HttpFields#addSetCookie(javax.servlet.http.Cookie)
320      */
321     public void addSetCookie(Cookie cookie)
322     {
323         _fields.addSetCookie(cookie);
324     }
325 
326     /* ------------------------------------------------------------ */
327     /**
328      * @param name
329      * @return
330      * @see org.mortbay.jetty.HttpFields#getDateField(java.lang.String)
331      */
332     public long getDateHeader(String name)
333     {
334         return _fields.getDateField(name);
335     }
336 
337     /* ------------------------------------------------------------ */
338     /**
339      * @return
340      * @see org.mortbay.jetty.HttpFields#getFieldNames()
341      */
342     public Enumeration getHeaderNames()
343     {
344         return _fields.getFieldNames();
345     }
346 
347     /* ------------------------------------------------------------ */
348     /**
349      * @param name
350      * @return
351      * @throws NumberFormatException
352      * @see org.mortbay.jetty.HttpFields#getLongField(java.lang.String)
353      */
354     public long getLongHeader(String name) throws NumberFormatException
355     {
356         return _fields.getLongField(name);
357     }
358 
359     /* ------------------------------------------------------------ */
360     /**
361      * @param name
362      * @return
363      * @see org.mortbay.jetty.HttpFields#getStringField(java.lang.String)
364      */
365     public String getHeader(String name)
366     {
367         return _fields.getStringField(name);
368     }
369 
370     /* ------------------------------------------------------------ */
371     /**
372      * @param name
373      * @return
374      * @see org.mortbay.jetty.HttpFields#getValues(java.lang.String)
375      */
376     public Enumeration getHeaderValues(String name)
377     {
378         return _fields.getValues(name);
379     }
380 
381     /* ------------------------------------------------------------ */
382     /**
383      * @param name
384      * @param value
385      * @see org.mortbay.jetty.HttpFields#put(java.lang.String, java.lang.String)
386      */
387     public void setHeader(String name, String value)
388     {
389         _fields.put(name,value);
390     }
391 
392     /* ------------------------------------------------------------ */
393     /**
394      * @param name
395      * @param date
396      * @see org.mortbay.jetty.HttpFields#putDateField(java.lang.String, long)
397      */
398     public void setDateHeader(String name, long date)
399     {
400         _fields.putDateField(name,date);
401     }
402 
403     /* ------------------------------------------------------------ */
404     /**
405      * @param name
406      * @param value
407      * @see org.mortbay.jetty.HttpFields#putLongField(java.lang.String, long)
408      */
409     public void setLongHeader(String name, long value)
410     {
411         _fields.putLongField(name,value);
412     }
413 
414     /* ------------------------------------------------------------ */
415     /**
416      * @param name
417      * @see org.mortbay.jetty.HttpFields#remove(java.lang.String)
418      */
419     public void removeHeader(String name)
420     {
421         _fields.remove(name);
422     }
423     
424     /* ------------------------------------------------------------ */
425     public String getContent()
426     {
427         if (_parsedContent!=null)
428             return getString(_parsedContent.toByteArray());
429         if (_genContent!=null)
430             return getString(_genContent);
431         return null;
432     }
433     
434     /* ------------------------------------------------------------ */
435     public void setContent(String content)
436     {
437         _parsedContent=null;
438         if (content!=null)
439         {
440             _genContent=getByteArray(content);
441             setLongHeader(HttpHeaders.CONTENT_LENGTH,_genContent.length);
442         }
443         else
444         {
445             removeHeader(HttpHeaders.CONTENT_LENGTH);
446             _genContent=null;
447         }
448     }
449 
450     /* ------------------------------------------------------------ */
451     private class PH extends HttpParser.EventHandler
452     {
453         public void startRequest(Buffer method, Buffer url, Buffer version) throws IOException
454         {
455             reset();
456             _method=getString(method);
457             _uri=getString(url);
458             _version=getString(version);
459         }
460 
461         public void startResponse(Buffer version, int status, Buffer reason) throws IOException
462         {
463             reset();
464             _version=getString(version);
465             _status=status;
466             _reason=getString(reason);
467         }
468         
469         public void parsedHeader(Buffer name, Buffer value) throws IOException
470         {
471             _fields.add(name,value);
472         }
473 
474         public void headerComplete() throws IOException
475         {
476             _contentType = _fields.get(HttpHeaders.CONTENT_TYPE_BUFFER);
477             if(_contentType!=null)
478             {
479                 String charset = MimeTypes.getCharsetFromContentType(_contentType);
480                 if(charset!=null)
481                     _charset = charset;
482             }
483         }
484 
485         public void messageComplete(long contextLength) throws IOException
486         {
487         }
488         
489         public void content(Buffer ref) throws IOException
490         {
491             if (_parsedContent==null)
492                 _parsedContent=new ByteArrayOutputStream2();
493             _parsedContent.write(ref.asArray());
494         }
495     }
496 
497 }