1 module hunt.http.codec.http.hpack.MetaDataBuilder; 2 3 import hunt.http.codec.http.hpack.AuthorityHttpField; 4 import hunt.http.codec.http.model.BadMessageException; 5 import hunt.http.codec.http.model.HostPortHttpField; 6 import hunt.http.codec.http.model.HttpField; 7 import hunt.http.codec.http.model.HttpFields; 8 import hunt.http.codec.http.model.HttpHeader; 9 import hunt.http.codec.http.model.HttpScheme; 10 import hunt.http.codec.http.model.HttpStatus; 11 import hunt.http.codec.http.model.HttpVersion; 12 import hunt.http.codec.http.model.MetaData; 13 import hunt.http.codec.http.model.StaticTableHttpField; 14 15 import hunt.lang.exception; 16 17 import std.algorithm; 18 import std.array; 19 import std.conv; 20 21 import hunt.logging; 22 23 /** 24 */ 25 class MetaDataBuilder { 26 private int _maxSize; 27 private int _size; 28 private int _status; 29 private string _method; 30 private string _scheme; 31 private HostPortHttpField _authority; 32 private string _path; 33 private long _contentLength = long.min; 34 private HttpFields _fields; 35 36 /** 37 * @param maxHeadersSize 38 * The maximum size of the headers, expressed as total name and 39 * value characters. 40 */ 41 this(int maxHeadersSize) { 42 _maxSize = maxHeadersSize; 43 _fields = new HttpFields(10); 44 } 45 46 /** 47 * Get the maxSize. 48 * 49 * @return the maxSize 50 */ 51 int getMaxSize() { 52 return _maxSize; 53 } 54 55 /** 56 * Get the size. 57 * 58 * @return the current size in bytes 59 */ 60 int getSize() { 61 return _size; 62 } 63 64 void emit(HttpField field) { 65 HttpHeader header = field.getHeader(); 66 string name = field.getName(); 67 string value = field.getValue(); 68 int field_size = cast(int)(name.length + (value == null ? 0 : value.length)); 69 _size += field_size + 32; 70 if (_size > _maxSize) 71 throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, 72 "Header size " ~ to!string(_size) ~ ">" ~ to!string(_maxSize)); 73 74 string fieldTypeName = typeof(field).stringof; 75 // trace("fieldTypeName: ", fieldTypeName); 76 if (fieldTypeName.startsWith("StaticTableHttpField")) { 77 if(header == HttpHeader.C_STATUS){ 78 StaticTableHttpField!int staticField = cast(StaticTableHttpField!int) field; 79 _status = staticField.getStaticValue(); 80 } 81 else if(header == HttpHeader.C_METHOD){ 82 _method = value; 83 } 84 else if(header == HttpHeader.C_SCHEME){ 85 StaticTableHttpField!string staticField = cast(StaticTableHttpField!string) field; 86 _scheme = staticField.getStaticValue(); 87 } 88 else 89 throw new IllegalArgumentException(name); 90 91 } else if (header != HttpHeader.Null) { 92 if(header == HttpHeader.C_STATUS) 93 _status = field.getIntValue(); 94 else if(header == HttpHeader.C_METHOD) 95 _method = value; 96 else if(header == HttpHeader.C_SCHEME){ 97 if (value != null) 98 _scheme = value; // HttpScheme.CACHE[value]; 99 } 100 else if(header == HttpHeader.C_AUTHORITY) { 101 if (typeid(field) == typeid(HostPortHttpField)) 102 _authority = cast(HostPortHttpField) field; 103 else if (value != null) 104 _authority = new AuthorityHttpField(value); 105 } 106 else if(header == HttpHeader.HOST){ 107 // :authority fields must come first. If we have one, ignore the 108 // host header as far as authority goes. 109 if (_authority is null) { 110 if (typeid(field) == typeid(HostPortHttpField)) 111 _authority = cast(HostPortHttpField) field; 112 else if (value != null) 113 _authority = new AuthorityHttpField(value); 114 } 115 _fields.add(field); 116 } 117 else if(header == HttpHeader.C_PATH) 118 _path = value; 119 else if(header == HttpHeader.CONTENT_LENGTH) { 120 _contentLength = field.getLongValue(); 121 _fields.add(field); 122 } 123 else 124 { 125 if (name[0] != ':') 126 _fields.add(field); 127 } 128 } else { 129 if (name[0] != ':') 130 _fields.add(field); 131 } 132 } 133 134 MetaData build() { 135 try { 136 HttpFields fields = _fields; 137 _fields = new HttpFields(std.algorithm.max(10, fields.size() + 5)); 138 139 if (!_method.empty) 140 return new HttpRequest(_method, _scheme, _authority, _path, HttpVersion.HTTP_2, fields, 141 _contentLength); 142 if (_status != 0) 143 return new HttpResponse(HttpVersion.HTTP_2, _status, fields, _contentLength); 144 return new MetaData(HttpVersion.HTTP_2, fields, _contentLength); 145 } finally { 146 _status = 0; 147 _method = null; 148 _scheme = null; 149 _authority = null; 150 _path = null; 151 _size = 0; 152 _contentLength = long.min; 153 } 154 } 155 156 /** 157 * Check that the max size will not be exceeded. 158 * 159 * @param length 160 * the length 161 * @param huffman 162 * the huffman name 163 */ 164 void checkSize(int length, bool huffman) { 165 // Apply a huffman fudge factor 166 if (huffman) 167 length = (length * 4) / 3; 168 if ((_size + length) > _maxSize) 169 throw new BadMessageException(HttpStatus.REQUEST_HEADER_FIELDS_TOO_LARGE_431, 170 "Header size " ~ to!string(_size + length) ~ ">" ~ to!string(_maxSize)); 171 } 172 }