Reading cookies

6,843 views
Skip to first unread message

Starfish

unread,
Feb 14, 2012, 7:46:00 PM2/14/12
to golan...@googlegroups.com
Hello! 

I'm trying to read a cookie without success. 

To set a cookie, I write:

expiration := *time.LocalTime()
expiration.Year += 1
cookie := http.Cookie{Name: "browserID", Value: "my value", Expires: expiration}
http.SetCookie(w, &cookie)       

To read, I write (without success):

cookie, _ := r.Cookie("browserID")
fmt.Fprint(*w, cookie) 

I'm very grateful for any help!

Kyle Lemons

unread,
Feb 14, 2012, 9:44:52 PM2/14/12
to Starfish, golan...@googlegroups.com
On Tue, Feb 14, 2012 at 4:46 PM, Starfish <ahn...@rocketmail.com> wrote:
Hello! 

I'm trying to read a cookie without success. 

To set a cookie, I write:

expiration := *time.LocalTime()
expiration.Year += 1
cookie := http.Cookie{Name: "browserID", Value: "my value", Expires: expiration}
http.SetCookie(w, &cookie)       

Are you sure the cookie is being set? (do you see it in your browser's cookie list)  Something in the back of my mind says you're missing something important (domain, maybe?)
 
To read, I write (without success):

cookie, _ := r.Cookie("browserID")
fmt.Fprint(*w, cookie)

Well, first off, don't ignore errors...  However, it's probably the failure of the cookie to get set. 
Message has been deleted

Volker Dobler

unread,
Feb 15, 2012, 3:08:54 AM2/15/12
to golang-nuts
Please post the whole code. Cookies (or at least what browsers
do with them) are tricky.

Volker

Starfish

unread,
Feb 15, 2012, 6:51:08 AM2/15/12
to golan...@googlegroups.com
Well, the cookie is set in both Chrome and Firefox. Here is one sample:

Name: browserID
Content: my value
Domain: localhost
Path: /
Send For: Any kind of connection
Accessible to Script: Yes
Created: Monday, February 13, 2012 12:29:52 AM
Expires: Wednesday, February 13, 2013 12:29:52 AM

I've tried to read the cookie in several ways. Here is one:

func debugRequest(w *http.ResponseWriter, r *http.Request) {
cookie, err := r.Cookie("browserID")
if err != nil {
fmt.Fprintf(*w, err.Error())
return
}
fmt.Fprintf(*w, cookie.Name)
}

This gives:

http: named cookied not present.

I use the most recent appengine btw. Beginning to suspect it's bugged.

Jessta

unread,
Feb 15, 2012, 7:04:18 AM2/15/12
to Starfish, golan...@googlegroups.com
On Wed, Feb 15, 2012 at 10:51 PM, Starfish <ahn...@rocketmail.com> wrote:
> func debugRequest(w *http.ResponseWriter, r *http.Request) {
> cookie, err := r.Cookie("browserID")
> if err != nil {
> fmt.Fprintf(*w, err.Error())
> return
> }
> fmt.Fprintf(*w, cookie.Name)
> }
>

How are you calling this code?
Why do you have a *http.ResponseWriter instead of just a http.ResponseWriter?

> This gives:
>
> http: named cookied not present.
> I use the most recent appengine btw. Beginning to suspect it's bugged.

--
=====================
http://jessta.id.au

Starfish

unread,
Feb 15, 2012, 7:40:47 AM2/15/12
to golan...@googlegroups.com, Starfish
It is called from the main handler:

func root(w http.ResponseWriter, r *http.Request) {
debugRequest(&w, r)
...

I'm not sure if this method is best practice. In C++ I would have used a reference.

chris dollin

unread,
Feb 15, 2012, 8:45:09 AM2/15/12
to Starfish, golan...@googlegroups.com
On 15 February 2012 12:40, Starfish <ahn...@rocketmail.com> wrote:
> It is called from the main handler:
>
> func root(w http.ResponseWriter, r *http.Request) {
> debugRequest(&w, r)
> ...
>
> I'm not sure if this method is best practice.

Definitely not.

Just pass it as a http.ResponseWriter.

(Usually you don't want pointers to interface values.)

Chris

--
Chris "allusive" Dollin

Starfish

unread,
Feb 15, 2012, 8:58:44 AM2/15/12
to golan...@googlegroups.com, Starfish
So, is an interface value passed by reference by default? I'm trying to avoid the object being copied; is that unnecessary?

chris dollin

unread,
Feb 15, 2012, 9:06:38 AM2/15/12
to Starfish, golan...@googlegroups.com
On 15 February 2012 13:58, Starfish <ahn...@rocketmail.com> wrote:
> So, is an interface value passed by reference by default?

Like all other values in Go, interface values are passed by value.
But like some other values in Go (eg slices, strings, maps, channels)
the internal structure of an interface value may point to other values.
If an interface variable contains a "big" value, then internally there
will be a pointer to a copy of that value. Copying interface values
is cheap.

> I'm trying to avoid the object being copied; is that unnecessary?

Yes. (In this case, anyway.)

Volker Dobler

unread,
Feb 15, 2012, 9:07:59 AM2/15/12
to golang-nuts
What is the content of Request.Header? Do you see the cookie
there?

Volker

Starfish

unread,
Feb 15, 2012, 9:20:15 AM2/15/12
to golan...@googlegroups.com
GET / HTTP/1.1
Host: localhost:8080
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:10.0) Gecko/20100101 Firefox/10.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Connection: keep-alive
Cookie: browserID=my value

Starfish

unread,
Feb 15, 2012, 9:24:49 AM2/15/12
to golan...@googlegroups.com
I have also tested:

for _, cookie := range r.Cookies() {
fmt.Fprint(w, cookie.Name)
fmt.Fprint(w, "hej")
}

But I get no cookies :(

Volker Dobler

unread,
Feb 15, 2012, 9:41:40 AM2/15/12
to golang-nuts
I assume this is what your browser sends. The question is now what
you receive (after parsing)

What would be the output of fmt.Fprintf(w, "%#v", r) if r
is the Request you recieved?

Starfish

unread,
Feb 15, 2012, 9:51:07 AM2/15/12
to golan...@googlegroups.com
To be more explicit, the loop:

header := r.Header
for field, array := range header {
fmt.Fprintf(w,"%s: %s\n", field, array)
}

Prints:

Accept: [text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8]
User-Agent: [Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.46 Safari/535.11]
Accept-Charset: [ISO-8859-1,utf-8;q=0.7,*;q=0.3]
X-Appengine-Inbound-Version-Id: [1.1]
X-Appengine-Inbound-User-Id: []
X-Appengine-Inbound-User-Email: []
Content-Length: [0]
Cookie: [browserID=my value]
X-Appengine-Inbound-Appid: [dev~template]
Connection: [close]
Content-Type: [application/x-www-form-urlencoded]
Accept-Language: [en-US,en;q=0.8,sv;q=0.6]

Starfish

unread,
Feb 15, 2012, 10:00:56 AM2/15/12
to golan...@googlegroups.com
&http.Request{Method:"GET", URL:(*url.URL)(0xf8400a91c0), Proto:"HTTP/1.0", ProtoMajor:1, ProtoMinor:0, Header:http.Header{"Accept":[]string{"text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"}, "User-Agent":[]string{"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.46 Safari/535.11"}, "Accept-Charset":[]string{"ISO-8859-1,utf-8;q=0.7,*;q=0.3"}, "X-Appengine-Inbound-Version-Id":[]string{"1.1"}, "X-Appengine-Inbound-User-Id":[]string{""}, "X-Appengine-Inbound-User-Email":[]string{""}, "Content-Length":[]string{"0"}, "Cookie":[]string{"browserID=my value"}, "X-Appengine-Inbound-Appid":[]string{"dev~template"}, "Connection":[]string{"close"}, "Content-Type":[]string{"application/x-www-form-urlencoded"}, "Accept-Language":[]string{"en-US,en;q=0.8,sv;q=0.6"}}, Body:(*http.body)(0xf84005ba80), ContentLength:0, TransferEncoding:[]string(nil), Close:false, Host:"localhost:8080", Form:url.Values(nil), MultipartForm:(*multipart.Form)(nil), Trailer:http.Header(nil), RemoteAddr:"127.0.0.1", RequestURI:"/", TLS:(*tls.ConnectionState)(nil)}

Volker Dobler

unread,
Feb 15, 2012, 10:25:19 AM2/15/12
to golang-nuts
So it seems as if you do get the cookie, it "just" gets lost
somewhere between parsing the header and r.Cookie(name).
Looks buggy but the workaround of taking the cookie from
r.Header["Cookie"] should not be too big. Maybe just
copy the current cookie code (not r60.3) to your app.

V.

Starfish

unread,
Feb 15, 2012, 10:41:08 AM2/15/12
to golan...@googlegroups.com
I'll do that.

Thanks for your trouble anyway.

Starfish

unread,
Feb 18, 2012, 11:40:59 AM2/18/12
to golan...@googlegroups.com
I filed a bug report for this issue. Apparently, the Cookie function can't retrieve cookies with spaces in the value field, for some reason.

Scott Dunlop

unread,
Feb 18, 2012, 7:51:29 PM2/18/12
to golan...@googlegroups.com
I went down this rabbit hole when I first started with Go, as well; the answer is rather simple.  When a method is defined in Go, it is bound either by value, such as:   

    func (r MunroeRng) Read(p []byte) (int, error) { ... }

Or against a pointer:

    // derived from src/pkg/bufio/bufio.go
    func (b *Reader) Read(p []byte) (int, error){ ... }

Both of these types satisfy io.Reader, but one is bound to the pointer, the other to the value.  Therefore:
    
    *munroe.Reader -- is an io.Reader; go will dereference to call Read.
    munroe.Reader -- is an io.Reader
    *bufio.Reader -- is an io.Reader; Read was bound to the pointer
    bufio.Reader -- is not an io.Reader (Read method requires pointer receiver)

Passing an interface by pointer will create an extra level of indirection that may be unnecessary.  This indirection adds one more thing to track for the GC, and one more pointer to dereference for access.

Scott Dunlop

unread,
Feb 18, 2012, 7:56:56 PM2/18/12
to golan...@googlegroups.com
Try: w.SetCookie(`"my value"`) -- it appears that http.SetCookie does not wrap the value in double quotes when invalid token characters are found.  (See http://www.ietf.org/rfc/rfc2109.txt sec 4.1) 

    //src/pkg/net/http.go
    func (c *Cookie) String() string {
        ...
        fmt.Fprintf(&b, "%s=%s", sanitizeName(c.Name), sanitizeValue(c.Value))
        ...
    }
    ...
    var cookieValueSanitizer = strings.NewReplacer("\n", " ", "\r", " ", ";", " ")
    ...
    func sanitizeValue(v string) string {
        return cookieValueSanitizer.Replace(v)
    }


Message has been deleted

Starfish

unread,
Feb 19, 2012, 5:24:08 AM2/19/12
to golan...@googlegroups.com
That was very enlightening. It is very subtle, and should be emphasized in docs and manuals.
Reply all
Reply to author
Forward
0 new messages