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 }