1 module archttp.Cookie; 2 3 import std.uri; 4 import std.format; 5 import std.array; 6 7 class Cookie 8 { 9 @safe: 10 11 private 12 { 13 string _name; 14 string _value; 15 string _domain; 16 string _path; 17 string _expires; 18 long _maxAge; 19 bool _secure; 20 bool _httpOnly; 21 } 22 23 this(string name, string value = "", string path = "/", string domain = "", string expires = "", long maxAge = 3600, bool secure = false, bool httpOnly = false) 24 { 25 _name = name; 26 27 this.value(value) 28 .domain(domain) 29 .path(path) 30 .expires(expires) 31 .maxAge(maxAge) 32 .secure(secure) 33 .httpOnly(httpOnly); 34 } 35 36 Cookie parse(string cookieString) 37 { 38 // if (!cookieString.length) 39 // return null; 40 41 // auto parts = cookieString.splitter(';'); 42 // auto idx = parts.front.indexOf('='); 43 // if (idx == -1) 44 // return null; 45 46 // auto name = parts.front[0 .. idx].strip(); 47 // dst.m_value = parts.front[name.length + 1 .. $].strip(); 48 // parts.popFront(); 49 50 // if (!name.length) 51 // return null; 52 53 // foreach(part; parts) { 54 // if (!part.length) 55 // continue; 56 57 // idx = part.indexOf('='); 58 // if (idx == -1) { 59 // idx = part.length; 60 // } 61 // auto key = part[0 .. idx].strip(); 62 // auto value = part[min(idx + 1, $) .. $].strip(); 63 64 // try { 65 // if (key.sicmp("httponly") == 0) { 66 // dst.m_httpOnly = true; 67 // } else if (key.sicmp("secure") == 0) { 68 // dst.m_secure = true; 69 // } else if (key.sicmp("expires") == 0) { 70 // // RFC 822 got updated by RFC 1123 (which is to be used) but is valid for this 71 // // this parsing is just for validation 72 // parseRFC822DateTimeString(value); 73 // dst.m_expires = value; 74 // } else if (key.sicmp("max-age") == 0) { 75 // if (value.length && value[0] != '-') 76 // dst.m_maxAge = value.to!long; 77 // } else if (key.sicmp("domain") == 0) { 78 // if (value.length && value[0] == '.') 79 // value = value[1 .. $]; // the leading . must be stripped (5.2.3) 80 81 // enforce!ConvException(value.all!(a => a >= 32), "Cookie Domain must not contain any control characters"); 82 // dst.m_domain = value.toLower; // must be lower (5.2.3) 83 // } else if (key.sicmp("path") == 0) { 84 // if (value.length && value[0] == '/') { 85 // enforce!ConvException(value.all!(a => a >= 32), "Cookie Path must not contain any control characters"); 86 // dst.m_path = value; 87 // } else { 88 // dst.m_path = null; 89 // } 90 // } // else extension value... 91 // } catch (DateTimeException) { 92 // } catch (ConvException) { 93 // } 94 // // RFC 6265 says to ignore invalid values on all of these fields 95 // } 96 // return name; 97 return null; 98 } 99 100 string name() const 101 { 102 return _name; 103 } 104 105 Cookie value(string value) 106 { 107 _value = encode(value); 108 return this; 109 } 110 111 string value() const 112 { 113 return decode(_value); 114 } 115 116 Cookie domain(string value) 117 { 118 _domain = value; 119 return this; 120 } 121 122 string domain() const 123 { 124 return _domain; 125 } 126 127 Cookie path(string value) 128 { 129 _path = value; 130 return this; 131 } 132 133 string path() const 134 { 135 return _path; 136 } 137 138 Cookie expires(string value) 139 { 140 _expires = value; 141 return this; 142 } 143 144 string expires() const 145 { 146 return _expires; 147 } 148 149 Cookie maxAge(long value) 150 { 151 _maxAge = value; 152 return this; 153 } 154 155 long maxAge() const 156 { 157 return _maxAge; 158 } 159 160 Cookie secure(bool value) 161 { 162 _secure = value; 163 return this; 164 } 165 166 bool secure() const 167 { 168 return _secure; 169 } 170 171 Cookie httpOnly(bool value) 172 { 173 _httpOnly = value; 174 return this; 175 } 176 177 bool httpOnly() const 178 { 179 return _httpOnly; 180 } 181 182 override string toString() 183 { 184 auto text = appender!string; 185 text ~= format!"%s=%s"(this._name, this.value()); 186 187 if (this._domain && this._domain != "") 188 { 189 text ~= format!"; Domain=%s"(this._domain); 190 } 191 192 if (this._path != "") 193 { 194 text ~= format!"; Path=%s"(this._path); 195 } 196 197 if (this.expires != "") 198 { 199 text ~= format!"; Expires=%s"(this._expires); 200 } 201 202 if (this.maxAge) 203 text ~= format!"; Max-Age=%s"(this._maxAge); 204 205 if (this.secure) 206 text ~= "; Secure"; 207 208 if (this.httpOnly) 209 text ~= "; HttpOnly"; 210 211 return text[]; 212 } 213 }