Skip to content

Commit

Permalink
Use opts lib to config stack
Browse files Browse the repository at this point in the history
  • Loading branch information
fogfish committed Nov 10, 2024
1 parent 396e483 commit 6ebc664
Show file tree
Hide file tree
Showing 12 changed files with 159 additions and 121 deletions.
2 changes: 1 addition & 1 deletion examples/http-request/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func request() http.Arrow {

func main() {
// instance of http stack
stack := http.New(http.WithDebugPayload())
stack := http.New(http.WithDebugPayload)

// declares http i/o
lazy := request()
Expand Down
2 changes: 1 addition & 1 deletion examples/http-response-chain/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func request() (*Heap, http.Arrow) {

func main() {
// instance of http stack
stack := http.New(http.WithDebugPayload())
stack := http.New(http.WithDebugPayload)

data, lazy := request()

Expand Down
2 changes: 1 addition & 1 deletion examples/http-response-image/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ func (api api) request(ctx context.Context) (*image.Image, error) {

func main() {
api := api{
Stack: http.New(http.WithDebugPayload()),
Stack: http.New(http.WithDebugPayload),
}

img, err := api.request(context.Background())
Expand Down
2 changes: 1 addition & 1 deletion examples/http-response/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ func request() (*HTTPBin, http.Arrow) {

func main() {
// instance of http stack
stack := http.New(http.WithDebugPayload())
stack := http.New(http.WithDebugPayload)

data, lazy := request()

Expand Down
12 changes: 10 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
module github.com/fogfish/gurl/v2

go 1.21
go 1.23

toolchain go1.23.1

require (
github.com/ajg/form v1.5.2-0.20200323032839-9aeb3cf462e1
github.com/fogfish/it/v2 v2.0.1
github.com/fogfish/it/v2 v2.0.2
golang.org/x/net v0.17.0
)

require github.com/google/go-cmp v0.6.0

require (
github.com/fogfish/golem/hseq v1.2.0 // indirect
github.com/fogfish/golem/optics v0.13.1 // indirect
github.com/fogfish/opts v0.0.2 // indirect
)
7 changes: 7 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
github.com/ajg/form v1.5.2-0.20200323032839-9aeb3cf462e1 h1:8Qzi+0Uch1VJvdrOhJ8U8FqoPLbUdETPgMqGJ6DSMSQ=
github.com/ajg/form v1.5.2-0.20200323032839-9aeb3cf462e1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
github.com/fogfish/golem/hseq v1.2.0 h1:B6yrzOHQNoTqSlhLb+AvK7dhEAELjHThrCQTF/uqwbM=
github.com/fogfish/golem/hseq v1.2.0/go.mod h1:17XORt8nNKl6KOhF43MHSmjK8NksbkBsohAoJGiinUs=
github.com/fogfish/golem/optics v0.13.1 h1:gkvJ5f7/AXaL8EuHLu5dgE/BwUSg/WX50D7b8f4G+6s=
github.com/fogfish/golem/optics v0.13.1/go.mod h1:U1y90OVcXF/A61dIP3abQ0x2GweTmzVHPC15pv0pcM0=
github.com/fogfish/it/v2 v2.0.1 h1:vu3kV2xzYDPHoMHMABxXeu5CoMcTfRc4gkWkzOUkRJY=
github.com/fogfish/it/v2 v2.0.1/go.mod h1:h5FdKaEQT4sUEykiVkB8VV4jX27XabFVeWhoDZaRZtE=
github.com/fogfish/it/v2 v2.0.2/go.mod h1:HHwufnTaZTvlRVnSesPl49HzzlMrQtweKbf+8Co/ll4=
github.com/fogfish/opts v0.0.2 h1:Iro+QQHR/l6G5afX6N5TtqZtV+iVeUxJUOpW63gqhwk=
github.com/fogfish/opts v0.0.2/go.mod h1:fAM7yksrn+u5opbyAh2HiObd5Zx54WnSMGZIU21AGFw=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
Expand Down
2 changes: 1 addition & 1 deletion http/mock/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ func IOError(err error) Option {
}

// Mock HTTP Client
func New(opts ...Option) µ.Config {
func New(opts ...Option) µ.Option {
m := &Mock{
r: &http.Response{
StatusCode: http.StatusOK,
Expand Down
4 changes: 2 additions & 2 deletions http/once_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func TestWriteOnceSuccess(t *testing.T) {
}

buf := bytes.Buffer{}
hts := http.New(http.WithMemento(), http.WithDefaultHost(ts.URL))
hts := http.New(http.WithMementoPayload, http.WithHost(ts.URL))
err := http.WriteOnce(&buf, hts, unittest)
it.Then(t).Should(it.Nil(err))

Expand Down Expand Up @@ -59,7 +59,7 @@ func TestWriteOnceNoMatch(t *testing.T) {
}

buf := bytes.Buffer{}
hts := http.New(http.WithMemento(), http.WithDefaultHost(ts.URL))
hts := http.New(http.WithMementoPayload, http.WithHost(ts.URL))
err := http.WriteOnce(&buf, hts, unittest)
it.Then(t).Should(it.Nil(err))

Expand Down
111 changes: 111 additions & 0 deletions http/options.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
//
// Copyright (C) 2019 - 2024 Dmitry Kolesnikov
//
// This file may be modified and distributed under the terms
// of the MIT license. See the LICENSE file for details.
// https://github.com/fogfish/gurl
//

package http

import (
"crypto/tls"
"fmt"
"net/http"
"net/http/cookiejar"

"github.com/fogfish/opts"
"golang.org/x/net/publicsuffix"
)

// HTTP Stack config option
type Option = opts.Option[Protocol]

var (
// Set custom implementation of HTTP client.
// It requires anything that implements Socket interface (aka http.Client)
//
// type Socket interface {
// Do(req *http.Request) (*http.Response, error)
// }
WithClient = opts.ForType[Protocol, Socket]()

// Set the default host for http stack.
// The host is used when request URI does not contain any host.
WithHost = opts.ForName[Protocol, string]("Host")

// Enables HTTP Response buffering
WithMemento = opts.ForName[Protocol, bool]("Memento")

// Buffers HTTP Response Payload into context.
WithMementoPayload = WithMemento(true)

// Disables TLS certificate validation for HTTP(S) sessions.
WithInsecureTLS = opts.From(withInsecureTLS)

// Enables automated cookie handling across requests originated from the session.
WithCookieJar = opts.From(withCookieJar)

// Disables default [gurl] redirect policy to Golang's one.
// It enables the HTTP stack automatically follows redirects
WithRedirects = opts.From(withRedirects)

// Enable log level
WithLogLevel = opts.ForName[Protocol, int]("LogLevel")

// Enables debug logging.
// The logger outputs HTTP requests only.
WithDebugRequest = WithLogLevel(1)

// Enables debug logging.
// The logger outputs HTTP requests and responses.
WithDebugResponse = WithLogLevel(2)

// Enable debug logging.
WithDebugPayload = WithLogLevel(3)
)

func withInsecureTLS(cat *Protocol) error {
cli, ok := cat.Socket.(*http.Client)
if !ok {
return fmt.Errorf("unsupported transport type %T", cat)
}

switch t := cli.Transport.(type) {
case *http.Transport:
if t.TLSClientConfig == nil {
t.TLSClientConfig = &tls.Config{}
}
t.TLSClientConfig.InsecureSkipVerify = true
return nil
default:
return fmt.Errorf("unsupported transport type %T", t)
}
}

func withCookieJar(cat *Protocol) error {
cli, ok := cat.Socket.(*http.Client)
if !ok {
return fmt.Errorf("unsupported transport type %T", cat)
}

jar, err := cookiejar.New(&cookiejar.Options{
PublicSuffixList: publicsuffix.List,
})
if err != nil {
return err
}
cli.Jar = jar

return nil
}

func withRedirects(cat *Protocol) error {
cli, ok := cat.Socket.(*http.Client)
if !ok {
return fmt.Errorf("unsupported transport type %T", cat)
}

cli.CheckRedirect = nil
return nil
}
120 changes: 16 additions & 104 deletions http/stack.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,11 @@ package http

import (
"context"
"crypto/tls"
"fmt"
"net"
"net/http"
"net/http/cookiejar"
"time"

"golang.org/x/net/publicsuffix"
"github.com/fogfish/opts"
)

//
Expand Down Expand Up @@ -47,15 +44,25 @@ type Protocol struct {
Memento bool
}

// Allocate instance of HTTP Stack
func New(opts ...Config) Stack {
// New instance of HTTP Stack
func New(opt ...Option) Stack {
cat, err := NewStack(opt...)
if err != nil {
panic(err)
}

return cat
}

// New instance of HTTP Stack
func NewStack(opt ...Option) (Stack, error) {
cat := &Protocol{Socket: Client()}

for _, opt := range opts {
opt(cat)
if err := opts.Apply(cat, opt); err != nil {
return nil, err
}

return cat
return cat, nil
}

// WithContext create instance of I/O Context
Expand Down Expand Up @@ -86,50 +93,6 @@ func (stack *Protocol) IO(ctx context.Context, arrows ...Arrow) error {
return nil
}

// Config option for HTTP client
type Config func(*Protocol)

// WithClient replaces default client with custom instance
func WithClient(client Socket) Config {
return func(cat *Protocol) {
cat.Socket = client
}
}

// Enables debug logging for requests
func WithDebugRequest() Config {
return func(cat *Protocol) {
cat.LogLevel = 1
}
}

// Enables debug logging for requests & response
func WithDebugResponse() Config {
return func(cat *Protocol) {
cat.LogLevel = 2
}
}

// Enables debug logging for requests, responses and payload
func WithDebugPayload() Config {
return func(cat *Protocol) {
cat.LogLevel = 3
}
}

// WithMemorize the response payload
func WithMemento() Config {
return func(cat *Protocol) {
cat.Memento = true
}
}

func WithDefaultHost(host string) Config {
return func(cat *Protocol) {
cat.Host = host
}
}

// Creates default HTTP client
func Client() *http.Client {
return &http.Client{
Expand All @@ -148,54 +111,3 @@ func Client() *http.Client {
},
}
}

// WithInsecureTLS disables certificates validation
func WithInsecureTLS() Config {
return func(cat *Protocol) {
cli, ok := cat.Socket.(*http.Client)
if !ok {
panic(fmt.Errorf("unsupported transport type %T", cat))
}

switch t := cli.Transport.(type) {
case *http.Transport:
if t.TLSClientConfig == nil {
t.TLSClientConfig = &tls.Config{}
}
t.TLSClientConfig.InsecureSkipVerify = true
default:
panic(fmt.Errorf("unsupported transport type %T", t))
}
}
}

// WithCookieJar enables cookie handlings
func WithCookieJar() Config {
return func(cat *Protocol) {
cli, ok := cat.Socket.(*http.Client)
if !ok {
panic(fmt.Errorf("unsupported transport type %T", cat))
}

jar, err := cookiejar.New(&cookiejar.Options{
PublicSuffixList: publicsuffix.List,
})
if err != nil {
panic(err)
}
cli.Jar = jar
}
}

// WithDefaultRedirectPolicy resets default gurl no-redirect policy to Golang's one.
// It enables the HTTP stack follows redirects
func WithDefaultRedirectPolicy() Config {
return func(cat *Protocol) {
cli, ok := cat.Socket.(*http.Client)
if !ok {
panic(fmt.Errorf("unsupported transport type %T", cat))
}

cli.CheckRedirect = nil
}
}
Loading

0 comments on commit 6ebc664

Please sign in to comment.