View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2012 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  package org.eclipse.jetty.http;
20  
21  import java.nio.ByteBuffer;
22  import java.util.HashMap;
23  import java.util.Map;
24  
25  import org.eclipse.jetty.util.StringMap;
26  import org.eclipse.jetty.util.StringUtil;
27  
28  
29  public enum HttpHeader
30  {
31      /* ------------------------------------------------------------ */
32      /** General Fields.
33       */
34      CONNECTION("Connection"),
35      CACHE_CONTROL("Cache-Control"),
36      DATE("Date"),
37      PRAGMA("Pragma"),
38      PROXY_CONNECTION ("Proxy-Connection"),
39      TRAILER("Trailer"),
40      TRANSFER_ENCODING("Transfer-Encoding"),
41      UPGRADE("Upgrade"),
42      VIA("Via"),
43      WARNING("Warning"),
44      NEGOTIATE("Negotiate"),
45  
46      /* ------------------------------------------------------------ */
47      /** Entity Fields.
48       */
49      ALLOW("Allow"),
50      CONTENT_ENCODING("Content-Encoding"),
51      CONTENT_LANGUAGE("Content-Language"),
52      CONTENT_LENGTH("Content-Length"),
53      CONTENT_LOCATION("Content-Location"),
54      CONTENT_MD5("Content-MD5"),
55      CONTENT_RANGE("Content-Range"),
56      CONTENT_TYPE("Content-Type"),
57      EXPIRES("Expires"),
58      LAST_MODIFIED("Last-Modified"),
59  
60      /* ------------------------------------------------------------ */
61      /** Request Fields.
62       */
63      ACCEPT("Accept"),
64      ACCEPT_CHARSET("Accept-Charset"),
65      ACCEPT_ENCODING("Accept-Encoding"),
66      ACCEPT_LANGUAGE("Accept-Language"),
67      AUTHORIZATION("Authorization"),
68      EXPECT("Expect"),
69      FORWARDED("Forwarded"),
70      FROM("From"),
71      HOST("Host"),
72      IF_MATCH("If-Match"),
73      IF_MODIFIED_SINCE("If-Modified-Since"),
74      IF_NONE_MATCH("If-None-Match"),
75      IF_RANGE("If-Range"),
76      IF_UNMODIFIED_SINCE("If-Unmodified-Since"),
77      KEEP_ALIVE("Keep-Alive"),
78      MAX_FORWARDS("Max-Forwards"),
79      PROXY_AUTHORIZATION("Proxy-Authorization"),
80      RANGE("Range"),
81      REQUEST_RANGE("Request-Range"),
82      REFERER("Referer"),
83      TE("TE"),
84      USER_AGENT("User-Agent"),
85      X_FORWARDED_FOR("X-Forwarded-For"),
86      X_FORWARDED_PROTO("X-Forwarded-Proto"),
87      X_FORWARDED_SERVER("X-Forwarded-Server"),
88      X_FORWARDED_HOST("X-Forwarded-Host"),
89  
90      /* ------------------------------------------------------------ */
91      /** Response Fields.
92       */
93      ACCEPT_RANGES("Accept-Ranges"),
94      AGE("Age"),
95      ETAG("ETag"),
96      LOCATION("Location"),
97      PROXY_AUTHENTICATE("Proxy-Authenticate"),
98      RETRY_AFTER("Retry-After"),
99      SERVER("Server"),
100     SERVLET_ENGINE("Servlet-Engine"),
101     VARY("Vary"),
102     WWW_AUTHENTICATE("WWW-Authenticate"),
103 
104     /* ------------------------------------------------------------ */
105     /** Other Fields.
106      */
107     COOKIE("Cookie"),
108     SET_COOKIE("Set-Cookie"),
109     SET_COOKIE2("Set-Cookie2"),
110     MIME_VERSION("MIME-Version"),
111     IDENTITY("identity"),
112 
113     UNKNOWN("::UNKNOWN::");
114 
115 
116     /* ------------------------------------------------------------ */
117     public final static StringMap<HttpHeader> CACHE= new StringMap<HttpHeader>(true);
118     static
119     {
120         for (HttpHeader header : HttpHeader.values())
121             if (header!=UNKNOWN)
122                 CACHE.put(header.toString(),header);
123     }
124     
125     /* ------------------------------------------------------------ */
126     private final static HttpHeader[] __hashed= new HttpHeader[4096]; 
127     private final static int __maxHashed;
128     static
129     {
130         // This hash function has been picked to have no collisions for 
131         // the known header values.  This allows a very quick lookup.
132         int max=0;
133         Map<Integer,HttpHeader> hashes=new HashMap<>();
134         for (HttpHeader header : HttpHeader.values())
135         {
136             String s=header.asString();
137             max=Math.max(max,s.length());
138             int h=0;
139             for (char c:s.toCharArray())
140                 h = 31*h + ((c>='a')?(c-'a'+'A'):c);
141             int hash=h%__hashed.length;
142             if (hash<0)hash=-hash;
143             if (hashes.containsKey(hash))
144             {
145                 // This should not happen with known headers.
146                 System.err.println("Duplicate hash "+header+" "+hashes.get(hash));
147                 System.exit(1);
148             }
149             hashes.put(hash,header);
150             __hashed[hash]=header;
151         }
152         __maxHashed=max;
153     }
154 
155     public static HttpHeader lookAheadGet(byte[] bytes, int position, int limit)
156     {
157         int h=0;
158         byte b=0;
159         limit=Math.min(position+__maxHashed,limit);
160         for (int i=position;i<limit;i++)
161         {
162             b=bytes[i];
163             if (b==':'||b==' ')
164                 break;
165             h= 31*h+ ((b>='a')?(b-'a'+'A'):b);
166         }
167         if (b!=':'&&b!=' ')
168             return null;
169 
170         int hash=h%__hashed.length;
171         if (hash<0)hash=-hash;
172         HttpHeader header=__hashed[hash];
173         
174         if (header!=null)
175         {
176             String s=header.asString();
177             for (int i=s.length();i-->0;)
178             {
179                 b=bytes[position+i];
180                 char c=s.charAt(i);
181                 if (c!=b && Character.toUpperCase(c)!=(b>='a'?(b-'a'+'A'):b))
182                     return null;
183             }
184         }
185         
186         return header;
187     }
188     
189     
190     private final String _string;
191     private final byte[] _bytes;
192     private final byte[] _bytesColonSpace;
193     private final ByteBuffer _buffer;
194 
195     /* ------------------------------------------------------------ */
196     HttpHeader(String s)
197     {
198         _string=s;
199         _bytes=StringUtil.getBytes(s);
200         _bytesColonSpace=StringUtil.getBytes(s+": ");
201         _buffer=ByteBuffer.wrap(_bytes);
202     }
203 
204     /* ------------------------------------------------------------ */
205     public ByteBuffer toBuffer()
206     {
207         return _buffer.asReadOnlyBuffer();
208     }
209 
210     /* ------------------------------------------------------------ */
211     public byte[] getBytes()
212     {
213         return _bytes;
214     }
215 
216     /* ------------------------------------------------------------ */
217     public byte[] getBytesColonSpace()
218     {
219         return _bytesColonSpace;
220     }
221 
222     /* ------------------------------------------------------------ */
223     public boolean is(String s)
224     {
225         return _string.equalsIgnoreCase(s);    
226     }
227 
228     /* ------------------------------------------------------------ */
229     public String asString()
230     {
231         return _string;
232     }
233     
234     /* ------------------------------------------------------------ */
235     @Override
236     public String toString()
237     {
238         return _string;
239     }
240     
241 }
242