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 }