1 module hunt.http.codec.http.model.MetaData; 2 3 import hunt.container; 4 5 import hunt.http.codec.http.model.HttpHeader; 6 import hunt.http.codec.http.model.HttpField; 7 import hunt.http.codec.http.model.HttpFields; 8 import hunt.http.codec.http.model.HostPortHttpField; 9 import hunt.http.codec.http.model.HttpScheme; 10 import hunt.http.codec.http.model.HttpURI; 11 import hunt.http.codec.http.model.HttpVersion; 12 13 import hunt.lang.common; 14 import hunt.string.common; 15 import hunt.string.StringBuilder; 16 17 import std.ascii; 18 import std.format; 19 import std.range; 20 21 22 alias HttpRequest = MetaData.Request; 23 alias HttpResponse = MetaData.Response; 24 25 /** 26 */ 27 class MetaData : Iterable!HttpField { 28 private HttpVersion _httpVersion; 29 private HttpFields _fields; 30 private long _contentLength; 31 private Supplier!HttpFields _trailers; 32 33 this(HttpVersion ver, HttpFields fields) { 34 this(ver, fields, long.min); 35 } 36 37 this(HttpVersion ver, HttpFields fields, long contentLength) { 38 _httpVersion = ver; 39 _fields = fields; 40 _contentLength = contentLength; 41 } 42 43 protected void recycle() { 44 _httpVersion = HttpVersion.Null; 45 if (_fields !is null) 46 _fields.clear(); 47 _contentLength = long.min; 48 } 49 50 bool isRequest() { 51 return false; 52 } 53 54 bool isResponse() { 55 return false; 56 } 57 58 /** 59 * @deprecated use {@link #getHttpVersion()} instead 60 */ 61 // deprecated("") 62 // HttpVersion getVersion() { 63 // return getHttpVersion(); 64 // } 65 66 /** 67 * @return the HTTP version of this MetaData object 68 */ 69 HttpVersion getHttpVersion() { 70 return _httpVersion; 71 } 72 73 /** 74 * @param httpVersion the HTTP version to set 75 */ 76 void setHttpVersion(HttpVersion httpVersion) { 77 _httpVersion = httpVersion; 78 } 79 80 /** 81 * @return the HTTP fields of this MetaData object 82 */ 83 HttpFields getFields() { 84 return _fields; 85 } 86 87 Supplier!HttpFields getTrailerSupplier() { 88 return _trailers; 89 } 90 91 void setTrailerSupplier(Supplier!HttpFields trailers) { 92 _trailers = trailers; 93 } 94 95 /** 96 * @return the content length if available, otherwise {@link Long#MIN_VALUE} 97 */ 98 long getContentLength() { 99 if (_contentLength == long.min) { 100 if (_fields !is null) { 101 HttpField field = _fields.getField(HttpHeader.CONTENT_LENGTH); 102 _contentLength = field is null ? -1 : field.getLongValue(); 103 } 104 } 105 return _contentLength; 106 } 107 108 /** 109 * @return an iterator over the HTTP fields 110 * @see #getFields() 111 */ 112 InputRange!HttpField iterator() { 113 return _fields is null ? inputRangeObject(new HttpField[0]) : _fields.iterator(); 114 } 115 116 117 int opApply(scope int delegate(ref HttpField) dg) 118 { 119 int result = 0; 120 foreach(HttpField v; _fields) 121 { 122 result = dg(v); 123 if(result != 0) return result; 124 } 125 return result; 126 } 127 128 override 129 string toString() { 130 StringBuilder sb = new StringBuilder(); 131 foreach (HttpField field ; _fields) 132 sb.append(field.toString()).append(std.ascii.newline); 133 return sb.toString(); 134 } 135 136 static class Request : MetaData { 137 private string _method; 138 private HttpURI _uri; 139 private Object attachment; 140 141 this(HttpFields fields) { 142 this("", null, HttpVersion.Null, fields); 143 } 144 145 // this(string method, HttpURI uri, HttpVersion ver, HttpFields fields) { 146 // this(method, uri, ver, fields, long.min); 147 // } 148 149 this(string method, HttpURI uri, HttpVersion ver, HttpFields fields, long contentLength=long.min) { 150 super(ver, fields, contentLength); 151 _method = method; 152 _uri = uri; 153 } 154 155 // this(string method, HttpScheme scheme, HostPortHttpField hostPort, string uri, HttpVersion ver, HttpFields fields) { 156 // this(method, new HttpURI(scheme.toString(), hostPort.getHost(), hostPort.getPort(), uri), ver, fields); 157 // } 158 159 // this(string method, HttpScheme scheme, HostPortHttpField hostPort, string uri, HttpVersion ver, HttpFields fields, long contentLength) { 160 // this(method, new HttpURI( scheme.toString(), hostPort.getHost(), hostPort.getPort(), uri), ver, fields, contentLength); 161 // } 162 163 this(string method, string scheme, HostPortHttpField hostPort, string uri, HttpVersion ver, HttpFields fields, long contentLength=long.min) { 164 this(method, new HttpURI(scheme, hostPort.getHost(), hostPort.getPort(), uri), ver, fields, contentLength); 165 } 166 167 this(Request request) { 168 this(request.getMethod(), new HttpURI(request.getURI()), request.getHttpVersion(), 169 new HttpFields(request.getFields()), request.getContentLength()); 170 } 171 172 override void recycle() { 173 super.recycle(); 174 _method = null; 175 if (_uri !is null) 176 _uri.clear(); 177 } 178 179 override 180 bool isRequest() { 181 return true; 182 } 183 184 /** 185 * @return the HTTP method 186 */ 187 string getMethod() { 188 return _method; 189 } 190 191 /** 192 * @param method the HTTP method to set 193 */ 194 void setMethod(string method) { 195 _method = method; 196 } 197 198 /** 199 * @return the HTTP URI 200 */ 201 HttpURI getURI() { 202 return _uri; 203 } 204 205 /** 206 * @return the HTTP URI in string form 207 */ 208 string getURIString() { 209 return _uri is null ? null : _uri.toString(); 210 } 211 212 /** 213 * @param uri the HTTP URI to set 214 */ 215 void setURI(HttpURI uri) { 216 _uri = uri; 217 } 218 219 Object getAttachment() { 220 return attachment; 221 } 222 223 void setAttachment(Object attachment) { 224 this.attachment = attachment; 225 } 226 227 override 228 string toString() { 229 HttpFields fields = getFields(); 230 return format("%s{u=%s,%s,h=%d,cl=%d}", 231 getMethod(), getURI(), getHttpVersion(), fields is null ? -1 : fields.size(), getContentLength()); 232 } 233 } 234 235 static class Response : MetaData { 236 private int _status; 237 private string _reason; 238 239 this() { 240 this(HttpVersion.Null, 0, null); 241 } 242 243 this(HttpVersion ver, int status, HttpFields fields) { 244 this(ver, status, fields, long.min); 245 } 246 247 this(HttpVersion ver, int status, HttpFields fields, long contentLength) { 248 super(ver, fields, contentLength); 249 _status = status; 250 } 251 252 this(HttpVersion ver, int status, string reason, HttpFields fields, long contentLength) { 253 super(ver, fields, contentLength); 254 _reason = reason; 255 _status = status; 256 } 257 258 override 259 bool isResponse() { 260 return true; 261 } 262 263 /** 264 * @return the HTTP status 265 */ 266 int getStatus() { 267 return _status; 268 } 269 270 /** 271 * @return the HTTP reason 272 */ 273 string getReason() { 274 return _reason; 275 } 276 277 /** 278 * @param status the HTTP status to set 279 */ 280 void setStatus(int status) { 281 _status = status; 282 } 283 284 /** 285 * @param reason the HTTP reason to set 286 */ 287 void setReason(string reason) { 288 _reason = reason; 289 } 290 291 override 292 string toString() { 293 HttpFields fields = getFields(); 294 return format("%s{s=%d,h=%d,cl=%d}", getHttpVersion(), getStatus(), fields is null ? -1 : fields.size(), getContentLength()); 295 } 296 } 297 }