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