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 }