httransform

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 22, 2019 License: MIT Imports: 18 Imported by: 2

README

httransform

Build Status CodeCov GoDoc Reference Go Report Card

httransform is the library/framework to build your own HTTP proxies. It relies on high-performant and memory-efficient fasthttp library as HTTP base layer and can give you the ability to build a proxy where you can control every aspect.

Main features of this framework:

  1. Support of HTTP (plain HTTP) proxy protocol.
  2. Support of HTTPS (with CONNECT method) protocol. This library does MITM and provides the possibility to generate TLS certificates for the hosts on-the-fly.
  3. Keeps and maintains the order of headers and their case (no normalization).
  4. Supports the concept of layers or middlewares which process HTTP requests and responses.
  5. Supports custom executors: a function which converts HTTP requests to HTTP responses. Allowing your proxy to fetch the data from other services, which are not necessarily HTTP. The executor simply converts HTTP request structure to HTTP response.

Please check the full documentation for more details.

Example

Just a small example to give you the feeling of how it all looks like:

package main

import (
    "net"

    "github.com/9seconds/httransform"
)

// These are generates examples of self-signed certificates
// to simplify the example.
var caCert = []byte(`-----BEGIN CERTIFICATE-----
MIICWzCCAcSgAwIBAgIJAJ34yk7oiKv5MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgxMjAyMTQyNTAyWhcNMjgxMTI5MTQyNTAyWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDL7Hzfmx7xfFWTRm26t/lLsCZwOri6VIzp2dYM5Hp0dV4XUZ+q60nEbHwN3Usr
GKAK/Rsr9Caam3A18Upn2ly69Tyr29kVK+PlsOgSSCUnAYcqT166/j205n3CGNLL
OPtQKfAT/iH3dPBObd8N4FR9FlXiYIiAp1opCbyu2mlHiwIDAQABo1MwUTAdBgNV
HQ4EFgQUOJ+uGtIhHxXHPNESBNI4YbwAl+wwHwYDVR0jBBgwFoAUOJ+uGtIhHxXH
PNESBNI4YbwAl+wwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCW
s7P0wJ8ON8ieEJe4pAfACpL6IyhZ5YK/C/hip+czxdvZHc5zngVwHP2vsIcHKBTr
8qXoHgh2gaXqwn8kRVNnZzWrxgSe8IR3oJ2yTbLAxqDS42SPfRLAUpy9sK/tEEGM
rMk/LWMzH/S6bLcsAm0GfVIrUNfg0eF0ZVIjxINBVA==
-----END CERTIFICATE-----`)

var caPrivateKey = []byte(`-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMvsfN+bHvF8VZNG
bbq3+UuwJnA6uLpUjOnZ1gzkenR1XhdRn6rrScRsfA3dSysYoAr9Gyv0JpqbcDXx
SmfaXLr1PKvb2RUr4+Ww6BJIJScBhypPXrr+PbTmfcIY0ss4+1Ap8BP+Ifd08E5t
3w3gVH0WVeJgiICnWikJvK7aaUeLAgMBAAECgYAk+/kR3OJZzcD/evB/wsoV7haq
mBvUv2znJLjrkayb3oV4GTeqGg5A76P4J8BwSoEMPSdma1ttAu/w+JgUCchzVPwU
34Sr80mYawOmGVGJsDnrrYA2w51Nj42e71pmRc9IqNLwFEhW5Uy7eASf3THJMWDl
F2M6xAVYr+X0eKLf4QJBAO8lVIIMnzIReSZukWBPp6GKmXOuEkWeBOfnYC2HOVZq
1M/E6naOP2MBk9CWG4o9ysjcZ1hosi3/txxrc8VmBAkCQQDaS651dpQ3TRE//raZ
s79ZBEdMCMlgXB6CPrZpvLz/3ZPcLih4MJ59oVkeFHCNct7ccQcQu4XHMGNBIRBh
kpvzAkEAlS/AjHC7T0y/O052upJ2jLweBqBtHaj6foFE6qIVDugOYp8BdXw/5s+x
GsrJ22+49Z0pi2mk3jVMUhpmWprNoQJBANdAT0v2XFpXfQ38bTQMYT82j9Myytdg
npjRm++Rs1AdvoIbZb52OqIoqoaVoxJnVchLD6t5LYXnecesAcok1e8CQEKB7ycJ
6yVwnBE3Ua9CHcGmrre6HmEWdPy1Zyb5DQC6duX46zEBzti9oWx0DJIQRZifeCvw
4J45NsSQjuuAAWs=
-----END PRIVATE KEY-----`)

func main() {
	ln, err := net.Listen("tcp", "127.0.0.1:3128")
	if err != nil {
		panic(err)
	}
	opts := ServerOpts{
		CertCA:  caCert,
		CertKey: caPrivateKey,
		Layers: []Layer{
			&ProxyAuthorizationBasicLayer{
				User:     []byte("user"),
				Password: []byte("password"),
				Realm:    "test",
			},
			&AddRemoveHeaderLayer{
				AbsentRequestHeaders: []string{"proxy-authorization"},
			},
		},
	}
	srv, err := NewServer(opts)
	if err != nil {
		panic(err)
	}

	if err := srv.Serve(ln); err != nil {
		panic(err)
	}
}

This will create an HTTP proxy on 127.0.0.1:3128. It will also require authentication (user and password) and will remove the Proxy-Authorization header before sending the request further.

Documentation

Overview

Package httransform is the framework to build HTTP proxies in Go.

This framework is built using fasthttp (https://github.com/valyala/fasthttp) library to provide fast processing of HTTP requests. Also, as fasthttp it actively uses object pooling to reduce the pressure on GC and possibly save a little bit of memory. Unlike its alternative, goproxy (https://github.com/elazarl/goproxy), httransform does not have disadvantages of using net/http: we can keep header case and order.

This framework provides features to build robust high-performant HTTP and HTTPS proxies (with the support of the CONNECT method and TLS certificate generation on-the-fly), it supports middleware layers and custom executors.

Layers are middlewares which do preprocess of the requests or postprocessing of the response. The thing about layers is that you have to define both directions: to executor and from executor. We encourage to create layers which know as less as possible about each other. If, for example, you raise an error in one layer, this error has to be processed only there, other layers should ignore that. This framework does not restrict any deviations from this rule, but you'll get more simple and clean design if you treat layers as independent as possible.

An executor is some function which converts HTTP request to response. In the most simple case, an executor is HTTP client. But also, you can convert the request to JSON, send it somewhere, get ProtoBuf back and convert it to HTTP response. Or you can play with NATS. Or 0mq. Or RabbitMQ. You got the idea. Executor defines the function which converts HTTP request to HTTP response.

If any of your layers creates an error, executor won't be called. HTTP response will be converted to 500 response and error would be propagated by the chain of layers back.

One scheme worth 1000 words:

       HTTP interface            Layer 1             Layer 2
     +----------------+      **************      **************
     |                |      *            *      *            *       ==============
---> |  HTTP request  | ===> *  OnRequest * ===> *  OnRequest * ===>  =            =
     |                |      *            *      *            *       =            =
     +----------------+      **************      **************       =  Executor  =
     |                |      *            *      *            *       =            =
<--- |  HTTP response | <=== * OnResponse * <=== * OnResponse * <===  =            =
     |                |      *            *      *            *       ==============
     +----------------+      **************      **************

As you see, the request goes through the all layers forward and backward. This is a contract of this package. Also, the executor does not raise an error. If the request is finished with an error, it has to be terminated within an executor. If executor got an error, it has to write into HTTP response about it.

Not let's see what is happening if OnRequest gives an error:

       HTTP interface            Layer 1                 Layer 2
     +----------------+      **************           **************
     |                |      *            *           *            *       ==============
---> |  HTTP request  | ===> *  OnRequest * ===> X    *  OnRequest *       =            =
     |                |      *            *      |    *            *       =            =
     +----------------+      **************      |    **************       =  Executor  =
     |                |      *            *      |    *            *       =            =
<--- |  HTTP response | <=== * OnResponse * <=== +    * OnResponse *       =            =
     |                |      *            *           *            *       ==============
     +----------------+      **************           **************

Almost the same story: the error is propagated back through the layers. On error, httransform generates a default InternalServerError response, and this error returns back through the chain of layers.

Index

Examples

Constants

View Source
const (
	// MaxConnsPerHost is the maximal number of open connections to some
	// host in HTTP client.
	MaxConnsPerHost = 8192

	// ConnectDialTimeout is the timeout to establish TCP connection to the
	// host. Usually it is used only for proxy chains.
	ConnectDialTimeout = 30 * time.Second

	// DefaultHTTPTImeout is the timeout from starting of HTTP request to
	// getting a response.
	DefaultHTTPTImeout = 3 * time.Minute
)

Defaults for HTTP clients.

View Source
const (
	// DefaultConcurrency is the number of concurrent connections for the
	// service.
	DefaultConcurrency = fasthttp.DefaultConcurrency

	// DefaultReadBufferSize is default size of read buffer for the
	// connection in bytes.
	DefaultReadBufferSize = 4096

	// DefaultWriteBufferSize is default size of write buffer for the
	// connection in bytes.
	DefaultWriteBufferSize = 4096

	// DefaultReadTimeout is the default timeout httransform uses to read
	// from user request.
	DefaultReadTimeout = time.Minute

	// DefaultWriteTimeout is the default timeout httransform uses to write
	// to user request.
	DefaultWriteTimeout = time.Minute

	// DefaultTLSCertCacheSize is the number of items we store in LRU cache
	// of generated TLS certificates before starting to prune obsoletes.
	DefaultTLSCertCacheSize = 10000
)

Defaults for ServerOpts.

Variables

View Source
var (
	// ErrProxyAuthorization is the error for ProxyAuthorizationBasicLayer
	// instance. If OnRequest callback of this method returns such an error,
	// then OnResponse callback generates correct 407 response.
	ErrProxyAuthorization = xerrors.New("cannot authenticate proxy user")
)

Functions

func ExecuteRequest

func ExecuteRequest(client HTTPRequestExecutor, req *fasthttp.Request, resp *fasthttp.Response)

ExecuteRequest is a basic method on executing requests. On error, it also converts response to default 500.

func ExecuteRequestTimeout

func ExecuteRequestTimeout(client HTTPRequestExecutor, req *fasthttp.Request, resp *fasthttp.Response, timeout time.Duration)

ExecuteRequestTimeout does the same as ExecuteRequest but also uses given timeout.

func ExtractAuthentication

func ExtractAuthentication(text []byte) ([]byte, []byte, error)

ExtractAuthentication parses the value of Proxy-Authorization header and returns values for user and password. Only Basic authentication scheme is supported.

Example
username := "user"
password := "password"
encoded := "Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password))

user, pass, _ := ExtractAuthentication([]byte(encoded))

fmt.Println(encoded)
fmt.Println(string(user))
fmt.Println(string(pass))
Output:

Basic dXNlcjpwYXNzd29yZA==
user
password

func HTTPExecutor

func HTTPExecutor(state *LayerState)

HTTPExecutor is the default executor and the simplies one you want to use. It does takes HTTP request from the state and execute the request, returning response after that.

func MakeProxyAuthorizationHeaderValue

func MakeProxyAuthorizationHeaderValue(proxyURL *url.URL) []byte

MakeProxyAuthorizationHeaderValue builds a value of Proxy-Authorization header with Basic authentication scheme based on information, given in URL.

If no user/pass is defined, then function returns nil.

Example (Full)

This exqmple shows how to use this function with both user and password.

u := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
	User:   url.UserPassword("user", "password"),
}

fmt.Println(u)
fmt.Println(string(MakeProxyAuthorizationHeaderValue(u)))
Output:

http://user:password@127.0.0.1:3128
Basic dXNlcjpwYXNzd29yZA==
Example (Nothing)

This example shows how this function behaves if we provide no credentials.

u := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}

fmt.Println(u)
fmt.Println(MakeProxyAuthorizationHeaderValue(u))
Output:

http://127.0.0.1:3128
[]
Example (User)

This example shows how to use this function if you have only user.

u := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
	User:   url.User("user"),
}

fmt.Println(u)
fmt.Println(string(MakeProxyAuthorizationHeaderValue(u)))
Output:

http://user@127.0.0.1:3128
Basic dXNlcjo=

func MakeSimpleResponse

func MakeSimpleResponse(resp *fasthttp.Response, msg string, statusCode int)

MakeSimpleResponse is a shortcut function which sets given message and status code to response. This is destructive function, all existing contents of the response are cleared, even body.

func ParseHeaders

func ParseHeaders(hset *HeaderSet, rawHeaders []byte) error

ParseHeaders parses raw HTTP headers into the headerset.

Types

type AddRemoveHeaderLayer

type AddRemoveHeaderLayer struct {
	// FrozenRequestHeaders is the set of headers which should be present
	// in the request with given values.
	FrozenRequestHeaders map[string]string

	// FrozenResponseHeaders is the set of headers which should be present
	// in the response with given values.
	FrozenResponseHeaders map[string]string

	// DefaultRequestHeaders is the set of headers which should be present
	// in the request. If RequestHeaders already has some value for the
	// header, then this layer does nothing. If value is absent, then
	// header is populated with the given default.
	DefaultRequestHeaders map[string]string

	// DefaultResponseHeaders is the set of headers which should be present
	// in the response. If ResponseHeaders already has some value for the
	// header, then this layer does nothing. If value is absent, then
	// header is populated with the given default.
	DefaultResponseHeaders map[string]string

	// AbsentRequestHeaders is the list of headers which should be
	// dropped from the request. This list has bigger priority than
	// FrozenRequestHeaders or DefaultRequestHeaders.
	AbsentRequestHeaders []string

	// AbsentResponseHeaders is the list of headers which should be
	// dropped from the response. This list has bigger priority than
	// FrozenResponseHeaders or DefaultResponseHeaders.
	AbsentResponseHeaders []string
}

AddRemoveHeaderLayer is the generic layer to manage request/response headers. If you need to add some special headers or remove sensitive data, please use this layer.

func (*AddRemoveHeaderLayer) OnRequest

func (a *AddRemoveHeaderLayer) OnRequest(state *LayerState) error

OnRequest is the callback for Layer interface.

func (*AddRemoveHeaderLayer) OnResponse

func (a *AddRemoveHeaderLayer) OnResponse(state *LayerState, err error)

OnResponse is the callback for Layer interface.

type Executor

type Executor func(*LayerState)

Executor presents a type which converts HTTP request to HTTP response. It is not necessary that executor is limited to HTTP. It can do anything, but as a result, it has to update response.

func MakeProxyChainExecutor

func MakeProxyChainExecutor(proxyURL *url.URL) (Executor, error)

MakeProxyChainExecutor is the factory which produce executors which execute given HTTP request using HTTP proxy. In other words, MakeProxyChainExecutor allows to chain HTTP proxies. This executor supports SOCKS5, HTTP and HTTPS proxies.

Example (Http)

Let's assume that our HTTP proxy is placed on 127.0.0.1:3128 address. Then we have to build the correct URL with HTTP scheme. Also, please remember that this executor will support both HTTP and HTTP proxies (i.e, will do CONNECT method for HTTPS).

httpURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
state := &LayerState{}

executor, _ := MakeProxyChainExecutor(httpURL)
executor(state)
Output:

Example (Socks5)

Let's assume that our SOCKS5 proxy is placed on 127.0.0.1:4040 address. Then we have to build the correct URL with socks5 scheme.

socksURL := &url.URL{
	Scheme: "socks5",
	Host:   "127.0.0.1:4040",
}
state := &LayerState{}

executor, _ := MakeProxyChainExecutor(socksURL)
executor(state)
Output:

type HTTPRequestExecutor

type HTTPRequestExecutor interface {
	Do(*fasthttp.Request, *fasthttp.Response) error
	DoTimeout(*fasthttp.Request, *fasthttp.Response, time.Duration) error
}

HTTPRequestExecutor is an interface to be used for ExecuteRequest and ExecuteRequestTimeout functions.

func MakeDefaultCONNECTProxyClient

func MakeDefaultCONNECTProxyClient(proxyURL *url.URL) HTTPRequestExecutor

MakeDefaultCONNECTProxyClient returns HTTPRequestExecutor which fetches the whole body in memory.

Please use this client if you need production-grade HTTP client.

This client uses given HTTPS proxy. You should not use this client for HTTP requests.

Example

Let's assume that HTTPS proxy is placed on "127.0.0.1:3128".

proxyURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
executor := MakeDefaultCONNECTProxyClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

// Please pay attention that we can access only https:// with this client.
req.SetRequestURI("https://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeDefaultHTTPClient

func MakeDefaultHTTPClient() HTTPRequestExecutor

MakeDefaultHTTPClient returns HTTPRequestExecutor which fetches the whole body in memory.

Please use this client if you need production-grade HTTP client.

Example
executor := MakeDefaultHTTPClient()

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeDefaultHTTPProxyClient

func MakeDefaultHTTPProxyClient(proxyURL *url.URL) HTTPRequestExecutor

MakeDefaultHTTPProxyClient returns HTTPRequestExecutor which fetches the whole body in memory.

Please use this client if you need production-grade HTTP client.

This client uses given HTTP proxy. You should not use this client for HTTPS requests.

Example

Let's assume that HTTP proxy is placed on "127.0.0.1:3128".

proxyURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
executor := MakeDefaultHTTPProxyClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

// Please pay attention that we can access only http:// with this client.
req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeDefaultSOCKS5ProxyClient

func MakeDefaultSOCKS5ProxyClient(proxyURL *url.URL) HTTPRequestExecutor

MakeDefaultSOCKS5ProxyClient returns HTTPRequestExecutor which fetches the whole body in memory.

Please use this client if you need production-grade HTTP client.

This client uses given SOCKS5 proxy.

Example

Let's assume that SOCKS5 proxy is placed on "127.0.0.1:4040".

proxyURL := &url.URL{
	Scheme: "socks5",
	Host:   "127.0.0.1:4040",
}
executor := MakeDefaultSOCKS5ProxyClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingClosingCONNECTHTTPClient

func MakeStreamingClosingCONNECTHTTPClient(proxyURL *url.URL) HTTPRequestExecutor

MakeStreamingClosingCONNECTHTTPClient returns HTTPRequestExecutor which streams body response but closes connection after every request.

This client uses given HTTPS proxy. You should not use this client for HTTP requests.

Example

Let's assume that HTTPS proxy is placed on "127.0.0.1:3128".

proxyURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
executor := MakeStreamingClosingCONNECTHTTPClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

// Please pay attention that we can access only https:// with this client.
req.SetRequestURI("https://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingClosingHTTPClient

func MakeStreamingClosingHTTPClient() HTTPRequestExecutor

MakeStreamingClosingHTTPClient returns HTTPRequestExecutor which streams body response but closes connection after every request.

Example
executor := MakeStreamingClosingHTTPClient()

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingClosingProxyHTTPClient

func MakeStreamingClosingProxyHTTPClient(proxyURL *url.URL) HTTPRequestExecutor

MakeStreamingClosingProxyHTTPClient returns HTTPRequestExecutor which streams body response but closes connection after every request.

This client uses given HTTP proxy. You should not use this client for HTTPS requests.

Example

Let's assume that HTTP proxy is placed on "127.0.0.1:3128".

proxyURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
executor := MakeStreamingClosingProxyHTTPClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

// Please pay attention that we can access only http:// with this client.
req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingClosingSOCKS5HTTPClient

func MakeStreamingClosingSOCKS5HTTPClient(proxyURL *url.URL) HTTPRequestExecutor

MakeStreamingClosingSOCKS5HTTPClient returns HTTPRequestExecutor which streams body response but closes connection after every request.

This client uses given SOCKS5 proxy.

Example

Let's assume that SOCKS5 proxy is placed on "127.0.0.1:4040".

proxyURL := &url.URL{
	Scheme: "socks5",
	Host:   "127.0.0.1:4040",
}
executor := MakeStreamingClosingSOCKS5HTTPClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingReuseCONNECTHTTPClient

func MakeStreamingReuseCONNECTHTTPClient(proxyURL *url.URL) HTTPRequestExecutor

MakeStreamingReuseCONNECTHTTPClient returns HTTPRequestExecutor which streams body response and maintains a pool of connections to the hosts.

This client uses given HTTPS proxy. You should not use this client for HTTP requests.

Example

Let's assume that HTTPS proxy is placed on "127.0.0.1:3128".

proxyURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
executor := MakeStreamingReuseCONNECTHTTPClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

// Please pay attention that we can access only https:// with this client.
req.SetRequestURI("https://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingReuseHTTPClient

func MakeStreamingReuseHTTPClient() HTTPRequestExecutor

MakeStreamingReuseHTTPClient returns HTTPRequestExecutor which streams body response and maintains a pool of connections to the hosts.

Example
executor := MakeStreamingReuseHTTPClient()

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingReuseProxyHTTPClient

func MakeStreamingReuseProxyHTTPClient(proxyURL *url.URL) HTTPRequestExecutor

MakeStreamingReuseProxyHTTPClient returns HTTPRequestExecutor which streams body response and maintains a pool of connections to the hosts.

This client uses given HTTP proxy. You should not use this client for HTTPS requests.

Example

Let's assume that HTTP proxy is placed on "127.0.0.1:3128".

proxyURL := &url.URL{
	Scheme: "http",
	Host:   "127.0.0.1:3128",
}
executor := MakeStreamingReuseProxyHTTPClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

// Please pay attention that we can access only http:// with this client.
req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

func MakeStreamingReuseSOCKS5HTTPClient

func MakeStreamingReuseSOCKS5HTTPClient(proxyURL *url.URL) HTTPRequestExecutor

MakeStreamingReuseSOCKS5HTTPClient returns HTTPRequestExecutor which streams body response and maintains a pool of connections to the hosts.

This client uses given SOCKS5 proxy.

Example

Let's assume that SOCKS5 proxy is placed on "127.0.0.1:4040".

proxyURL := &url.URL{
	Scheme: "socks5",
	Host:   "127.0.0.1:4040",
}
executor := MakeStreamingReuseSOCKS5HTTPClient(proxyURL)

req := fasthttp.AcquireRequest()
defer fasthttp.ReleaseRequest(req)

resp := fasthttp.AcquireResponse()
defer fasthttp.ReleaseResponse(resp)

req.SetRequestURI("http://google.com")
req.Header.SetMethod("GET")

_ = executor.Do(req, resp)
Output:

type Header struct {
	// HTTP headers are case-insensitive so we need to have some case
	// insensitive ID to be able to refer them. ID usually stores
	// lowercased key.
	ID string

	// Key stores the name of the header (with correct case).
	Key []byte

	// Value stores value of the header (with correct case).
	Value []byte
}

Header is a structure to present both key and value of the header.

func (*Header) String

func (h *Header) String() string

String method returns some string representation of this datastructure so *Header implements fmt.Stringer interface.

type HeaderSet

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

HeaderSet presents collection of headers keeping their order.

If you delete a header, then other headers will keep their positions. If you update the value again, then original position is going to be restored.

hs := HeaderSet{}
hs.SetString("Connection", "close")
hs.GetString("connection")

This will return you "close". Please pay attention to the fact that we've used lowercased version. It works. And it works even for updates.

hs := HeaderSet{}
hs.SetString("Connection", "close")
hs.SetString("connection", "keep-alive")
hs.GetString("Connection")

This will return you "keep-alive". What will you see on the wire? Header name will be "Connection" because we've seen such case in the first place.

func (*HeaderSet) Clear

func (hs *HeaderSet) Clear()

Clear drops internal state of the headerset.

func (*HeaderSet) DeleteBytes

func (hs *HeaderSet) DeleteBytes(key []byte)

DeleteBytes is a version of DeleteString which accepts bytes.

func (*HeaderSet) DeleteString

func (hs *HeaderSet) DeleteString(key string)

DeleteString removes (marks as deleted) a header with the given key from header set.

func (*HeaderSet) GetBytes

func (hs *HeaderSet) GetBytes(key []byte) ([]byte, bool)

GetBytes is the version of GetString which works with bytes.

func (*HeaderSet) GetString

func (hs *HeaderSet) GetString(key string) (string, bool)

GetString returns a value of the header with the given name (ignoring the case). If no such header exist, then second parameter is false.

Semantically, this method is similar to accessing map's key.

func (*HeaderSet) Items

func (hs *HeaderSet) Items() []*Header

Items returns a list of headers from header set in the correct order.

func (*HeaderSet) SetBytes

func (hs *HeaderSet) SetBytes(key []byte, value []byte)

SetBytes is the version of SetString which works with bytes.

func (*HeaderSet) SetString

func (hs *HeaderSet) SetString(key, value string)

SetString sets key and value of the header. If we've already seen such header (ignoring its case), we'll update it value, otherwise header will be appended to the list. If header was deleted, it would be restored keeping the original position in header set.

func (*HeaderSet) String

func (hs *HeaderSet) String() string

String returns a string representation of the header set. So, *HeaderSet implements fmt.Stringer interface.

type Layer

type Layer interface {
	OnRequest(*LayerState) error
	OnResponse(*LayerState, error)
}

Layer is the middleware for HTTP proxy. Every request will go through OnRequest method. If method spot the error, it has to return it. In that case we won't propagate such error forward, it is going to go backwards by the stack of layers.

We do not limit you but encourgate every layer to manage its own errors. So, if your layer raises ErrSomething, then you have to handle only ErrSomething in OnResponse method. Any other errors should be ignored. Sometimes this advice is tricky to implement but in general it leads to more simpler design.

Layer contracts: if you executed OnRequest, then we should execute OnResponse. Another contract is order: if you execute layer in order 1-2-3-4-5, then OnResponse chains will be executed in order of 5-4-3-2-1 (stack rewind). If step 3 executed error, then execution is stopped and we'll call OnResponses as 3-2-1.

type LayerState

type LayerState struct {
	// RequestID has unique identifier of every request.
	RequestID uint64

	// ProxyUser is username taken from Proxy-Authorization header. Empty
	// if nothing is present.
	ProxyUser []byte

	// ProxyPassword is password taken from Proxy-Authorization header.
	// Empty if nothing is present.
	ProxyPassword []byte

	// RequestHeaders contains request headers. This structure is populated
	// by httransform so you do not need to fill it from the initial
	// contents of Request.
	//
	// If you want to update request headers, you should do it using
	// this field, do not modify Request directly. After the last layer
	// but before propagation to executer, httransform drops contents of
	// Request.Header and fills them with items from RequestHeaders.
	RequestHeaders *HeaderSet

	// ResponseHeaders contains response headers. This structure is
	// populated by httransform so you do not need to fill it from the
	// initial contents of Response.
	//
	// If you want to update response headers, you should do it using this
	// field, do not modify Response directly. After the last layer but
	// before returning back to the client, httransform drops contents of
	// Response.Header and fills them with items from ResponseHeaders.
	ResponseHeaders *HeaderSet

	// Request is the instance of the original request.
	Request *fasthttp.Request

	// Response is the instance of the original response.
	Response *fasthttp.Response

	// RemoteAddr is an IP address + port of the client initiated the
	// connection.
	RemoteAddr net.Addr
	// contains filtered or unexported fields
}

LayerState is the state structure which propagated through layer chain and terminated on Executor.

You may see Request/Response structures there. You can update then but we encourage you to update relevant HeaderSet structure if you want to keep order of headers.

Also, LayerState provides context-like interface so you can store your values there using Set/Get/Delete methods.

func (*LayerState) Delete

func (l *LayerState) Delete(key string)

Delete removes key from the context of the LayerState. It is safe to unknown keys.

func (*LayerState) Get

func (l *LayerState) Get(key string) (interface{}, bool)

Get takes value from the context of layer state. If LayerState instance has no such key, then last parameter is false. If it has - true.

func (*LayerState) Set

func (l *LayerState) Set(key string, value interface{})

Set sets new value to the context of layer state.

type LogTracer

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

LogTracer stores duration of execution for OnRequest/OnResponse of every layer as well as time elapsed in executor and dumps it to logger.

func (*LogTracer) Clear

func (l *LogTracer) Clear()

Clear drops internal state of the tracer before returning it back to the TracerPool.

func (*LogTracer) Dump

func (l *LogTracer) Dump(state *LayerState, logger Logger)

Dump dumps internal state of the tracer when request is finished its execution.

func (*LogTracer) FinishExecute

func (l *LogTracer) FinishExecute()

FinishExecute is executed after calling executor of the request.

func (*LogTracer) FinishOnRequest

func (l *LogTracer) FinishOnRequest(err error)

FinishOnRequest is executed after calling OnRequest for every layer.

func (*LogTracer) FinishOnResponse

func (l *LogTracer) FinishOnResponse()

FinishOnResponse is executed after calling OnResponse for every layer.

func (*LogTracer) StartExecute

func (l *LogTracer) StartExecute()

StartExecute is executed before calling an executor of the request.

func (*LogTracer) StartOnRequest

func (l *LogTracer) StartOnRequest()

StartOnRequest is executed before calling OnRequest for every layer.

func (*LogTracer) StartOnResponse

func (l *LogTracer) StartOnResponse()

StartOnResponse is executed before calling OnResponse for every layer.

type Logger

type Logger interface {
	// Debug logs information which is usable only for debugging. Usually
	// this is quite noisy data you absolutely do not want to have in
	// production.
	Debug(string, ...interface{})

	// Info logs some informational messages about the current state.
	Info(string, ...interface{})

	// Warn logs events which are suspicious but the system can continue to
	// work.
	Warn(string, ...interface{})

	// Error logs events which are serious problems which can corrupt your
	// server.
	Error(string, ...interface{})

	// Panic logs events which lead to crash.
	Panic(string, ...interface{})
}

Logger is the common interface for the logger which can be used within httransform internals. Basically, if you need to log something from internals, please propagate something which implements this interface to NewServer.

All methods of this interface should work in Print mode: messages and arguments.

type Metrics

type Metrics interface {
	// NewConnection reports new established connection.
	NewConnection()

	// DropConnection reports connection closed.
	DropConnection()

	// NewGet reports about new HTTP GET request.
	NewGet()

	// NewHead reports about new HTTP HEAD request.
	NewHead()

	// NewPost reports about new HTTP POST request.
	NewPost()

	// NewPut reports about new HTTP PUT request.
	NewPut()

	// NewDelete reports about new HTTP DELETE request.
	NewDelete()

	// NewConnect reports about new HTTP CONNECT request.
	NewConnect()

	// NewOptions reports about new HTTP OPTIONS request.
	NewOptions()

	// NewTrace reports about new HTTP TRACE request.
	NewTrace()

	// NewPatch reports about new HTTP PATCH request.
	NewPatch()

	// NewOther reports about new HTTP request with rate verb.
	NewOther()

	// DropGet reports about closed HTTP GET request.
	DropGet()

	// DropHead reports about closed HTTP HEAD request.
	DropHead()

	// DropPost reports about closed HTTP POST request.
	DropPost()

	// DropPut reports about closed HTTP PUT request.
	DropPut()

	// DropDelete reports about closed HTTP DELETE request.
	DropDelete()

	// DropConnect reports about closed HTTP CONNECT request.
	DropConnect()

	// DropOptions reports about closed HTTP OPTIONS request.
	DropOptions()

	// DropTrace reports about closed HTTP TRACE request.
	DropTrace()

	// DropPatch reports about closed HTTP PATCH request.
	DropPatch()

	// DropOther reports about closed HTTP request with rate verb.
	DropOther()

	// NewCertificate reports about new generated TLS certificate.
	NewCertificate()

	// DropCertificate reports about pruned TLS certificate.
	DropCertificate()
}

Metrics is an interface for notifying on multiple events which can happen within a framework. For example, open/close connections, some method counters etc.

type NoopLogger

type NoopLogger struct{}

NoopLogger is a dummy logger which drops out messages.

func (*NoopLogger) Debug

func (n *NoopLogger) Debug(_ string, _ ...interface{})

Debug is to support Logger interface.

func (*NoopLogger) Error

func (n *NoopLogger) Error(_ string, _ ...interface{})

Error is to support Logger interface.

func (*NoopLogger) Info

func (n *NoopLogger) Info(_ string, _ ...interface{})

Info is to support Logger interface.

func (*NoopLogger) Panic

func (n *NoopLogger) Panic(msg string, args ...interface{})

Panic is to support Logger interface.

func (*NoopLogger) Warn

func (n *NoopLogger) Warn(_ string, _ ...interface{})

Warn is to support Logger interface.

type NoopMetrics

type NoopMetrics struct{}

NoopMetrics is a metrics structure which does nothing.

func (*NoopMetrics) DropCertificate

func (n *NoopMetrics) DropCertificate()

DropCertificate reports about pruned TLS certificate.

func (*NoopMetrics) DropConnect

func (n *NoopMetrics) DropConnect()

DropConnect reports about closed HTTP CONNECT request.

func (*NoopMetrics) DropConnection

func (n *NoopMetrics) DropConnection()

DropConnection reports connection closed.

func (*NoopMetrics) DropDelete

func (n *NoopMetrics) DropDelete()

DropDelete reports about closed HTTP DELETE request.

func (*NoopMetrics) DropGet

func (n *NoopMetrics) DropGet()

DropGet reports about closed HTTP GET request.

func (*NoopMetrics) DropHead

func (n *NoopMetrics) DropHead()

DropHead reports about closed HTTP HEAD request.

func (*NoopMetrics) DropOptions

func (n *NoopMetrics) DropOptions()

DropOptions reports about closed HTTP OPTIONS request.

func (*NoopMetrics) DropOther

func (n *NoopMetrics) DropOther()

DropOther reports about closed HTTP request with rate verb.

func (*NoopMetrics) DropPatch

func (n *NoopMetrics) DropPatch()

DropPatch reports about closed HTTP PATCH request.

func (*NoopMetrics) DropPost

func (n *NoopMetrics) DropPost()

DropPost reports about closed HTTP POST request.

func (*NoopMetrics) DropPut

func (n *NoopMetrics) DropPut()

DropPut reports about closed HTTP PUT request.

func (*NoopMetrics) DropTrace

func (n *NoopMetrics) DropTrace()

DropTrace reports about closed HTTP TRACE request.

func (*NoopMetrics) NewCertificate

func (n *NoopMetrics) NewCertificate()

NewCertificate reports about new generated TLS certificate.

func (*NoopMetrics) NewConnect

func (n *NoopMetrics) NewConnect()

NewConnect reports about new HTTP CONNECT request.

func (*NoopMetrics) NewConnection

func (n *NoopMetrics) NewConnection()

NewConnection reports new established connection.

func (*NoopMetrics) NewDelete

func (n *NoopMetrics) NewDelete()

NewDelete reports about new HTTP DELETE request.

func (*NoopMetrics) NewGet

func (n *NoopMetrics) NewGet()

NewGet reports about new HTTP GET request.

func (*NoopMetrics) NewHead

func (n *NoopMetrics) NewHead()

NewHead reports about new HTTP HEAD request.

func (*NoopMetrics) NewOptions

func (n *NoopMetrics) NewOptions()

NewOptions reports about new HTTP OPTIONS request.

func (*NoopMetrics) NewOther

func (n *NoopMetrics) NewOther()

NewOther reports about new HTTP request with rate verb.

func (*NoopMetrics) NewPatch

func (n *NoopMetrics) NewPatch()

NewPatch reports about new HTTP PATCH request.

func (*NoopMetrics) NewPost

func (n *NoopMetrics) NewPost()

NewPost reports about new HTTP POST request.

func (*NoopMetrics) NewPut

func (n *NoopMetrics) NewPut()

NewPut reports about new HTTP PUT request.

func (*NoopMetrics) NewTrace

func (n *NoopMetrics) NewTrace()

NewTrace reports about new HTTP TRACE request.

type NoopTracer

type NoopTracer struct {
}

NoopTracer is a tracer which does nothing.

func (*NoopTracer) Clear

func (n *NoopTracer) Clear()

Clear drops internal state of the tracer before returning it back to the TracerPool.

func (*NoopTracer) Dump

func (n *NoopTracer) Dump(_ *LayerState, _ Logger)

Dump dumps internal state of the tracer when request is finished its execution.

func (*NoopTracer) FinishExecute

func (n *NoopTracer) FinishExecute()

FinishExecute is executed after calling executor of the request.

func (*NoopTracer) FinishOnRequest

func (n *NoopTracer) FinishOnRequest(_ error)

FinishOnRequest is executed after calling OnRequest for every layer.

func (*NoopTracer) FinishOnResponse

func (n *NoopTracer) FinishOnResponse()

FinishOnResponse is executed after calling OnResponse for every layer.

func (*NoopTracer) StartExecute

func (n *NoopTracer) StartExecute()

StartExecute is executed before calling an executor of the request.

func (*NoopTracer) StartOnRequest

func (n *NoopTracer) StartOnRequest()

StartOnRequest is executed before calling OnRequest for every layer.

func (*NoopTracer) StartOnResponse

func (n *NoopTracer) StartOnResponse()

StartOnResponse is executed before calling OnResponse for every layer.

type ProxyAuthorizationBasicLayer

type ProxyAuthorizationBasicLayer struct {
	// User is the username for proxy authorization.
	User []byte

	// Password is the password for proxy authorization.
	Password []byte

	// Realm is the proxy realm. This is not a mandatory header, this is
	// required only if we want to tell user about the realm she tries to
	// access.
	//
	// In other words, on authorization error, the value of
	// Proxy-Authenticate header would be 'Basic realm="RealmYouTold"'.
	Realm string
}

ProxyAuthorizationBasicLayer is the layer to manage Basic Proxy Authorization protocol (i.e Proxy-Authorization header) with predefined user/password pair.

func (*ProxyAuthorizationBasicLayer) MakeProxyAuthRequiredResponse

func (p *ProxyAuthorizationBasicLayer) MakeProxyAuthRequiredResponse(state *LayerState)

MakeProxyAuthRequiredResponse sets 407 response (Proxy Authorization Required).

func (*ProxyAuthorizationBasicLayer) OnRequest

func (p *ProxyAuthorizationBasicLayer) OnRequest(state *LayerState) error

OnRequest is the callback for Layer interface.

func (*ProxyAuthorizationBasicLayer) OnResponse

func (p *ProxyAuthorizationBasicLayer) OnResponse(state *LayerState, err error)

OnResponse is the callback for Layer interface.

type Server

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

Server presents a HTTP proxy service.

Example

This is an example of server which runs on some local port, checks authorization with user:password credentials.

{ // nolint: funlen
	// These 2 lines are example keys. If you want to generate your
	// own CA certificate and private key, please run following command:
	//
	// openssl req -x509 -newkey rsa:1024 -keyout private-key.pem -out ca.crt -days 3650 -nodes
	//
	var caCert = []byte(`-----BEGIN CERTIFICATE-----
MIICWzCCAcSgAwIBAgIJAJ34yk7oiKv5MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMTgxMjAyMTQyNTAyWhcNMjgxMTI5MTQyNTAyWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB
gQDL7Hzfmx7xfFWTRm26t/lLsCZwOri6VIzp2dYM5Hp0dV4XUZ+q60nEbHwN3Usr
GKAK/Rsr9Caam3A18Upn2ly69Tyr29kVK+PlsOgSSCUnAYcqT166/j205n3CGNLL
OPtQKfAT/iH3dPBObd8N4FR9FlXiYIiAp1opCbyu2mlHiwIDAQABo1MwUTAdBgNV
HQ4EFgQUOJ+uGtIhHxXHPNESBNI4YbwAl+wwHwYDVR0jBBgwFoAUOJ+uGtIhHxXH
PNESBNI4YbwAl+wwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCW
s7P0wJ8ON8ieEJe4pAfACpL6IyhZ5YK/C/hip+czxdvZHc5zngVwHP2vsIcHKBTr
8qXoHgh2gaXqwn8kRVNnZzWrxgSe8IR3oJ2yTbLAxqDS42SPfRLAUpy9sK/tEEGM
rMk/LWMzH/S6bLcsAm0GfVIrUNfg0eF0ZVIjxINBVA==
-----END CERTIFICATE-----`)

	var caPrivateKey = []byte(`-----BEGIN PRIVATE KEY-----
MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBAMvsfN+bHvF8VZNG
bbq3+UuwJnA6uLpUjOnZ1gzkenR1XhdRn6rrScRsfA3dSysYoAr9Gyv0JpqbcDXx
SmfaXLr1PKvb2RUr4+Ww6BJIJScBhypPXrr+PbTmfcIY0ss4+1Ap8BP+Ifd08E5t
3w3gVH0WVeJgiICnWikJvK7aaUeLAgMBAAECgYAk+/kR3OJZzcD/evB/wsoV7haq
mBvUv2znJLjrkayb3oV4GTeqGg5A76P4J8BwSoEMPSdma1ttAu/w+JgUCchzVPwU
34Sr80mYawOmGVGJsDnrrYA2w51Nj42e71pmRc9IqNLwFEhW5Uy7eASf3THJMWDl
F2M6xAVYr+X0eKLf4QJBAO8lVIIMnzIReSZukWBPp6GKmXOuEkWeBOfnYC2HOVZq
1M/E6naOP2MBk9CWG4o9ysjcZ1hosi3/txxrc8VmBAkCQQDaS651dpQ3TRE//raZ
s79ZBEdMCMlgXB6CPrZpvLz/3ZPcLih4MJ59oVkeFHCNct7ccQcQu4XHMGNBIRBh
kpvzAkEAlS/AjHC7T0y/O052upJ2jLweBqBtHaj6foFE6qIVDugOYp8BdXw/5s+x
GsrJ22+49Z0pi2mk3jVMUhpmWprNoQJBANdAT0v2XFpXfQ38bTQMYT82j9Myytdg
npjRm++Rs1AdvoIbZb52OqIoqoaVoxJnVchLD6t5LYXnecesAcok1e8CQEKB7ycJ
6yVwnBE3Ua9CHcGmrre6HmEWdPy1Zyb5DQC6duX46zEBzti9oWx0DJIQRZifeCvw
4J45NsSQjuuAAWs=
-----END PRIVATE KEY-----`)

	ln, err := net.Listen("tcp", "127.0.0.1:0") // 0 forces kernel to choose random port
	if err != nil {
		panic(err)
	}

	opts := ServerOpts{
		CertCA:  caCert,
		CertKey: caPrivateKey,
		Layers: []Layer{
			&ProxyAuthorizationBasicLayer{
				User:     []byte("user"),
				Password: []byte("password"),
				Realm:    "test",
			},
			&AddRemoveHeaderLayer{
				AbsentRequestHeaders: []string{"proxy-authorization"},
			},
		},
	}
	srv, err := NewServer(opts)

	if err != nil {
		panic(err)
	}

	go srv.Serve(ln) // nolint: errcheck

	proxyURL := &url.URL{
		Host:   ln.Addr().String(),
		Scheme: "http",
	}
	client := &http.Client{
		Transport: &http.Transport{
			Proxy: http.ProxyURL(proxyURL),
		},
	}

	resp, _ := client.Get("http://httpbin.org/status/200")
	fmt.Println(resp.Status)

	if _, err := io.Copy(ioutil.Discard, resp.Body); err != nil {
		panic(err)
	}

	resp.Body.Close()

	proxyURL.User = url.UserPassword("user", "password")
	client.Transport = &http.Transport{Proxy: http.ProxyURL(proxyURL)}
	resp, err = client.Get("http://httpbin.org/status/200")

	if err != nil {
		panic(err)
	}

	defer resp.Body.Close()

	fmt.Println(resp.Status)
	
Output:

407 Proxy Authentication Required
200 OK

func NewServer

func NewServer(opts ServerOpts) (*Server, error)

NewServer creates new instance of the Server.

func (*Server) Serve

func (s *Server) Serve(ln net.Listener) error

Serve starts to work using given listener.

func (*Server) Shutdown

func (s *Server) Shutdown() error

Shutdown gracefully stops the server.

type ServerOpts

type ServerOpts struct {
	// Concurrency is the number of concurrent connections to the service.
	Concurrency int

	// ReadBufferSize is the size of the read buffer for server TCP
	// connection.
	ReadBufferSize int

	// WriteBufferSize is the size of the write buffer for server TCP
	// connection.
	WriteBufferSize int

	// ReadTimeout is the timeout server uses to read from user request.
	ReadTimeout time.Duration

	// ReadTimeout is the timeout server uses to write to the user request.
	WriteTimeout time.Duration

	// CertCA is CA certificate for generating TLS certificate.
	CertCA []byte

	// CertKey is CA private key for generating TLS cerificate.
	CertKey []byte

	// OrganizationName is the name of organization which generated TLS
	// certificate.
	OrganizationName string

	// TLSCertCacheSize is the number of items we store in LRU cache
	// of generated TLS certificates before starting to prune obsoletes.
	TLSCertCacheSize int

	// Tracer is an instance of tracer pool to use. By default pool of
	// NoopTracers is going to be used.
	TracerPool *TracerPool

	// Layers presents a list of middleware layers used by proxy.
	// Can be nil.
	Layers []Layer

	// Executor is an instance of the Executor used by proxy. Default is
	// HTTPExecutor.
	Executor Executor

	// Logger is an instance of Logger used by proxy. Default is
	// NoopLogger.
	Logger Logger

	// Metrics is an instance of metrics client used by proxy. Default is
	// NoopMetrics.
	Metrics Metrics
}

ServerOpts is the datastructure to configure Server instance. The list of configuration options can be huge so it worth to use a separate object for this purpose.

func (*ServerOpts) GetCertCA

func (s *ServerOpts) GetCertCA() []byte

GetCertCA returns a CA certificate which should be used to generate TLS certificates.

func (*ServerOpts) GetCertKey

func (s *ServerOpts) GetCertKey() []byte

GetCertKey returns a CA private key which should be used to generate TLS certificates.

func (*ServerOpts) GetConcurrency

func (s *ServerOpts) GetConcurrency() int

GetConcurrency returns a number of concurrent connections for the service we have to set.

func (*ServerOpts) GetExecutor

func (s *ServerOpts) GetExecutor() Executor

GetExecutor returns executor to use.

func (*ServerOpts) GetLayers

func (s *ServerOpts) GetLayers() []Layer

GetLayers returns a list of middleware layers to use.

func (*ServerOpts) GetLogger

func (s *ServerOpts) GetLogger() Logger

GetLogger returns logger to use within proxy.

func (*ServerOpts) GetMetrics

func (s *ServerOpts) GetMetrics() Metrics

GetMetrics returns metrics client to use within proxy.

func (*ServerOpts) GetOrganizationName

func (s *ServerOpts) GetOrganizationName() string

GetOrganizationName returns a name of the organization which should issue TLS certificates.

func (*ServerOpts) GetReadBufferSize

func (s *ServerOpts) GetReadBufferSize() int

GetReadBufferSize returns the size of read buffer for the client connection in bytes we have to set to the server.

func (*ServerOpts) GetReadTimeout

func (s *ServerOpts) GetReadTimeout() time.Duration

GetReadTimeout is the timeout server has to use to read from user request.

func (*ServerOpts) GetTLSCertCacheSize

func (s *ServerOpts) GetTLSCertCacheSize() int

GetTLSCertCacheSize returns the number of items to store in LRU cache of generated TLS certificates before starting to prune obsoletes.

func (*ServerOpts) GetTracerPool

func (s *ServerOpts) GetTracerPool() *TracerPool

GetTracerPool returns a tracer pool to use.

func (*ServerOpts) GetWriteBufferSize

func (s *ServerOpts) GetWriteBufferSize() int

GetWriteBufferSize returns the size of write buffer for the client connection in bytes we have to set to the server.

func (*ServerOpts) GetWriteTimeout

func (s *ServerOpts) GetWriteTimeout() time.Duration

GetWriteTimeout is the timeout server has to use to write to user.

type StdLogger

type StdLogger struct {
	// Log is the configured instance of logger we want to wrap.
	Log *log.Logger
}

StdLogger is the wrapper over default log.Logger instance which provides Logger inteface for httransform.

func (*StdLogger) Debug

func (s *StdLogger) Debug(msg string, args ...interface{})

Debug is to support Logger interface.

func (*StdLogger) Error

func (s *StdLogger) Error(msg string, args ...interface{})

Error is to support Logger interface.

func (*StdLogger) Info

func (s *StdLogger) Info(msg string, args ...interface{})

Info is to support Logger interface.

func (*StdLogger) Panic

func (s *StdLogger) Panic(msg string, args ...interface{})

Panic is to support Logger interface.

func (*StdLogger) Warn

func (s *StdLogger) Warn(msg string, args ...interface{})

Warn is to support Logger interface.

type Tracer

type Tracer interface {
	// StartOnRequest is executed before calling OnRequest for every layer.
	StartOnRequest()

	// StartOnResponse is executed before calling OnResponse for every
	// layer.
	StartOnResponse()

	// StartExecute is executed before calling an executor of the request.
	StartExecute()

	// FinishOnRequest is executed after calling OnRequest for every layer.
	FinishOnRequest(err error)

	// FinishOnResponse is executed after calling OnResponse for every
	// layer.
	FinishOnResponse()

	// FinishExecute is executed after calling executor of the request.
	FinishExecute()

	// Clear drops internal state of the tracer before returning it back to
	// the TracerPool.
	Clear()

	// Dump dumps internal state of the tracer when request is finished its
	// execution.
	Dump(state *LayerState, logger Logger)
}

Tracer allows to trace how HTTP proxy works. On every event happening it executes a callback. After request processing is done, it executes Dump.

type TracerCreateFunc

type TracerCreateFunc func() Tracer

TracerCreateFunc is a function which creates a new tracer. This function has to be used for initialization of the TracerPool.

type TracerPool

type TracerPool struct {
	sync.Pool
}

TracerPool is a special instance of sync.Pool which manages tracer objects.

func NewTracerPool

func NewTracerPool(create TracerCreateFunc) *TracerPool

NewTracerPool creates a new instance of TracerPool based on the given create function.

Directories

Path Synopsis
Package ca contains functions to manage lifecycle of TLS CA.
Package ca contains functions to manage lifecycle of TLS CA.
Package client contains a simple implementation of HTTP 1 client which returns a streaming body.
Package client contains a simple implementation of HTTP 1 client which returns a streaming body.

Jump to

Keyboard shortcuts

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