1 module hunt.http.codec.http.model.HttpVersion;
2 
3 import hunt.container.ByteBuffer;
4 
5 // import java.nio.charset.StandardCharsets;
6 
7 import hunt.util.traits;
8 import hunt.lang.exception;
9 
10 import std.ascii;
11 import std.string;
12 
13 // import hunt.http.utils.collection.ArrayTrie;
14 // import hunt.http.utils.collection.Trie;
15 
16 struct HttpVersion {
17 	enum HttpVersion Null = HttpVersion("null", 0);
18 	enum HttpVersion HTTP_0_9 = HttpVersion("HTTP/0.9", 9);
19 	enum HttpVersion HTTP_1_0 = HttpVersion("HTTP/1.0", 10);
20 	enum HttpVersion HTTP_1_1 = HttpVersion("HTTP/1.1", 11);
21 	enum HttpVersion HTTP_2 = HttpVersion("HTTP/2.0", 20);
22 
23 	private __gshared HttpVersion[string] CACHE;
24 
25 	shared static this() {
26 		foreach (HttpVersion ver; HttpVersion.values())
27 			CACHE[ver.toString()] = ver;
28 	}
29 
30 	mixin GetConstantValues!(HttpVersion);
31 
32 	/**
33 	 * Optimized lookup to find a HTTP Version and whitespace in a byte array.
34 	 * 
35 	 * @param bytes
36 	 *            Array containing ISO-8859-1 characters
37 	 * @param position
38 	 *            The first valid index
39 	 * @param limit
40 	 *            The first non valid index
41 	 * @return A HttpMethod if a match or null if no easy match.
42 	 */
43 	static HttpVersion lookAheadGet(byte[] bytes, int position, int limit) {
44 		int length = limit - position;
45 		if (length < 9)
46 			return HttpVersion.Null;
47 
48 		if (bytes[position + 4] == '/' && bytes[position + 6] == '.'
49 				&& std.ascii.isWhite(cast(char) bytes[position + 8])
50 				&& ((bytes[position] == 'H' && bytes[position + 1] == 'T'
51 					&& bytes[position + 2] == 'T' && bytes[position + 3] == 'P') || (bytes[position] == 'h'
52 					&& bytes[position + 1] == 't' && bytes[position + 2] == 't'
53 					&& bytes[position + 3] == 'p'))) {
54 			switch (bytes[position + 5]) {
55 			case '1':
56 				switch (bytes[position + 7]) {
57 				case '0':
58 					return HTTP_1_0;
59 				case '1':
60 					return HTTP_1_1;
61 				default:
62 					break;
63 				}
64 				break;
65 			case '2':
66 				if (bytes[position + 7] == '0') {
67 					return HTTP_2;
68 				}
69 				break;
70 
71 			default:
72 				break;
73 			}
74 		}
75 
76 		return HttpVersion.Null;
77 	}
78 
79 	/**
80 	 * Optimised lookup to find a HTTP Version and trailing white space in a
81 	 * byte array.
82 	 * 
83 	 * @param buffer
84 	 *            buffer containing ISO-8859-1 characters
85 	 * @return A HttpVersion if a match or null if no easy match.
86 	 */
87 	static HttpVersion lookAheadGet(ByteBuffer buffer) {
88 		if (buffer.hasArray())
89 			return lookAheadGet(buffer.array(), buffer.arrayOffset() + buffer.position(),
90 					buffer.arrayOffset() + buffer.limit());
91 		return HttpVersion.Null;
92 	}
93 
94 	private string _string;
95 	private byte[] _bytes;
96 	// private ByteBuffer _buffer;
97 	private int _version;
98 
99 	this(string s, int ver) {
100 		_string = s;
101 		_bytes = cast(byte[]) s.dup;
102 		// _buffer = ByteBuffer.wrap(_bytes);
103 		_version = ver;
104 	}
105 
106 	byte[] toBytes() {
107 		return _bytes;
108 	}
109 
110 	// ByteBuffer toBuffer() {
111 	// 	return _buffer.asReadOnlyBuffer();
112 	// }
113 
114 	int getVersion() {
115 		return _version;
116 	}
117 
118 	bool isSame(string s) {
119 		return s.length != 0 && std..string.icmp(_string, s) == 0;
120 	}
121 
122 	string asString() {
123 		return _string;
124 	}
125 
126 	string toString() {
127 		return _string;
128 	}
129 
130 	int opCmp(ref const HttpVersion h) const {
131 		if (_version > h._version)
132 			return 1;
133 		else if (_version == h._version)
134 			return 0;
135 		else
136 			return -1;
137 	}
138 
139 	int opCmp(const HttpVersion h) const {
140 		if (_version > h._version)
141 			return 1;
142 		else if (_version == h._version)
143 			return 0;
144 		else
145 			return -1;
146 	}
147 
148 	/**
149 	 * Case insensitive fromString() conversion
150 	 * 
151 	 * @param version
152 	 *            the string to convert to enum constant
153 	 * @return the enum constant or null if version unknown
154 	 */
155 	static HttpVersion fromString(string ver) {
156 		return CACHE.get(ver, HttpVersion.Null);
157 	}
158 
159 	static HttpVersion fromVersion(int ver) {
160 		switch (ver) {
161 		case 9:
162 			return HttpVersion.HTTP_0_9;
163 		case 10:
164 			return HttpVersion.HTTP_1_0;
165 		case 11:
166 			return HttpVersion.HTTP_1_1;
167 		case 20:
168 			return HttpVersion.HTTP_2;
169 		default:
170 			throw new IllegalArgumentException("");
171 		}
172 	}
173 }