README

PkgGoDev Go Report Card

httpsproxy

httpsproxy is a Go library provides an http serve mux that can work as an HTTPS proxy for a site with self-signed https certificate.

Why?

The main user of this library is blynk-proxy, please refer to its README for more information.

This library is moved out of blynk-proxy project because I believe others facing similar situation could benefit from it.

Example

Please refer to pkg.go.dev example or blynk-proxy code.

License

BSD 3-Clause.

Expand ▾ Collapse ▴

Documentation

Overview

Package httpsproxy provides an http serve mux that can work as an HTTPS proxy for a site with self-signed https certificate.

The main user of this library is blynk-proxy, please refer to that project for context and examples: https://github.com/fishy/blynk-proxy

Example

Code:

package main

import (
	"go.yhsif.com/httpsproxy"
	"log"
	"net/url"
	"os"
	"time"
)

func main() {
	target := "https://self-signed.badssl.com/"
	targetURL, err := url.Parse(target)
	if err != nil {
		log.Fatal(err)
	}

	// Get it by the following command:
	// openssl s_client -showcerts -connect self-signed.badssl.com:443 </dev/null
	cert := `-----BEGIN CERTIFICATE-----
MIIE8DCCAtigAwIBAgIJAM28Wkrsl2exMA0GCSqGSIb3DQEBCwUAMH8xCzAJBgNV
BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp
c2NvMQ8wDQYDVQQKDAZCYWRTU0wxMjAwBgNVBAMMKUJhZFNTTCBJbnRlcm1lZGlh
dGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTE2MDgwODIxMTcwNVoXDTE4MDgw
ODIxMTcwNVowgagxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYw
FAYDVQQHDA1TYW4gRnJhbmNpc2NvMTYwNAYDVQQKDC1CYWRTU0wgRmFsbGJhY2su
IFVua25vd24gc3ViZG9tYWluIG9yIG5vIFNOSS4xNDAyBgNVBAMMK2JhZHNzbC1m
YWxsYmFjay11bmtub3duLXN1YmRvbWFpbi1vci1uby1zbmkwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQDCBOz4jO4EwrPYUNVwWMyTGOtcqGhJsCK1+ZWe
sSssdj5swEtgTEzqsrTAD4C2sPlyyYYC+VxBXRMrf3HES7zplC5QN6ZnHGGM9kFC
xUbTFocnn3TrCp0RUiYhc2yETHlV5NFr6AY9SBVSrbMo26r/bv9glUp3aznxJNEx
tt1NwMT8U7ltQq21fP6u9RXSM0jnInHHwhR6bCjqN0rf6my1crR+WqIW3GmxV0Tb
ChKr3sMPR3RcQSLhmvkbk+atIgYpLrG6SRwMJ56j+4v3QHIArJII2YxXhFOBBcvm
/mtUmEAnhccQu3Nw72kYQQdFVXz5ZD89LMOpfOuTGkyG0cqFAgMBAAGjRTBDMAkG
A1UdEwQCMAAwNgYDVR0RBC8wLYIrYmFkc3NsLWZhbGxiYWNrLXVua25vd24tc3Vi
ZG9tYWluLW9yLW5vLXNuaTANBgkqhkiG9w0BAQsFAAOCAgEAsuFs0K86D2IB20nB
QNb+4vs2Z6kECmVUuD0vEUBR/dovFE4PfzTr6uUwRoRdjToewx9VCwvTL7toq3dd
oOwHakRjoxvq+lKvPq+0FMTlKYRjOL6Cq3wZNcsyiTYr7odyKbZs383rEBbcNu0N
c666/ozs4y4W7ufeMFrKak9UenrrPlUe0nrEHV3IMSF32iV85nXm95f7aLFvM6Lm
EzAGgWopuRqD+J0QEt3WNODWqBSZ9EYyx9l2l+KI1QcMalG20QXuxDNHmTEzMaCj
4Zl8k0szexR8rbcQEgJ9J+izxsecLRVp70siGEYDkhq0DgIDOjmmu8ath4yznX6A
pYEGtYTDUxIvsWxwkraBBJAfVxkp2OSg7DiZEVlMM8QxbSeLCz+63kE/d5iJfqde
cGqX7rKEsVW4VLfHPF8sfCyXVi5sWrXrDvJm3zx2b3XToU7EbNONO1C85NsUOWy4
JccoiguV8V6C723IgzkSgJMlpblJ6FVxC6ZX5XJ0ZsMI9TIjibM2L1Z9DkWRCT6D
QjuKbYUeURhScofQBiIx73V7VXnFoc1qHAUd/pGhfkCUnUcuBV1SzCEhjiwjnVKx
HJKvc9OYjJD0ZuvZw9gBrY7qKyBX8g+sglEGFNhruH8/OhqrV8pBXX/EWY0fUZTh
iywmc6GTT7X94Ze2F7iB45jh7WQ=
-----END CERTIFICATE-----`

	certPool, failed, err := httpsproxy.NewCertPool(cert)
	if err != nil {
		log.Printf("WARNING: Cannot get system cert pool: %v", err)
	}
	if len(failed) > 0 {
		log.Printf("WARNING: Failed to add cert(s) to pool: %v", failed)
	}

	selfURL, err := url.Parse("https://my-proxy.com")
	if err != nil {
		log.Printf("WARNING: Cannot get parse self URL: %v", err)
	}

	mux := httpsproxy.Mux(
		httpsproxy.DefaultHTTPClient(
			certPool,
			30*time.Second,
			httpsproxy.NoRedirCheckRedirectFunc,
		),
		targetURL,
		selfURL,
		nil, // logger
	)

	port := os.Getenv("PORT")
	if port == "" {
		port = "8080"
		log.Printf("Defaulting to port %s", port)
	}
	log.Printf("Listening on port %s", port)

	// Start serving with:
	// log.Fatal(http.ListenAndServe(":"+port, mux))
	_ = mux
}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func CheckError

func CheckError(logger *log.Logger, w http.ResponseWriter, err error) bool

CheckError checks error. If error is non-nil, it writes HTTP status code 502 (bad gateway) and the error message to the response and returns true.

func CopyRequestHeaders

func CopyRequestHeaders(from, to *http.Request, headers []string)

CopyRequestHeaders copies specified headers from one http.Request to another.

func DefaultHTTPClient

func DefaultHTTPClient(
	certPool *x509.CertPool,
	timeout time.Duration,
	checkRedirectFunc func(*http.Request, []*http.Request) error,
) *http.Client

DefaultHTTPClient returns an http client that can be used in Mux function with:

certPool: the x509 cert pool to trust.

timeout: the http timeout.

checkRedirectFunc: the function to handle 3xx redirects, could be nil which means default behavior.

func Mux

func Mux(
	client *http.Client,
	targetURL, selfURL *url.URL,
	logger *log.Logger,
) *http.ServeMux

Mux creates an http serve mux to do the proxy job.

The returned mux contains a single handler for "/" to the handler generated by ProxyRootHandler to do the proxy. You can add your own handlers to handle cases like health check.

Refer to the doc of ProxyRootHandler for the more detailed explanations of the args.

func NewCertPool

func NewCertPool(pemCerts ...string) (
	certPool *x509.CertPool,
	failedCerts []string,
	sysCertPoolErr error,
)

NewCertPool creates a new cert pool.

It tries to get the system cert pool first, then append new pemCerts into the pool.

Any new certs failed to append to the pool will be returned via failedCerts.

If for any reason it's unable to get the system cert pool, the error will be returned by sysCertPoolErr and the returned certPool will only have successfully added new certs.

func NoRedirCheckRedirectFunc

func NoRedirCheckRedirectFunc(*http.Request, []*http.Request) error

NoRedirCheckRedirectFunc is a CheckRedirect function implemention can be used in http.Client. It does not follow any redirections.

func ProxyRootHandler

func ProxyRootHandler(
	client *http.Client,
	targetURL, selfURL *url.URL,
	logger *log.Logger,
) func(w http.ResponseWriter, r *http.Request)

ProxyRootHandler generates the http handler function to be used to serve root ("/") in http mux.

client is the http client to use. You can either use DefaultHTTPClient function to get a default implementation, or refer to its code to create your own. You migh also find go.yhsif.com/badcerts package useful when creating your own client.

targetURL is the target URL this mux proxies to. Only its scheme and host will be used.

selfURL is for 3xx redirect rewrite. It could be nil, which means this mux won't rewrite any 3xx responses.

logger is the logger to log errors. It could be nil, which means no errors will be logged.

func RewriteURL

func RewriteURL(
	logger *log.Logger,
	origURL, targetHost string,
	selfURL *url.URL,
) string

RewriteURL rewrites all targetHost URLs to us (selfURL).

Types

This section is empty.