Go HTTP Post and use Cookies

62,928

Solution 1

Go 1.1 introduced a cookie jar implementation net/http/cookiejar.

import (
    "net/http"
    "net/http/cookiejar"
)

jar, err := cookiejar.New(nil)
if err != nil { 
  // error handling 
}

client := &http.Client{
    Jar: jar,
}

Solution 2

First you'll need to implement the http.CookieJar interface. You can then pass this into the client you create and it will be used for requests made with the client. As a basic example:

package main

import (
    "fmt"
    "net/http"
    "net/url"
    "io/ioutil"
    "sync"
)

type Jar struct {
    lk      sync.Mutex
    cookies map[string][]*http.Cookie
}

func NewJar() *Jar {
    jar := new(Jar)
    jar.cookies = make(map[string][]*http.Cookie)
    return jar
}

// SetCookies handles the receipt of the cookies in a reply for the
// given URL.  It may or may not choose to save the cookies, depending
// on the jar's policy and implementation.
func (jar *Jar) SetCookies(u *url.URL, cookies []*http.Cookie) {
    jar.lk.Lock()
    jar.cookies[u.Host] = cookies
    jar.lk.Unlock()
}

// Cookies returns the cookies to send in a request for the given URL.
// It is up to the implementation to honor the standard cookie use
// restrictions such as in RFC 6265.
func (jar *Jar) Cookies(u *url.URL) []*http.Cookie {
    return jar.cookies[u.Host]
}

func main() {
    jar := NewJar()
    client := http.Client{nil, nil, jar}

    resp, _ := client.PostForm("http://www.somesite.com/login", url.Values{
        "email": {"myemail"},
        "password": {"mypass"},
    })
    resp.Body.Close()

    resp, _ = client.Get("http://www.somesite.com/protected")

    b, _ := ioutil.ReadAll(resp.Body)
    resp.Body.Close()

    fmt.Println(string(b))
}

Solution 3

At the version 1.5 of Go, we can use http.NewRequest to make a post request with cookie.

package main                                                                                              
import "fmt"
import "net/http"
import "io/ioutil"
import "strings"

func main() {
    // Declare http client
    client := &http.Client{}

    // Declare post data
    PostData := strings.NewReader("useId=5&age=12")

    // Declare HTTP Method and Url
    req, err := http.NewRequest("POST", "http://localhost/", PostData)

    // Set cookie
    req.Header.Set("Cookie", "name=xxxx; count=x")
    resp, err := client.Do(req)
    // Read response
    data, err := ioutil.ReadAll(resp.Body)

    // error handle
    if err != nil {
        fmt.Printf("error = %s \n", err);
    }   

    // Print response
    fmt.Printf("Response = %s", string(data));
}           

Solution 4

net/http/cookiejar is a good option, but I like to know what cookies are actually required when making my requests. You can get the response cookies like this:

package main
import "net/http"

func main() {
   res, err := http.Get("https://stackoverflow.com")
   if err != nil {
      panic(err)
   }
   for _, c := range res.Cookies() {
      println(c.Name, c.Value)
   }
}

and you can add cookies like this:

package main
import "net/http"

func main() {
   req, err := http.NewRequest("GET", "https://stackoverflow.com", nil)
   if err != nil {
      panic(err)
   }
   req.AddCookie(&http.Cookie{Name: "west", Value: "left"})
}
Share:
62,928
Lionel
Author by

Lionel

Updated on July 09, 2022

Comments

  • Lionel
    Lionel almost 2 years

    I'm trying to use Go to log into a website and store the cookies for later use.

    Could you give example code for posting a form, storing the cookies, and accessing another page using the cookies?

    I think I might need to make a Client to store the cookies, by studying http://gotour.golang.org/src/pkg/net/http/client.go

    package main
    
    import ("net/http"
            "log"
            "net/url"
            )
    
    func Login(user, password string) string {
            postUrl := "http://www.pge.com/eum/login"
    
            // Set up Login
            values := make(url.Values)
            values.Set("user", user)
            values.Set("password", password)
    
            // Submit form
            resp, err := http.PostForm(postUrl, values)
            if err != nil {
                    log.Fatal(err)
            }
            defer resp.Body.Close()
    
            // How do I store cookies?
            return "Hello"
    }
    
    func ViewBill(url string, cookies) string {
    
    //What do I put here?
    
    }
    
  • habanoz
    habanoz over 11 years
    You should probably use a map keyed on hostname for the cookie jar.
  • dskinner
    dskinner over 11 years
    for a generic solution, agreed. This would be similar to how a browser works, but in the end it depends on implementation details.
  • Stephen Weinberg
    Stephen Weinberg about 11 years
    "Implementations of CookieJar must be safe for concurrent use by multiple goroutines." This is not concurrency safe. Not to mention the fact this sends your cookies to other hosts. I am going to downvote.
  • dskinner
    dskinner about 11 years
    strong points for something that might get a copy and paste. I updated the example with a lock/unlock on SetCookies but honestly not quite sure about Cookies. A new slice and copies of the cookies would assure thread safety but I'm unaware of how the method might be used internally. Since I can't really answer that, I'll just as well down vote my own answer so copy and pasters beware!
  • matt
    matt almost 11 years
    You're going to get a panic: runtime error: assignment to entry in nil map unless you set jar.cookies = map[string][]*http.Cookie{} somewhere ;-)
  • Twisted1919
    Twisted1919 about 8 years
    For anyone using this approach and having issues with loosing cookies, have a look at stackoverflow.com/a/37043843/600061 for a fix
  • Ninh Pham
    Ninh Pham over 5 years
    He asked for http client, not server.
  • Florian Loch
    Florian Loch over 5 years
    Sorry to say, but this is a nightmare from a security perspective! Not considering Same Origin Policy at all and therefore vulnerable to leaking potentially sensible cookies (like session tokens) to hosts that should never receive them...
  • Salvatore Timpani
    Salvatore Timpani over 3 years
    I am getting undefined: cookieJar using this
  • chmike
    chmike over 2 years
    @SalvatoreTimpani you forgot the import. It works well with it.