How to send a GET request with login data and save cookie data to txt file?

Issue

I want to send a GET request with login data and save cookie data to txt file.

I had a curl data

   curl -c cookies.txt 'http://localhost:8080/api/v2/auth/login' \
  -H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98"' \
  -H 'sec-ch-ua-mobile: ?1' \
  -H 'User-Agent: Mozilla/5.0 (Linux; Android 9; BND-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.106 Mobile Safari/537.36' \
  -H 'Content-type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'Accept: text/javascript, text/html, application/xml, text/xml, */*' \
  -H 'Referer: http://localhost:8080/' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'sec-ch-ua-platform: "Android"' \
  --data-raw 'username=admin&password=pasxxord7' \
  --compressed

I need to convert this curl to Go; I have tried online converter, it’s giving error and I don’t think they have any capability to store cookies to txt file.

I had a sample Go file which doesn’t have a capability to send username and password, but I think it does saves cookies.txt file:

My main.go contents:

package main

import "net/http/cookiejar"
import "net/http"
import "encoding/json"
import "io/ioutil"
import "fmt"

func main(){
    cookies := make(map[string][]*http.Cookie)
    jar, _ := cookiejar.New(nil)
    client := http.Client{Jar: jar}
    r, err := client.Get("http://localhost:8080/api/v2/auth/login")
    if err != nil {
        fmt.Println(err)
        return
    }
    siteCookies := jar.Cookies(r.Request.URL)
    cookies[r.Request.URL.String()] = siteCookies
    data, _ := json.Marshal(cookies)
    ioutil.WriteFile("cookies.txt", data, 0644)
}

I need to mainly convert and add this curl flag and data --data-raw 'username=admin&password=pasxxord7' to Go.

Solution

When you use the curl flag --data-raw is sends a POST request. You can verify this by using the verbose output flag -v, for example:

$ curl -c cookies.txt 'http://requestbin.net/r/40vmgerp' \
  -H 'sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98"' \
  -H 'sec-ch-ua-mobile: ?1' \
  -H 'User-Agent: Mozilla/5.0 (Linux; Android 9; BND-AL10) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.106 Mobile Safari/537.36' \
  -H 'Content-type: application/x-www-form-urlencoded; charset=UTF-8' \
  -H 'Accept: text/javascript, text/html, application/xml, text/xml, */*' \
  -H 'Referer: http://localhost:8080/' \
  -H 'X-Requested-With: XMLHttpRequest' \
  -H 'sec-ch-ua-platform: "Android"' \
  --data-raw 'username=admin&password=pasxxord7' \
  --compressed -v

* Connected to requestbin.net (172.67.190.62) port 80 (#0)
> POST /r/40vmgerp HTTP/1.1 <--------------------
> Host: requestbin.net
> Accept-Encoding: deflate, gzip
> sec-ch-ua: " Not A;Brand";v="99", "Chromium";v="98"
> sec-ch-ua-mobile: ?1
...

Generally GET requests are not used for transmitting data in the body so using a POST as curl does automatically when data-raw is given is correct.

Based on your example headers and data for data-raw it appears you are using form values which can also be specified as:

curl localhost -F 'username=admin' -F 'password=pasxxord7'

This would add the content-type multipart/form-data header and send as POST automatically. This has the advantage of doing any necessary escaping as well.


To recreate your curl request in Go would be as follows:

package main

import (
    "encoding/json"
    "fmt"
    "net/http"
    "net/url"
    "os"
    "strings"
)

func main() {
    data := url.Values{}
    data.Set("username", "admin")
    data.Set("password", "pasxxord7")

    body := strings.NewReader(data.Encode())

    req, err := http.NewRequest(http.MethodPost, "https://requestbin.net/r/40vmgerp", body)
    if err != nil {
        panic(err)
    }

    // Omitted other headers for brevity.
    req.Header.Set("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8")
    req.Header.Set("Accept", "text/javascript, text/html, application/xml, text/xml, */*")

    resp, err := http.DefaultClient.Do(req)
    if err != nil {
        panic(err)
    }
    defer resp.Body.Close()

    cookies := resp.Cookies()

    if len(cookies) > 0 {
        cookieFile, err := os.Create("cookies.txt")
        if err != nil {
            panic(err)
        }
        defer cookieFile.Close()

        encoder := json.NewEncoder(cookieFile)

        for _, cookie := range cookies {
            // fmt.Fprintln(cookieFile, cookie.String()) // write plain text to file
            if err := encoder.Encode(cookie); err != nil {
                panic(err)
            }
        }
    } else {
        fmt.Println("No cookies found.")
    }
}

Note the example above uses RequestBin rather than localhost but should otherwise be complete if you add your other headers.

You don’t need to use a Cookie Jar because that is used to store and send cookies with an outgoing request. It appears you are only interested in storing the cookies sent back from the server and so you need to call the .Cookies() method on the response and use what is returned.

Answered By – D. Smith

Answer Checked By – Cary Denson (GoLangFix Admin)

Leave a Reply

Your email address will not be published.