1 module hunt.http.HttpHeader;
2 
3 import hunt.logging;
4 import hunt.util.ObjectUtils;
5 
6 import std.algorithm;
7 import std.conv;
8 import std.string;
9 
10 bool contains(HttpHeader[] items, ref HttpHeader item) {
11     return items.canFind(item);
12 }
13 
14 /**
15 */
16 struct HttpHeader {
17     enum HttpHeader Null = HttpHeader("Null");
18 
19     /**
20      * General Fields.
21      */
22     enum HttpHeader CONNECTION = HttpHeader("Connection");
23     enum HttpHeader CACHE_CONTROL = HttpHeader("Cache-Control");
24     enum HttpHeader DATE = HttpHeader("Date");
25     enum HttpHeader PRAGMA = HttpHeader("Pragma");
26     enum HttpHeader PROXY_CONNECTION = HttpHeader("Proxy-Connection");
27     enum HttpHeader TRAILER = HttpHeader("Trailer");
28     enum HttpHeader TRANSFER_ENCODING = HttpHeader("Transfer-Encoding");
29     enum HttpHeader UPGRADE = HttpHeader("Upgrade");
30     enum HttpHeader VIA = HttpHeader("Via");
31     enum HttpHeader WARNING = HttpHeader("Warning");
32     enum HttpHeader NEGOTIATE = HttpHeader("Negotiate");
33 
34     /**
35      * Entity Fields.
36      */
37     enum HttpHeader ALLOW = HttpHeader("Allow");
38     enum HttpHeader CONTENT_DISPOSITION = HttpHeader("Content-Disposition");
39     enum HttpHeader CONTENT_ENCODING = HttpHeader("Content-Encoding");
40     enum HttpHeader CONTENT_LANGUAGE = HttpHeader("Content-Language");
41     enum HttpHeader CONTENT_LENGTH = HttpHeader("Content-Length");
42     enum HttpHeader CONTENT_LOCATION = HttpHeader("Content-Location");
43     enum HttpHeader CONTENT_MD5 = HttpHeader("Content-MD5");
44     enum HttpHeader CONTENT_RANGE = HttpHeader("Content-Range");
45     enum HttpHeader CONTENT_TYPE = HttpHeader("Content-Type");
46     enum HttpHeader EXPIRES = HttpHeader("Expires");
47     enum HttpHeader LAST_MODIFIED = HttpHeader("Last-Modified");
48 
49     /**
50      * Request Fields.
51      */
52     enum HttpHeader ACCEPT = HttpHeader("Accept");
53     enum HttpHeader ACCEPT_CHARSET = HttpHeader("Accept-Charset");
54     enum HttpHeader ACCEPT_ENCODING = HttpHeader("Accept-Encoding");
55     enum HttpHeader ACCEPT_LANGUAGE = HttpHeader("Accept-Language");
56     enum HttpHeader AUTHORIZATION = HttpHeader("Authorization");
57     enum HttpHeader EXPECT = HttpHeader("Expect");
58     enum HttpHeader FORWARDED = HttpHeader("Forwarded");
59     enum HttpHeader FROM = HttpHeader("From");
60     enum HttpHeader HOST = HttpHeader("Host");
61     enum HttpHeader IF_MATCH = HttpHeader("If-Match");
62     enum HttpHeader IF_MODIFIED_SINCE = HttpHeader("If-Modified-Since");
63     enum HttpHeader IF_NONE_MATCH = HttpHeader("If-None-Match");
64     enum HttpHeader IF_RANGE = HttpHeader("If-Range");
65     enum HttpHeader IF_UNMODIFIED_SINCE = HttpHeader("If-Unmodified-Since");
66     enum HttpHeader KEEP_ALIVE = HttpHeader("Keep-Alive");
67     enum HttpHeader MAX_FORWARDS = HttpHeader("Max-Forwards");
68     enum HttpHeader PROXY_AUTHORIZATION = HttpHeader("Proxy-Authorization");
69     enum HttpHeader RANGE = HttpHeader("Range");
70     enum HttpHeader REQUEST_RANGE = HttpHeader("Request-Range");
71     enum HttpHeader REFERER = HttpHeader("Referer");
72     enum HttpHeader TE = HttpHeader("TE");
73     enum HttpHeader USER_AGENT = HttpHeader("User-Agent");
74     enum HttpHeader X_FORWARDED_FOR = HttpHeader("X-Forwarded-For");
75     enum HttpHeader X_FORWARDED_PROTO = HttpHeader("X-Forwarded-Proto");
76     enum HttpHeader X_FORWARDED_SERVER = HttpHeader("X-Forwarded-Server");
77     enum HttpHeader X_FORWARDED_HOST = HttpHeader("X-Forwarded-Host");
78 
79     /**
80      * Response Fields.
81      */
82     enum HttpHeader ACCEPT_RANGES = HttpHeader("Accept-Ranges");
83     enum HttpHeader AGE = HttpHeader("Age");
84     enum HttpHeader ETAG = HttpHeader("ETag");
85     enum HttpHeader LOCATION = HttpHeader("Location");
86     enum HttpHeader PROXY_AUTHENTICATE = HttpHeader("Proxy-Authenticate");
87     enum HttpHeader RETRY_AFTER = HttpHeader("Retry-After");
88     enum HttpHeader SERVER = HttpHeader("Server");
89     enum HttpHeader SERVLET_ENGINE = HttpHeader("Servlet-Engine");
90     enum HttpHeader VARY = HttpHeader("Vary");
91     enum HttpHeader WWW_AUTHENTICATE = HttpHeader("WWW-Authenticate");
92 
93     /**
94      * WebSocket Fields.
95      */
96     enum HttpHeader ORIGIN = HttpHeader("Origin");
97     enum HttpHeader SEC_WEBSOCKET_KEY = HttpHeader("Sec-WebSocket-Key");
98     enum HttpHeader SEC_WEBSOCKET_VERSION = HttpHeader("Sec-WebSocket-Version");
99     enum HttpHeader SEC_WEBSOCKET_EXTENSIONS = HttpHeader("Sec-WebSocket-Extensions");
100     enum HttpHeader SEC_WEBSOCKET_SUBPROTOCOL = HttpHeader("Sec-WebSocket-Protocol");
101     enum HttpHeader SEC_WEBSOCKET_ACCEPT = HttpHeader("Sec-WebSocket-Accept");
102 
103     /**
104      * Other Fields.
105      */
106     enum HttpHeader COOKIE = HttpHeader("Cookie");
107     enum HttpHeader SET_COOKIE = HttpHeader("Set-Cookie");
108     enum HttpHeader SET_COOKIE2 = HttpHeader("Set-Cookie2");
109     enum HttpHeader MIME_VERSION = HttpHeader("MIME-Version");
110     enum HttpHeader IDENTITY = HttpHeader("identity");
111 
112     enum HttpHeader X_POWERED_BY = HttpHeader("X-Powered-By");
113     enum HttpHeader HTTP2_SETTINGS = HttpHeader("HTTP2-Settings");
114 
115     enum HttpHeader STRICT_TRANSPORT_SECURITY = HttpHeader("Strict-Transport-Security");
116 
117     /**
118      * HTTP2 Fields.
119      */
120     enum HttpHeader C_METHOD = HttpHeader(":method");
121     enum HttpHeader C_SCHEME = HttpHeader(":scheme");
122     enum HttpHeader C_AUTHORITY = HttpHeader(":authority");
123     enum HttpHeader C_PATH = HttpHeader(":path");
124     enum HttpHeader C_STATUS = HttpHeader(":status");
125 
126     enum HttpHeader UNKNOWN = HttpHeader("::UNKNOWN::");
127 
128     private __gshared HttpHeader[string] CACHE;
129 
130     static bool exists(string name) {
131         return (name.toLower() in CACHE) !is null;
132     }
133 
134     static HttpHeader get(string name) {
135         return CACHE.get(name.toLower(), HttpHeader.Null);
136     }
137 
138     static int getCount() {
139         return cast(int) CACHE.length;
140     }
141 
142     shared static this() {
143         int i = 0;
144         foreach (ref HttpHeader header; HttpHeader.values()) {
145             // header._ordinal = i++;
146             if (header != UNKNOWN)
147                 CACHE[header.asString().toLower()] = header;
148         }
149 
150         // trace(CACHE);
151         // foreach(ref HttpHeader header; HttpHeader.values())
152         // {
153         //     tracef("xx=%d", header._ordinal);
154         // }
155     }
156 
157     mixin ValuesMemberTempate!(HttpHeader);
158 
159     private int _ordinal;
160     private string _string;
161     private byte[] _bytes;
162     private byte[] _bytesColonSpace;
163     // private ByteBuffer _buffer;
164 
165     this(string s) {
166         // tracef("<%s>", s);
167         _string = s;
168         _bytes = cast(byte[]) s.dup; // StringUtils.getBytes(s);
169         _bytesColonSpace = cast(byte[])(_string ~ ": ").dup;
170         _ordinal = cast(int) hashOf(s.toLower());
171         // _buffer = BufferUtils.toBuffer(_bytes);
172     }
173 
174     // ByteBuffer toBuffer() {
175     //     return _buffer.asReadOnlyBuffer();
176     // }
177 
178     byte[] getBytes() {
179         return _bytes;
180     }
181 
182     byte[] getBytesColonSpace() {
183         return _bytesColonSpace;
184     }
185 
186     bool isSame(string s) const nothrow {
187         return std..string.icmp(_string, s) == 0;
188     }
189 
190     string asString() const nothrow {
191         return _string;
192     }
193 
194     string toString() {
195         return _string;
196     }
197 
198     int ordinal() {
199         return _ordinal;
200     }
201 
202     size_t toHash() @trusted nothrow {
203         return hashOf(_string);
204     }
205 
206     bool opEquals(const HttpHeader h) nothrow {
207         return std..string.cmp(_string, h._string) == 0;
208     }
209 
210     bool opEquals(ref const HttpHeader h) nothrow {
211         return std..string.cmp(_string, h._string) == 0;
212     }
213 
214     // bool opEquals(const HttpHeader h) const nothrow{
215     //     return isSame(h.asString());
216     // } 
217 }
218 
219 // import hunt.io.ByteBuffer;
220 // import java.nio.charset.StandardCharsets;
221 // import java.util.EnumSet;
222 
223 // import hunt.http.utils.collection.ArrayTrie;
224 // import hunt.http.utils.collection.Trie;
225 
226 /**
227  * 
228  */
229 struct HttpHeaderValue {
230 
231 	enum HttpHeaderValue CLOSE = HttpHeaderValue("close");
232     enum HttpHeaderValue CHUNKED = HttpHeaderValue("chunked");
233     enum HttpHeaderValue GZIP = HttpHeaderValue("gzip");
234     enum HttpHeaderValue IDENTITY = HttpHeaderValue("identity");
235     enum HttpHeaderValue KEEP_ALIVE = HttpHeaderValue("keep-alive");
236     enum HttpHeaderValue CONTINUE = HttpHeaderValue("100-continue");
237     enum HttpHeaderValue PROCESSING = HttpHeaderValue("102-processing");
238     enum HttpHeaderValue TE = HttpHeaderValue("TE");
239     enum HttpHeaderValue BYTES = HttpHeaderValue("bytes");
240     enum HttpHeaderValue NO_CACHE = HttpHeaderValue("no-cache");
241     enum HttpHeaderValue UPGRADE = HttpHeaderValue("Upgrade");
242     enum HttpHeaderValue UNKNOWN = HttpHeaderValue("::UNKNOWN::");	
243 
244 
245 	private enum HttpHeader[] __known = [
246 			HttpHeader.CONNECTION, 
247 			HttpHeader.TRANSFER_ENCODING,
248 			HttpHeader.CONTENT_ENCODING
249 			];
250 	
251 	__gshared HttpHeaderValue[string] CACHE; 
252 
253 	shared static this() {
254 		foreach (ref HttpHeaderValue value ; HttpHeaderValue.values())
255         {
256             if (value != UNKNOWN)
257                 CACHE[value.toString()] = value;
258 		}
259 	}
260 
261 	mixin ValuesMemberTempate!(HttpHeaderValue);
262 
263 	private string _string;
264 	// private ByteBuffer buffer;
265 	
266 	private this(string s) {
267 		_string = s;
268 		// buffer = BufferUtils.toBuffer(s.getBytes(StandardCharsets.UTF_8));
269 	}
270 
271 	// ByteBuffer toBuffer() {
272 	// 	return buffer.asReadOnlyBuffer();
273 	// }
274 
275     bool isSame(string s) {
276         return s.length != 0 && std..string.icmp(_string, s) == 0;
277     }
278 
279 	string asString() {
280 		return _string;
281 	}
282 
283 	string toString() {
284 		return _string;
285 	}
286 
287 	static bool hasKnownValues(HttpHeader header) {
288 		if (header == HttpHeader.Null)
289 			return false;
290 		return __known.canFind(header);
291 	}
292 }