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 }