|
8 | 8 | "bytes"
|
9 | 9 | "fmt"
|
10 | 10 | "log"
|
| 11 | + "net" |
11 | 12 | "strconv"
|
12 | 13 | "strings"
|
13 | 14 | "time"
|
@@ -145,7 +146,15 @@ func (c *Cookie) String() string {
|
145 | 146 | fmt.Fprintf(&b, "; Path=%s", sanitizeCookiePath(c.Path))
|
146 | 147 | }
|
147 | 148 | if len(c.Domain) > 0 {
|
148 |
| - fmt.Fprintf(&b, "; Domain=%s", sanitizeCookieDomain(c.Domain)) |
| 149 | + if validCookieDomain(c.Domain) { |
| 150 | + // A c.Domain containing illegal characters is not |
| 151 | + // sanitized but simply dropped which turns the cookie |
| 152 | + // into a host-only cookie. |
| 153 | + fmt.Fprintf(&b, "; Domain=%s", c.Domain) |
| 154 | + } else { |
| 155 | + log.Printf("net/http: invalid Cookie.Domain %q; dropping domain attribute", |
| 156 | + c.Domain) |
| 157 | + } |
149 | 158 | }
|
150 | 159 | if c.Expires.Unix() > 0 {
|
151 | 160 | fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
|
@@ -208,26 +217,78 @@ func readCookies(h Header, filter string) []*Cookie {
|
208 | 217 | return cookies
|
209 | 218 | }
|
210 | 219 |
|
211 |
| -var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") |
| 220 | +// validCookieDomain returns wheter v is a valid cookie domain-value. |
| 221 | +func validCookieDomain(v string) bool { |
| 222 | + if isCookieDomainName(v) { |
| 223 | + return true |
| 224 | + } |
| 225 | + if net.ParseIP(v) != nil && !strings.Contains(v, ":") { |
| 226 | + return true |
| 227 | + } |
| 228 | + return false |
| 229 | +} |
212 | 230 |
|
213 |
| -// http://tools.ietf.org/html/rfc6265#section-4.1.1 |
214 |
| -// domain-av = "Domain=" domain-value |
215 |
| -// domain-value = <subdomain> |
216 |
| -// ; defined in [RFC1034], Section 3.5, as |
217 |
| -// ; enhanced by [RFC1123], Section 2.1 |
218 |
| -func sanitizeCookieDomain(v string) string { |
219 |
| - // TODO: implement http://tools.ietf.org/html/rfc1034#section-3.5 |
220 |
| - return oldCookieValueSanitizer.Replace(v) |
| 231 | +// isCookieDomainName returns whether s is a valid domain name or a valid |
| 232 | +// domain name with a leading dot '.'. It is almost a direct copy of |
| 233 | +// package net's isDomainName. |
| 234 | +func isCookieDomainName(s string) bool { |
| 235 | + if len(s) == 0 { |
| 236 | + return false |
| 237 | + } |
| 238 | + if len(s) > 255 { |
| 239 | + return false |
| 240 | + } |
| 241 | + |
| 242 | + if s[0] == '.' { |
| 243 | + // A cookie a domain attribute may start with a leading dot. |
| 244 | + s = s[1:] |
| 245 | + } |
| 246 | + last := byte('.') |
| 247 | + ok := false // Ok once we've seen a letter. |
| 248 | + partlen := 0 |
| 249 | + for i := 0; i < len(s); i++ { |
| 250 | + c := s[i] |
| 251 | + switch { |
| 252 | + default: |
| 253 | + return false |
| 254 | + case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': |
| 255 | + // No '_' allowed here (in contrast to package net). |
| 256 | + ok = true |
| 257 | + partlen++ |
| 258 | + case '0' <= c && c <= '9': |
| 259 | + // fine |
| 260 | + partlen++ |
| 261 | + case c == '-': |
| 262 | + // Byte before dash cannot be dot. |
| 263 | + if last == '.' { |
| 264 | + return false |
| 265 | + } |
| 266 | + partlen++ |
| 267 | + case c == '.': |
| 268 | + // Byte before dot cannot be dot, dash. |
| 269 | + if last == '.' || last == '-' { |
| 270 | + return false |
| 271 | + } |
| 272 | + if partlen > 63 || partlen == 0 { |
| 273 | + return false |
| 274 | + } |
| 275 | + partlen = 0 |
| 276 | + } |
| 277 | + last = c |
| 278 | + } |
| 279 | + if last == '-' || partlen > 63 { |
| 280 | + return false |
| 281 | + } |
| 282 | + |
| 283 | + return ok |
221 | 284 | }
|
222 | 285 |
|
| 286 | +var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-") |
| 287 | + |
223 | 288 | func sanitizeCookieName(n string) string {
|
224 | 289 | return cookieNameSanitizer.Replace(n)
|
225 | 290 | }
|
226 | 291 |
|
227 |
| -// This is the replacer used in the original Go cookie code. |
228 |
| -// It's not correct, but it's here for now until it's replaced. |
229 |
| -var oldCookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ") |
230 |
| - |
231 | 292 | // http://tools.ietf.org/html/rfc6265#section-4.1.1
|
232 | 293 | // cookie-value = *cookie-octet / ( DQUOTE *cookie-octet DQUOTE )
|
233 | 294 | // cookie-octet = %x21 / %x23-2B / %x2D-3A / %x3C-5B / %x5D-7E
|
|
0 commit comments