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