View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  
20  package org.eclipse.jetty.http2.hpack;
21  
22  
23  import org.eclipse.jetty.http.BadMessageException;
24  import org.eclipse.jetty.http.HostPortHttpField;
25  import org.eclipse.jetty.http.HttpField;
26  import org.eclipse.jetty.http.HttpFields;
27  import org.eclipse.jetty.http.HttpScheme;
28  import org.eclipse.jetty.http.HttpStatus;
29  import org.eclipse.jetty.http.HttpVersion;
30  import org.eclipse.jetty.http.MetaData;
31  
32  public class MetaDataBuilder
33  { 
34      private final int _maxSize;
35      private int _size;
36      private int _status;
37      private String _method;
38      private HttpScheme _scheme;
39      private HostPortHttpField _authority;
40      private String _path;  
41      private long _contentLength=Long.MIN_VALUE;
42  
43      private HttpFields _fields = new HttpFields(10);
44      
45      /* ------------------------------------------------------------ */
46      /**
47       * @param maxHeadersSize The maximum size of the headers, expressed as total name and value characters.
48       */
49      MetaDataBuilder(int maxHeadersSize)
50      {
51          _maxSize=maxHeadersSize;
52      }
53      
54      /** Get the maxSize.
55       * @return the maxSize
56       */
57      public int getMaxSize()
58      {
59          return _maxSize;
60      }
61  
62      /** Get the size.
63       * @return the current size in bytes
64       */
65      public int getSize()
66      {
67          return _size;
68      }
69  
70      public void emit(HttpField field)
71      {        
72          int field_size = field.getName().length()+field.getValue().length();
73          _size+=field_size;
74          if (_size>_maxSize)
75              throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+_size+">"+_maxSize);
76          
77          if (field instanceof StaticTableHttpField)
78          {
79              StaticTableHttpField value = (StaticTableHttpField)field;
80              switch(field.getHeader())
81              {
82                  case C_STATUS:
83                      _status=(Integer)value.getStaticValue();
84                      break;
85                      
86                  case C_METHOD:
87                      _method=field.getValue();
88                      break;
89  
90                  case C_SCHEME:
91                      _scheme = (HttpScheme)value.getStaticValue();
92                      break;
93                      
94                  default:
95                      throw new IllegalArgumentException(field.getName());
96              }
97          }
98          else if (field.getHeader()!=null)
99          {
100             switch(field.getHeader())
101             {
102                 case C_STATUS:
103                     _status=field.getIntValue();
104                     break;
105 
106                 case C_METHOD:
107                     _method=field.getValue();
108                     break;
109 
110                 case C_SCHEME:
111                     _scheme = HttpScheme.CACHE.get(field.getValue());
112                     break;
113 
114                 case C_AUTHORITY:
115                     _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
116                     break;
117 
118                 case HOST:
119                     // :authority fields must come first.  If we have one, ignore the host header as far as authority goes.
120                     if (_authority==null)
121                         _authority=(field instanceof HostPortHttpField)?((HostPortHttpField)field):new AuthorityHttpField(field.getValue());
122                     _fields.add(field);
123                     break;
124 
125                 case C_PATH:
126                     _path = field.getValue();
127                     break;
128 
129                 case CONTENT_LENGTH:
130                     _contentLength = field.getLongValue();
131                     _fields.add(field);
132                     break;
133                     
134                 default:
135                     if (field.getName().charAt(0)!=':')
136                         _fields.add(field);
137             }
138         }
139         else
140         {
141             if (field.getName().charAt(0)!=':')
142                 _fields.add(field);
143         }
144     }
145     
146     public MetaData build()
147     {
148         try
149         {
150             HttpFields fields = _fields;
151             _fields = new HttpFields(Math.max(10,fields.size()+5));
152             
153             if (_method!=null)
154                 return new MetaData.Request(_method,_scheme,_authority,_path,HttpVersion.HTTP_2,fields,_contentLength);
155             if (_status!=0)
156                 return new MetaData.Response(HttpVersion.HTTP_2,_status,fields,_contentLength);
157             return new MetaData(HttpVersion.HTTP_2,fields,_contentLength);
158         }
159         finally
160         {
161             _status=0;
162             _method=null;
163             _scheme=null;
164             _authority=null;
165             _path=null;
166             _size=0;
167             _contentLength=Long.MIN_VALUE;
168         }
169     }
170 
171     /* ------------------------------------------------------------ */
172     /** Check that the max size will not be exceeded.
173      * @param length the length
174      * @param huffman the huffman name
175      */
176     public void checkSize(int length, boolean huffman)
177     {
178         // Apply a huffman fudge factor
179         if (huffman)
180             length=(length*4)/3;
181         if ((_size+length)>_maxSize)
182             throw new BadMessageException(HttpStatus.REQUEST_ENTITY_TOO_LARGE_413,"Header size "+(_size+length)+">"+_maxSize);
183     }
184 }