View Javadoc

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