1 module hunt.http.HttpRequest;
2
3 import hunt.http.HttpField;
4 import hunt.http.HttpFields;
5 import hunt.http.HttpHeader;
6 import hunt.http.HttpMetaData;
7 import hunt.http.HttpScheme;
8 import hunt.http.HttpVersion;
9
10 import hunt.collection;
11 import hunt.Functions;
12 import hunt.Exceptions;
13 import hunt.logging;
14 import hunt.net.util.HttpURI;
15 import hunt.text.Common;
16 import hunt.util.StringBuilder;
17 import hunt.util.Common;
18
19 import std.ascii;
20 import std.format;
21 import std.range;
22
23
24 version(WITH_HUNT_TRACE) {
25 import hunt.trace.Tracer;
26 }
27
28 /**
29 *
30 */
31 class HttpRequest : HttpMetaData {
32 private string _method;
33 private HttpURI _uri;
34 private Object[string] _attributes;
35
36 this(HttpFields fields) {
37 this("", null, HttpVersion.Null, fields);
38 }
39
40 // this(string method, HttpURI uri, HttpVersion ver, HttpFields fields) {
41 // this(method, uri, ver, fields, long.min);
42 // }
43
44
45 this(string method, string scheme, string host, int port, string uri,
46 HttpVersion ver, HttpFields fields, long contentLength=long.min) {
47 this(method, new HttpURI(scheme, host, port, uri), ver, fields, contentLength);
48 }
49
50 this(HttpRequest request) {
51 this(request.getMethod(), new HttpURI(request.getURI()), request.getHttpVersion(),
52 new HttpFields(request.getFields()), request.getContentLength());
53 }
54
55 this(string method, HttpURI uri, HttpVersion ver, HttpFields fields, long contentLength=long.min) {
56 super(ver, fields, contentLength);
57 _method = method;
58 _uri = uri;
59
60 }
61
62 override void recycle() {
63 super.recycle();
64 _method = null;
65 if (_uri !is null)
66 _uri.clear();
67 }
68
69 override bool isRequest() {
70 return true;
71 }
72
73 /**
74 * Checks whether the request is secure or not.
75 *
76 * This method can read the client protocol from the "X-Forwarded-Proto" header
77 * when trusted proxies were set via "setTrustedProxies()".
78 *
79 * The "X-Forwarded-Proto" header must contain the protocol: "https" or "http".
80 *
81 * @return bool
82 */
83 bool isHttps() {
84 // FIXME: Needing refactor or cleanup -@zhangxueping at 2020-04-16T11:28:15+08:00
85 //
86 string scheme = _uri.getScheme();
87 return scheme == HttpScheme.HTTPS || scheme == HttpScheme.WSS;
88 }
89
90 /**
91 * @return the HTTP method
92 */
93 string getMethod() {
94 return _method;
95 }
96
97 /**
98 * @param method the HTTP method to set
99 */
100 void setMethod(string method) {
101 _method = method;
102 }
103
104 /**
105 * @return the HTTP URI
106 */
107 HttpURI getURI() {
108 return _uri;
109 }
110
111 /**
112 * @return the HTTP URI in string form
113 */
114 string getURIString() {
115 return _uri is null ? null : _uri.toString();
116 }
117
118 /**
119 * @param uri the HTTP URI to set
120 */
121 void setURI(HttpURI uri) {
122 _uri = uri;
123 }
124
125 bool headerExists(HttpHeader header) {
126 return getFields().containsKey(header.asString());
127 }
128
129 bool headerExists(string key) {
130 return getFields().containsKey(key);
131 }
132
133 bool isChunked() {
134 string transferEncoding = getFields().get(HttpHeader.TRANSFER_ENCODING);
135 return HttpHeaderValue.CHUNKED.asString() == transferEncoding
136 || (getHttpVersion() == HttpVersion.HTTP_2 && getContentLength() < 0);
137 }
138
139 deprecated("Using getAttribute instead.")
140 Object getAttachment() {
141 return getAttribute("_attachment");
142 }
143
144 deprecated("Using setAttribute instead.")
145 void setAttachment(Object attachment) {
146 // this.attachment = attachment;
147 setAttribute("_attachment", attachment);
148 }
149
150 /**
151 * Returns the value of the user-defined attribute of this connection.
152 *
153 * @param key the key of the attribute
154 * @return <tt>null</tt> if there is no attribute with the specified key
155 */
156 Object getAttribute(string key) {
157 return getAttribute(key, null);
158 }
159
160 /**
161 * Returns the value of user defined attribute associated with the
162 * specified key. If there's no such attribute, the specified default
163 * value is associated with the specified key, and the default value is
164 * returned. This method is same with the following code except that the
165 * operation is performed atomically.
166 * <pre>
167 * if (containsAttribute(key)) {
168 * return getAttribute(key);
169 * } else {
170 * setAttribute(key, defaultValue);
171 * return defaultValue;
172 * }
173 * </pre>
174 *
175 * @param key the key of the attribute we want to retreive
176 * @param defaultValue the default value of the attribute
177 * @return The retrieved attribute or <tt>null</tt> if not found
178 */
179 Object getAttribute(string key, Object defaultValue) {
180 return _attributes.get(key, defaultValue);
181 }
182
183 /**
184 * Sets a user-defined attribute.
185 *
186 * @param key the key of the attribute
187 * @param value the value of the attribute
188 * @return The old value of the attribute. <tt>null</tt> if it is new.
189 */
190 Object setAttribute(string key, Object value) {
191 auto itemPtr = key in _attributes;
192 Object oldValue = null;
193 if(itemPtr !is null) {
194 oldValue = *itemPtr;
195 }
196 _attributes[key] = value;
197 return oldValue;
198 }
199
200 /**
201 * Removes a user-defined attribute with the specified key.
202 *
203 * @param key The key of the attribute we want to remove
204 * @return The old value of the attribute. <tt>null</tt> if not found.
205 */
206 Object removeAttribute(string key) {
207 auto itemPtr = key in _attributes;
208 if(itemPtr is null) {
209 return null;
210 } else {
211 Object oldValue = *itemPtr;
212 _attributes.remove(key);
213 return oldValue;
214 }
215 }
216
217 /**
218 * @param key The key of the attribute we are looking for in the connection
219 * @return <tt>true</tt> if this connection contains the attribute with
220 * the specified <tt>key</tt>.
221 */
222 bool containsAttribute(string key) {
223 auto itemPtr = key in _attributes;
224 return itemPtr !is null;
225 }
226
227 /**
228 * @return the set of keys of all user-defined attributes.
229 */
230 string[] getAttributeKeys() {
231 return _attributes.keys();
232 }
233
234 override string toString() {
235 HttpFields fields = getFields();
236 return format("%s{u=%s,%s,h=%d,cl=%d}",
237 getMethod(), getURI(), getHttpVersion(), fields is null ? -1 : fields.size(), getContentLength());
238 }
239
240 version(WITH_HUNT_TRACE) {
241 Tracer tracer;
242 }
243
244 }