skipper: github.com/zalando/skipper/net Index | Examples | Files

package net

import "github.com/zalando/skipper/net"

Package net provides generic network related functions used across Skipper, which might be useful also in other contexts than Skipper.

Index

Examples

Package Files

doc.go httpclient.go net.go

func RemoteHost Uses

func RemoteHost(r *http.Request) net.IP

RemoteHost returns the remote address of the client. When the 'X-Forwarded-For' header is set, then it is used instead. This is how most often proxies behave. Wikipedia shows the format https://en.wikipedia.org/wiki/X-Forwarded-For#Format

Example:

X-Forwarded-For: client, proxy1, proxy2

func RemoteHostFromLast Uses

func RemoteHostFromLast(r *http.Request) net.IP

RemoteHostFromLast returns the remote address of the client. When the 'X-Forwarded-For' header is set, then it is used instead. This is known to be true for AWS Application LoadBalancer. AWS docs https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/x-forwarded-headers.html

Example:

X-Forwarded-For: ip-address-1, ip-address-2, client-ip-address

type Client Uses

type Client struct {
    // contains filtered or unexported fields
}

Client adds additional features like Bearer token injection, and opentracing to the wrapped http.Client with the same interface as http.Client from the stdlib.

Code:

tracer := lightstep.NewTracer(lightstep.Options{})

cli := net.NewClient(net.Options{
    Tracer:                     tracer,
    OpentracingComponentTag:    "testclient",
    OpentracingSpanName:        "clientSpan",
    BearerTokenRefreshInterval: 10 * time.Second,
    BearerTokenFile:            "/tmp/foo.token",
    IdleConnTimeout:            2 * time.Second,
})
defer cli.Close()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("Authorization: %s", r.Header.Get("Authorization"))
    log.Printf("Ot-Tracer-Sampled: %s", r.Header.Get("Ot-Tracer-Sampled"))
    log.Printf("Ot-Tracer-Traceid: %s", r.Header.Get("Ot-Tracer-Traceid"))
    log.Printf("Ot-Tracer-Spanid: %s", r.Header.Get("Ot-Tracer-Spanid"))
    w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

u := "http://" + srv.Listener.Addr().String() + "/"

for i := 0; i < 15; i++ {
    rsp, err := cli.Get(u)
    if err != nil {
        log.Fatalf("Failed to do request: %v", err)
    }
    log.Printf("rsp code: %v", rsp.StatusCode)
    time.Sleep(1 * time.Second)
}

Code:

tracer := lightstep.NewTracer(lightstep.Options{})

sp := secrets.NewSecretPaths(10 * time.Second)
if err := sp.Add("/tmp/bar.token"); err != nil {
    log.Fatalf("failed to read secret: %v", err)
}

cli := net.NewClient(net.Options{
    Tracer:                  tracer,
    OpentracingComponentTag: "testclient",
    OpentracingSpanName:     "clientSpan",
    SecretsReader:           sp,
    IdleConnTimeout:         2 * time.Second,
})
defer cli.Close()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("Authorization: %s", r.Header.Get("Authorization"))
    log.Printf("Ot-Tracer-Sampled: %s", r.Header.Get("Ot-Tracer-Sampled"))
    log.Printf("Ot-Tracer-Traceid: %s", r.Header.Get("Ot-Tracer-Traceid"))
    log.Printf("Ot-Tracer-Spanid: %s", r.Header.Get("Ot-Tracer-Spanid"))
    w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

u := "http://" + srv.Listener.Addr().String() + "/"

for i := 0; i < 15; i++ {
    rsp, err := cli.Get(u)
    if err != nil {
        log.Fatalf("Failed to do request: %v", err)
    }
    log.Printf("rsp code: %v", rsp.StatusCode)
    time.Sleep(1 * time.Second)
}

Code:

tracer := lightstep.NewTracer(lightstep.Options{})
sec := []byte("mysecret")

cli := net.NewClient(net.Options{
    Tracer:                  tracer,
    OpentracingComponentTag: "testclient",
    OpentracingSpanName:     "clientSpan",
    SecretsReader: secrets.NewHostSecret(
        newTestSecretsReader(
            map[string][]byte{
                "key": sec,
            },
        ),
        map[string]string{
            "127.0.0.1": "key",
        },
    ),
    IdleConnTimeout: 2 * time.Second,
})
defer cli.Close()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("Authorization: %s", r.Header.Get("Authorization"))
    log.Printf("Ot-Tracer-Sampled: %s", r.Header.Get("Ot-Tracer-Sampled"))
    log.Printf("Ot-Tracer-Traceid: %s", r.Header.Get("Ot-Tracer-Traceid"))
    log.Printf("Ot-Tracer-Spanid: %s", r.Header.Get("Ot-Tracer-Spanid"))
    w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

u := "http://" + srv.Listener.Addr().String() + "/"

for i := 0; i < 15; i++ {
    rsp, err := cli.Get(u)
    if err != nil {
        log.Fatalf("Failed to do request: %v", err)
    }
    log.Printf("rsp code: %v", rsp.StatusCode)
    time.Sleep(1 * time.Second)
}

Code:

tracer := lightstep.NewTracer(lightstep.Options{})
sec := []byte("mysecret")

cli := net.NewClient(net.Options{
    Tracer:                  tracer,
    OpentracingComponentTag: "testclient",
    OpentracingSpanName:     "clientSpan",
    SecretsReader: secrets.NewStaticDelegateSecret(
        newTestSecretsReader(
            map[string][]byte{
                "key": sec,
            },
        ),
        "key",
    ),
    IdleConnTimeout: 2 * time.Second,
})
defer cli.Close()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("Authorization: %s", r.Header.Get("Authorization"))
    log.Printf("Ot-Tracer-Sampled: %s", r.Header.Get("Ot-Tracer-Sampled"))
    log.Printf("Ot-Tracer-Traceid: %s", r.Header.Get("Ot-Tracer-Traceid"))
    log.Printf("Ot-Tracer-Spanid: %s", r.Header.Get("Ot-Tracer-Spanid"))
    w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

u := "http://" + srv.Listener.Addr().String() + "/"

for i := 0; i < 15; i++ {
    rsp, err := cli.Get(u)
    if err != nil {
        log.Fatalf("Failed to do request: %v", err)
    }
    log.Printf("rsp code: %v", rsp.StatusCode)
    time.Sleep(1 * time.Second)
}

Code:

tracer := lightstep.NewTracer(lightstep.Options{})
sec := []byte("mysecret")
cli := net.NewClient(net.Options{
    Tracer:                  tracer,
    OpentracingComponentTag: "testclient",
    OpentracingSpanName:     "clientSpan",
    SecretsReader:           secrets.StaticSecret(sec),
    IdleConnTimeout:         2 * time.Second,
})
defer cli.Close()

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("Authorization: %s", r.Header.Get("Authorization"))
    log.Printf("Ot-Tracer-Sampled: %s", r.Header.Get("Ot-Tracer-Sampled"))
    log.Printf("Ot-Tracer-Traceid: %s", r.Header.Get("Ot-Tracer-Traceid"))
    log.Printf("Ot-Tracer-Spanid: %s", r.Header.Get("Ot-Tracer-Spanid"))
    w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

u := "http://" + srv.Listener.Addr().String() + "/"

for i := 0; i < 15; i++ {
    rsp, err := cli.Get(u)
    if err != nil {
        log.Fatalf("Failed to do request: %v", err)
    }
    log.Printf("rsp code: %v", rsp.StatusCode)
    time.Sleep(1 * time.Second)
}

func NewClient Uses

func NewClient(o Options) *Client

NewClient creates a wrapped http.Client and uses Transport to support OpenTracing. On teardown you have to use Close() to not leak a goroutine.

If secrets.SecretsReader is nil, but BearerTokenFile is not empty string, it creates StaticDelegateSecret with a wrapped secrets.SecretPaths, which can be used with Kubernetes secrets to read from the secret an automatically updated Bearer token.

func (*Client) Close Uses

func (c *Client) Close()

func (*Client) CloseIdleConnections Uses

func (c *Client) CloseIdleConnections()

CloseIdleConnections delegates the call to the underlying http.Client.

func (*Client) Do Uses

func (c *Client) Do(req *http.Request) (*http.Response, error)

Do delegates the given http.Request to the underlying http.Client and adds a Bearer token to the authorization header, if Client has a secrets.SecretsReader and the request does not contain an Authorization header.

func (*Client) Get Uses

func (c *Client) Get(url string) (*http.Response, error)

func (*Client) Head Uses

func (c *Client) Head(url string) (*http.Response, error)

func (*Client) Post Uses

func (c *Client) Post(url, contentType string, body io.Reader) (*http.Response, error)

func (*Client) PostForm Uses

func (c *Client) PostForm(url string, data url.Values) (*http.Response, error)

type Options Uses

type Options struct {
    // DisableKeepAlives see https://golang.org/pkg/net/http/#Transport.DisableKeepAlives
    DisableKeepAlives bool
    // DisableCompression see https://golang.org/pkg/net/http/#Transport.DisableCompression
    DisableCompression bool
    // ForceAttemptHTTP2 see https://golang.org/pkg/net/http/#Transport.ForceAttemptHTTP2
    ForceAttemptHTTP2 bool
    // MaxIdleConns see https://golang.org/pkg/net/http/#Transport.MaxIdleConns
    MaxIdleConns int
    // MaxIdleConnsPerHost see https://golang.org/pkg/net/http/#Transport.MaxIdleConnsPerHost
    MaxIdleConnsPerHost int
    // MaxConnsPerHost see https://golang.org/pkg/net/http/#Transport.MaxConnsPerHost
    MaxConnsPerHost int
    // WriteBufferSize see https://golang.org/pkg/net/http/#Transport.WriteBufferSize
    WriteBufferSize int
    // ReadBufferSize see https://golang.org/pkg/net/http/#Transport.ReadBufferSize
    ReadBufferSize int
    // MaxResponseHeaderBytes see
    // https://golang.org/pkg/net/http/#Transport.MaxResponseHeaderBytes
    MaxResponseHeaderBytes int64
    // Timeout sets all Timeouts, that are set to 0 to the given
    // value. Basically it's the default timeout value.
    Timeout time.Duration
    // TLSHandshakeTimeout see
    // https://golang.org/pkg/net/http/#Transport.TLSHandshakeTimeout,
    // if not set or set to 0, its using Options.Timeout.
    TLSHandshakeTimeout time.Duration
    // IdleConnTimeout see
    // https://golang.org/pkg/net/http/#Transport.IdleConnTimeout,
    // if not set or set to 0, its using Options.Timeout.
    IdleConnTimeout time.Duration
    // ResponseHeaderTimeout see
    // https://golang.org/pkg/net/http/#Transport.ResponseHeaderTimeout,
    // if not set or set to 0, its using Options.Timeout.
    ResponseHeaderTimeout time.Duration
    // ExpectContinueTimeout see
    // https://golang.org/pkg/net/http/#Transport.ExpectContinueTimeout,
    // if not set or set to 0, its using Options.Timeout.
    ExpectContinueTimeout time.Duration
    // Tracer instance, can be nil to not enable tracing
    Tracer opentracing.Tracer

    // BearerTokenFile injects bearer token read from file, which
    // file path is the given string. In case SecretsReader is
    // provided, BearerTokenFile will be ignored.
    BearerTokenFile string
    // BearerTokenRefreshInterval refresh bearer from
    // BearerTokenFile. In case SecretsReader is provided,
    // BearerTokenFile will be ignored.
    BearerTokenRefreshInterval time.Duration
    // SecretsReader is used to read and refresh bearer tokens
    SecretsReader secrets.SecretsReader

    // Log is used for error logging
    Log logging.Logger

    // OpentracingComponentTag sets component tag for all requests
    OpentracingComponentTag string
    // OpentracingSpanName sets span name for all requests
    OpentracingSpanName string
}

Options are mostly passed to the http.Transport of the same name. Options.Timeout can be used as default for all timeouts, that are not set. You can pass an opentracing.Tracer https://godoc.org/github.com/opentracing/opentracing-go#Tracer, which can be nil to get the https://godoc.org/github.com/opentracing/opentracing-go#NoopTracer.

type Transport Uses

type Transport struct {
    // contains filtered or unexported fields
}

Transport wraps an http.Transport and adds support for tracing and bearerToken injection.

Code:

tracer := lightstep.NewTracer(lightstep.Options{})

cli := net.NewTransport(net.Options{
    Tracer: tracer,
})
defer cli.Close()
cli = net.WithSpanName(cli, "myspan")
cli = net.WithBearerToken(cli, "mytoken")

srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    log.Printf("Authorization: %s", r.Header.Get("Authorization"))
    log.Printf("Ot-Tracer-Sampled: %s", r.Header.Get("Ot-Tracer-Sampled"))
    log.Printf("Ot-Tracer-Traceid: %s", r.Header.Get("Ot-Tracer-Traceid"))
    log.Printf("Ot-Tracer-Spanid: %s", r.Header.Get("Ot-Tracer-Spanid"))
    w.WriteHeader(http.StatusOK)
}))
defer srv.Close()

u := "http://" + srv.Listener.Addr().String() + "/"
req, err := http.NewRequest("GET", u, nil)
if err != nil {
    log.Fatalf("Failed to create request: %v", err)
}

rsp, err := cli.RoundTrip(req)
if err != nil {
    log.Fatalf("Failed to do request: %v", err)
}
log.Printf("rsp code: %v", rsp.StatusCode)

func NewTransport Uses

func NewTransport(options Options) *Transport

NewTransport creates a wrapped http.Transport, with regular DNS lookups using CloseIdleConnections on every IdleConnTimeout. You can optionally add tracing. On teardown you have to use Close() to not leak a goroutine.

func WithBearerToken Uses

func WithBearerToken(t *Transport, bearerToken string) *Transport

WithBearerToken adds an Authorization header with "Bearer " prefix and add the given bearerToken as value to all requests. To regular update your token you need to call this method and use the returned Transport.

func WithComponentTag Uses

func WithComponentTag(t *Transport, componentName string) *Transport

WithComponentTag sets the component name, if you have an enabled tracing Transport.

func WithSpanName Uses

func WithSpanName(t *Transport, spanName string) *Transport

WithSpanName sets the name of the span, if you have an enabled tracing Transport.

func (*Transport) Close Uses

func (t *Transport) Close()

func (*Transport) CloseIdleConnections Uses

func (t *Transport) CloseIdleConnections()

func (*Transport) RoundTrip Uses

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip the request with tracing, bearer token injection and add client tracing: DNS, TCP/IP, TLS handshake, connection pool access. Client traces are added as logs into the created span.

Package net imports 12 packages (graph) and is imported by 12 packages. Updated 2020-03-28. Refresh now. Tools for package owners.