OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libgo/] [go/] [net/] [http/] [cookie.go] - Rev 848

Go to most recent revision | Compare with Previous | Blame | View Log

// 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 http

import (
        "bytes"
        "fmt"
        "strconv"
        "strings"
        "time"
)

// This implementation is done according to RFC 6265:
//
//    http://tools.ietf.org/html/rfc6265

// A Cookie represents an HTTP cookie as sent in the Set-Cookie header of an
// HTTP response or the Cookie header of an HTTP request.
type Cookie struct {
        Name       string
        Value      string
        Path       string
        Domain     string
        Expires    time.Time
        RawExpires string

        // MaxAge=0 means no 'Max-Age' attribute specified. 
        // MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'
        // MaxAge>0 means Max-Age attribute present and given in seconds
        MaxAge   int
        Secure   bool
        HttpOnly bool
        Raw      string
        Unparsed []string // Raw text of unparsed attribute-value pairs
}

// readSetCookies parses all "Set-Cookie" values from
// the header h and returns the successfully parsed Cookies.
func readSetCookies(h Header) []*Cookie {
        cookies := []*Cookie{}
        for _, line := range h["Set-Cookie"] {
                parts := strings.Split(strings.TrimSpace(line), ";")
                if len(parts) == 1 && parts[0] == "" {
                        continue
                }
                parts[0] = strings.TrimSpace(parts[0])
                j := strings.Index(parts[0], "=")
                if j < 0 {
                        continue
                }
                name, value := parts[0][:j], parts[0][j+1:]
                if !isCookieNameValid(name) {
                        continue
                }
                value, success := parseCookieValue(value)
                if !success {
                        continue
                }
                c := &Cookie{
                        Name:  name,
                        Value: value,
                        Raw:   line,
                }
                for i := 1; i < len(parts); i++ {
                        parts[i] = strings.TrimSpace(parts[i])
                        if len(parts[i]) == 0 {
                                continue
                        }

                        attr, val := parts[i], ""
                        if j := strings.Index(attr, "="); j >= 0 {
                                attr, val = attr[:j], attr[j+1:]
                        }
                        lowerAttr := strings.ToLower(attr)
                        parseCookieValueFn := parseCookieValue
                        if lowerAttr == "expires" {
                                parseCookieValueFn = parseCookieExpiresValue
                        }
                        val, success = parseCookieValueFn(val)
                        if !success {
                                c.Unparsed = append(c.Unparsed, parts[i])
                                continue
                        }
                        switch lowerAttr {
                        case "secure":
                                c.Secure = true
                                continue
                        case "httponly":
                                c.HttpOnly = true
                                continue
                        case "domain":
                                c.Domain = val
                                // TODO: Add domain parsing
                                continue
                        case "max-age":
                                secs, err := strconv.Atoi(val)
                                if err != nil || secs != 0 && val[0] == '0' {
                                        break
                                }
                                if secs <= 0 {
                                        c.MaxAge = -1
                                } else {
                                        c.MaxAge = secs
                                }
                                continue
                        case "expires":
                                c.RawExpires = val
                                exptime, err := time.Parse(time.RFC1123, val)
                                if err != nil {
                                        exptime, err = time.Parse("Mon, 02-Jan-2006 15:04:05 MST", val)
                                        if err != nil {
                                                c.Expires = time.Time{}
                                                break
                                        }
                                }
                                c.Expires = exptime.UTC()
                                continue
                        case "path":
                                c.Path = val
                                // TODO: Add path parsing
                                continue
                        }
                        c.Unparsed = append(c.Unparsed, parts[i])
                }
                cookies = append(cookies, c)
        }
        return cookies
}

// SetCookie adds a Set-Cookie header to the provided ResponseWriter's headers.
func SetCookie(w ResponseWriter, cookie *Cookie) {
        w.Header().Add("Set-Cookie", cookie.String())
}

// String returns the serialization of the cookie for use in a Cookie
// header (if only Name and Value are set) or a Set-Cookie response
// header (if other fields are set).
func (c *Cookie) String() string {
        var b bytes.Buffer
        fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
        if len(c.Path) > 0 {
                fmt.Fprintf(&b, "; Path=%s", sanitizeValue(c.Path))
        }
        if len(c.Domain) > 0 {
                fmt.Fprintf(&b, "; Domain=%s", sanitizeValue(c.Domain))
        }
        if c.Expires.Unix() > 0 {
                fmt.Fprintf(&b, "; Expires=%s", c.Expires.UTC().Format(time.RFC1123))
        }
        if c.MaxAge > 0 {
                fmt.Fprintf(&b, "; Max-Age=%d", c.MaxAge)
        } else if c.MaxAge < 0 {
                fmt.Fprintf(&b, "; Max-Age=0")
        }
        if c.HttpOnly {
                fmt.Fprintf(&b, "; HttpOnly")
        }
        if c.Secure {
                fmt.Fprintf(&b, "; Secure")
        }
        return b.String()
}

// readCookies parses all "Cookie" values from the header h and
// returns the successfully parsed Cookies.
//
// if filter isn't empty, only cookies of that name are returned
func readCookies(h Header, filter string) []*Cookie {
        cookies := []*Cookie{}
        lines, ok := h["Cookie"]
        if !ok {
                return cookies
        }

        for _, line := range lines {
                parts := strings.Split(strings.TrimSpace(line), ";")
                if len(parts) == 1 && parts[0] == "" {
                        continue
                }
                // Per-line attributes
                parsedPairs := 0
                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, success := parseCookieValue(val)
                        if !success {
                                continue
                        }
                        cookies = append(cookies, &Cookie{Name: name, Value: val})
                        parsedPairs++
                }
        }
        return cookies
}

var cookieNameSanitizer = strings.NewReplacer("\n", "-", "\r", "-")

func sanitizeName(n string) string {
        return cookieNameSanitizer.Replace(n)
}

var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ")

func sanitizeValue(v string) string {
        return cookieValueSanitizer.Replace(v)
}

func unquoteCookieValue(v string) string {
        if len(v) > 1 && v[0] == '"' && v[len(v)-1] == '"' {
                return v[1 : len(v)-1]
        }
        return v
}

func isCookieByte(c byte) bool {
        switch {
        case c == 0x21, 0x23 <= c && c <= 0x2b, 0x2d <= c && c <= 0x3a,
                0x3c <= c && c <= 0x5b, 0x5d <= c && c <= 0x7e:
                return true
        }
        return false
}

func isCookieExpiresByte(c byte) (ok bool) {
        return isCookieByte(c) || c == ',' || c == ' '
}

func parseCookieValue(raw string) (string, bool) {
        return parseCookieValueUsing(raw, isCookieByte)
}

func parseCookieExpiresValue(raw string) (string, bool) {
        return parseCookieValueUsing(raw, isCookieExpiresByte)
}

func parseCookieValueUsing(raw string, validByte func(byte) bool) (string, bool) {
        raw = unquoteCookieValue(raw)
        for i := 0; i < len(raw); i++ {
                if !validByte(raw[i]) {
                        return "", false
                }
        }
        return raw, true
}

func isCookieNameValid(raw string) bool {
        for _, c := range raw {
                if !isToken(byte(c)) {
                        return false
                }
        }
        return true
}

Go to most recent revision | Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.