// Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. package curl2info import ( "net" "net/http" "strings" ) var isTokenTable = [127]bool{ '!': true, '#': true, '$': true, '%': true, '&': true, '\'': true, '*': true, '+': true, '-': true, '.': true, '0': true, '1': true, '2': true, '3': true, '4': true, '5': true, '6': true, '7': true, '8': true, '9': true, 'A': true, 'B': true, 'C': true, 'D': true, 'E': true, 'F': true, 'G': true, 'H': true, 'I': true, 'J': true, 'K': true, 'L': true, 'M': true, 'N': true, 'O': true, 'P': true, 'Q': true, 'R': true, 'S': true, 'T': true, 'U': true, 'W': true, 'V': true, 'X': true, 'Y': true, 'Z': true, '^': true, '_': true, '`': true, 'a': true, 'b': true, 'c': true, 'd': true, 'e': true, 'f': true, 'g': true, 'h': true, 'i': true, 'j': true, 'k': true, 'l': true, 'm': true, 'n': true, 'o': true, 'p': true, 'q': true, 'r': true, 's': true, 't': true, 'u': true, 'v': true, 'w': true, 'x': true, 'y': true, 'z': true, '|': true, '~': true, } func isTokenRune(r rune) bool { i := int(r) return i < len(isTokenTable) && isTokenTable[i] } // ReadRawCookies parses all "Cookie" values from the rawcookie and // returns the successfully parsed Cookies. // // if filter isn't empty, only cookies of that name are returned func ReadRawCookies(soptions string, filter string) []*http.Cookie { line := soptions cookies := []*http.Cookie{} parts := strings.Split(strings.TrimSpace(line), ";") if len(parts) == 1 && parts[0] == "" { return cookies } // Per-line attributes for i := 0; i < len(parts); i++ { parts[i] = strings.TrimSpace(parts[i]) if len(parts[i]) == 0 { continue } name, val := parts[i], "" if j := strings.Index(name, "="); j >= 0 { name, val = name[:j], name[j+1:] } if !isCookieNameValid(name) { continue } if filter != "" && filter != name { continue } val, ok := parseCookieValue(val, true) if !ok { continue } cookies = append(cookies, &http.Cookie{Name: name, Value: val}) } return cookies } // validCookieDomain returns whether v is a valid cookie domain-value. func validCookieDomain(v string) bool { if isCookieDomainName(v) { return true } if net.ParseIP(v) != nil && !strings.Contains(v, ":") { return true } return false } // isCookieDomainName returns whether s is a valid domain name or a valid // domain name with a leading dot '.'. It is almost a direct copy of // package net's isDomainName. func isCookieDomainName(s string) bool { if len(s) == 0 { return false } if len(s) > 255 { return false } if s[0] == '.' { // A cookie a domain attribute may start with a leading dot. s = s[1:] } last := byte('.') ok := false // Ok once we've seen a letter. partlen := 0 for i := 0; i < len(s); i++ { c := s[i] switch { default: return false case 'a' <= c && c <= 'z' || 'A' <= c && c <= 'Z': // No '_' allowed here (in contrast to package net). ok = true partlen++ case '0' <= c && c <= '9': // fine partlen++ case c == '-': // Byte before dash cannot be dot. if last == '.' { return false } partlen++ case c == '.': // Byte before dot cannot be dot, dash. if last == '.' || last == '-' { return false } if partlen > 63 || partlen == 0 { return false } partlen = 0 } last = c } if last == '-' || partlen > 63 { return false } return ok } func validCookieValueByte(b byte) bool { return 0x20 <= b && b < 0x7f && b != '"' && b != ';' && b != '\\' } func parseCookieValue(raw string, allowDoubleQuote bool) (string, bool) { // Strip the quotes, if present. if allowDoubleQuote && len(raw) > 1 && raw[0] == '"' && raw[len(raw)-1] == '"' { raw = raw[1 : len(raw)-1] } for i := 0; i < len(raw); i++ { if !validCookieValueByte(raw[i]) { return "", false } } return raw, true } func isCookieNameValid(raw string) bool { if raw == "" { return false } return strings.IndexFunc(raw, isNotToken) < 0 } func isNotToken(r rune) bool { return !isTokenRune(r) }