uncurl

package module
v0.0.0-...-8cdd106 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 16, 2020 License: BSD-3-Clause Imports: 9 Imported by: 1

README

Uncurl Godoc

A Go library to consume a Chrome/Chromium browser "Copy as cURL" string and generate one or more Go *http.Request objects from it

Explanation

In the Chrome or Chromium browser, if you open "Developer tools" and go to the Network tab and navigate somewhere with the browser, you will see a list of requests. Right-clicking one these requests yields a menu with a Copy submenu. One of those options is "Copy as cURL". It allows you to paste a curl command to your terminal or editor, one that reproduces the request if run.

This library accepts that text input and turns it into a Go request. Further Go requests can be generated with different target URLs while maintaining the same header values.

Usage

Initial usage of this package typically follows these steps:

  1. Navigate in Chrome/Chromium with dev tools open to network tab, find a request you'd like to extract, right-click and select Copy => Copy as cURL
  2. In code, call un, err := uncurl.NewString(str) on the extracted string
  3. Generate new requests via uncurl methods, modify request objects, make requests, and extract new URLs from the responses to use in further requests

For a trivial example, let's request the weather in San Diego, and find all the text that looks like a temperature reading in the returned HTTP body.

Example 1: Weather in San Diego
package main

import (
	"bytes"
	"io/ioutil"
	"log"
	"net/http"
	"regexp"

	"github.com/jrefior/uncurl"
)

const tempPattern = `-?\d+(?:\.\d+)? ?°`

const weather = `
curl 'https://www.wunderground.com/weather/us/ca/san-diego' -H 'authority: www.wunderground.com' -H 'upgrade-insecure-requests: 1' -H 'user-agent: Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.130 Safari/537.36' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9' -H 'sec-fetch-site: none' -H 'sec-fetch-mode: navigate' -H 'accept-encoding: gzip, deflate, br' -H 'accept-language: en-US,en;q=0.9' -H 'cookie: usprivacy=foo; s_fid=bar; s_vi=zip' --compressed`

var tempRe *regexp.Regexp

func init() {
	tempRe = regexp.MustCompile(tempPattern)
}

func main() {
	un, err := uncurl.NewString(weather)
	if err != nil {
		log.Fatalf("Failed to initialize uncurl from weather string: %s", err)
	}
	r := un.Request()
	// modify request here if needed
	resp, err := http.DefaultClient.Do(r)
	if err != nil {
		log.Fatalf("Error making request: %s", err)
	}
	if resp.StatusCode != 200 {
		log.Fatalf("Unexpected status code %d", resp.StatusCode)
	}
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("Error reading response body: %s", err)
	}
	// often would save the body to a file here for later processing, but in this case let's just
	// search it now
	temps := tempRe.FindAll(b, -1)
	if temps == nil {
		log.Fatal("no temps found")
	}
	log.Printf("Temperatures found: %s\n", bytes.Join(temps, []byte(`, `)))
}

Output:

2020/02/12 07:56:15 Temperatures found: 65°, 48°, 47°, 1.5°, 1.5°, 1.5°, 1.5°, 1.5°, 5°, 41°, 6°, 27°, 81°, 20.9°, 36.4°, 4°, 10°, 5°, 20.9°, 36.4°, 67°, 55°, 67°, 55°, 110°, 80°, 75°, 0°, 30°, 20°, 35°, 58°, 50°, 360°, 360°, 360°, 360°, 360°, 70°, 60°, 36°, 22°, 74°, 70°, 70°, 69°, 3°
Header Value Lists

net/http servers do not split request header values into different elements by comma. This was suspected during review of standard library source code, and then shown via testing. E.g. a curl with this header:

-H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9'

hit a server handler with this code:

func handler(w http.ResponseWriter, r *http.Request) {    
    for k, v := range r.Header {    
        fmt.Printf("%28s %2d\n", k, len(v))    
    }    
}    

which showed the accept header length was 1. A header value slice length of 1 was found for all headers tested, e.g.:

             Accept-Encoding  1
   Upgrade-Insecure-Requests  1
                  User-Agent  1
              Sec-Fetch-Mode  1
             Accept-Language  1
                   Authority  1
                      Accept  1
              Sec-Fetch-Site  1

That behavior is reproduced here on the client side -- no effort is made to split curl -H arguments into different elements.

Documentation

Overview

package uncurl is Go library to consume a Chrome/Chromium browser "Copy as cURL" string and generate one or more Go *http.Request objects from it

In the Chrome or Chromium browser, if you open "Developer tools" and go to the Network tab and navigate somewhere with the browser, you will see a list of requests. Right-clicking one these requests yields a menu with a Copy submenu. One of those options is "Copy as cURL". It allows you to paste a `curl` command to your terminal or editor, one that reproduces the request if run.

This library accepts that text input and turns it into a Go request. Further Go requests can be generated with different target URLs while maintaining the same header values.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Uncurl

type Uncurl struct {

	// AcceptEncoding is the original `accept-encoding` header value. Including this header on our Go
	// request would signal to the `net/http` package that we do not wish to use DefaultTransport for
	// our request, disabling automatic gzip handling. As that's not usually desired, the value is
	// instead copied here for the user to employ as desired.
	AcceptEncoding string
	// contains filtered or unexported fields
}

Uncurl is the object from which requests are generated. Create one with New

func New

func New(b []byte) (*Uncurl, error)

New generates a new Uncurl object from a Chrome/Chromium "Copy as cURL" input as bytes. This is useful when you're loading from a file or concerned about efficiency. If you prefer to pass string input instead, use NewString.

func NewString

func NewString(s string) (*Uncurl, error)

NewString generates a new Uncurl object from a Chrome/Chromium "Copy as cURL" string

func (*Uncurl) Body

func (un *Uncurl) Body() []byte

Body returns a copy of the --data argument from the original curl string. The slice will be empty if --data was not present.

func (*Uncurl) Header

func (un *Uncurl) Header() http.Header

Header creates a new http.Header map and copies all headers from the original curl, with the exception of Accept-Encoding, to it

func (*Uncurl) Method

func (un *Uncurl) Method() string

Method returns the HTTP method string from the original curl string

func (*Uncurl) NewRequest

func (un *Uncurl) NewRequest(method, url string, body io.Reader) (*http.Request, error)

NewRequest is like Request(), but allows the caller to set the method, url, and body; matching the function signature of http.NewRequest

func (*Uncurl) NewRequestWithContext

func (un *Uncurl) NewRequestWithContext(ctx context.Context, method, url string, body io.Reader) (*http.Request, error)

NewRequestWithContext is like NewRequest but allows setting of context as well, matching the signature of http.NewRequestWithContext

func (*Uncurl) Request

func (un *Uncurl) Request() *http.Request

Request returns the Go `*http.Request` version of the curl

func (*Uncurl) String

func (un *Uncurl) String() string

String satisfies the `fmt.Stringer` interface by returning the original curl string

func (*Uncurl) Target

func (un *Uncurl) Target() string

Target returns the URL from the original curl string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL