hlfhr

package module
v1.3.8 Latest Latest
Warning

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

Go to latest
Published: Jan 5, 2025 License: BSD-3-Clause Imports: 14 Imported by: 3

README

HTTPS Listener For HTTP Redirect

If client sent an HTTP request to an HTTPS server port, returns 302 redirection, like nginx's "error_page 497".

Setup

go get github.com/bddjr/hlfhr
// Use hlfhr.New
srv := hlfhr.New(&http.Server{
	// Write something...
})
// Then just use it like [http.Server]

err := srv.ListenAndServeTLS("localhost.crt", "localhost.key")

Logic

flowchart TD
	Read("Hijacking net.Conn.Read")

	IsLooksLikeHTTP("First byte looks like HTTP ?")

	CancelHijacking(["✅ Cancel hijacking..."])

	ReadRequest("🔍 Read request")

	IsHandlerExist("`
	HttpOnHttpsPort
	ErrorHandler
	exist ?`")

	302Redirect{{"🟡 302 Redirect"}}

	Handler{{"💡 Handler"}}

	Close(["❌ Close."])

    Read --> IsLooksLikeHTTP
    IsLooksLikeHTTP -- "🔐false" --> CancelHijacking
    IsLooksLikeHTTP -- "📄true" --> ReadRequest --> IsHandlerExist
	IsHandlerExist -- "✖false" --> 302Redirect --> Close
	IsHandlerExist -- "✅true" --> Handler --> Close

HttpOnHttpsPortErrorHandler Example

If you need http.Hijacker or http.ResponseController.EnableFullDuplex, please use hahosp.

// 307 Temporary Redirect
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	hlfhr.RedirectToHttps(w, r, 307)
})
// Check Host Header
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	hostname, port := hlfhr.SplitHostnamePort(r.Host)
	switch hostname {
	case "localhost":
		//
	case "www.localhost", "127.0.0.1":
		r.Host = hlfhr.HostnameAppendPort("localhost", port)
	default:
		w.WriteHeader(421)
		return
	}
	hlfhr.RedirectToHttps(w, r, 302)
})
// Script Redirect
srv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
	w.Header().Set("Content-Type", "text/html")
	w.WriteHeader(300)
	io.WriteString(w, "<script>location.protocol='https:'</script>")
})

Method Example

New
srv := hlfhr.New(&http.Server{
	// Write something...
})
NewServer
srv := hlfhr.NewServer(&http.Server{
	// Write something...
})
ListenAndServeTLS
// Just use it like [http.ListenAndServeTLS]
var h http.Handler
err := hlfhr.ListenAndServeTLS(":443", "localhost.crt", "localhost.key", h)
ServeTLS
// Just use it like [http.ServeTLS]
var l net.Listener
var h http.Handler
err := hlfhr.ServeTLS(l, h, "localhost.crt", "localhost.key")
Redirect
var w http.ResponseWriter
hlfhr.Redirect(w, 302, "https://example.com/")
RedirectToHttps
var w http.ResponseWriter
var r *http.Request
hlfhr.RedirectToHttps(w, r, 302)
SplitHostnamePort
hostname, port := hlfhr.SplitHostnamePort("[::1]:5678")
// hostname: [::1]
// port: 5678
Hostname
hostname := hlfhr.Hostname("[::1]:5678")
// hostname: [::1]
Port
port := hlfhr.Port("[::1]:5678")
// port: 5678
HostnameAppendPort
Host := hlfhr.HostnameAppendPort("[::1]", "5678")
// Host: [::1]:5678
ReplaceHostname
Host := hlfhr.ReplaceHostname("[::1]:5678", "localhost")
// Host: localhost:5678
ReplacePort
Host := hlfhr.ReplacePort("[::1]:5678", "7890")
// Host: [::1]:7890
Ipv6CutPrefixSuffix
v6 := hlfhr.Ipv6CutPrefixSuffix("[::1]")
// v6: ::1
IsHttpServerShuttingDown
var srv *http.Server
isShuttingDown := hlfhr.IsHttpServerShuttingDown(srv)
Server.IsShuttingDown
var srv *hlfhr.Server
isShuttingDown := srv.IsShuttingDown()
NewResponse
var c net.Conn
var h http.Handler
var r *http.Request

w := NewResponse(c, true)

h.ServeHTTP(w, r)
err := w.FlushError()
c.Close()
ConnFirstByteLooksLikeHttp
b := []byte("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n")
looksLikeHttp := hlfhr.ConnFirstByteLooksLikeHttp(b[0])
NewBufioReaderWithBytes
var c net.Conn
var b []byte
n, err := c.Read(b)
br := hlfhr.NewBufioReaderWithBytes(b, n, c)
BufioSetReader
var r io.Reader
lr := &io.LimitedReader{R: r, N: 4096}
// Read header
br := bufio.NewReader(lr)
// Read body
hlfhr.BufioSetReader(br, r)

Test

git clone https://github.com/bddjr/hlfhr
cd hlfhr
chmod +x run.sh
./run.sh

Reference

https://github.com/golang/go/issues/49310
https://github.com/golang/go

https://tls12.xargs.org/#client-hello
https://tls13.xargs.org/#client-hello

https://developer.mozilla.org/docs/Web/HTTP

https://nginx.org/en/docs/http/ngx_http_ssl_module.html#errors


License

BSD-3-clause license

Documentation

Overview

HTTPS Listener For HTTP Redirect

https://github.com/bddjr/hlfhr

Index

Constants

This section is empty.

Variables

View Source
var ErrHttpOnHttpsPort = errors.New("client sent an HTTP request to an HTTPS server")

Functions

func BufioSetReader added in v1.3.3

func BufioSetReader(br *bufio.Reader, rd io.Reader)

func Hostname added in v0.2.0

func Hostname(Host string) (hostname string)

"[::1]:5678" => "[::1]"

func HostnameAppendPort added in v0.2.0

func HostnameAppendPort(hostname string, port string) string

"[::1]", "5678" => "[::1]:5678"

"[::1]", ":5678" => "[::1]:5678"

"[::1]", "" => "[::1]"

"[::1]", ":" => "[::1]"

"::1" , "5678" => "[::1]:5678"

"::1" , ":5678" => "[::1]:5678"

"::1" , "" => "[::1]"

"::1" , ":" => "[::1]"

func Ipv6CutPrefixSuffix added in v0.2.0

func Ipv6CutPrefixSuffix(v6 string) string

"[::1]" => "::1"

func IsHttpServerShuttingDown added in v1.1.0

func IsHttpServerShuttingDown(srv *http.Server) bool

func ListenAndServeTLS

func ListenAndServeTLS(addr, certFile, keyFile string, handler http.Handler) error

ListenAndServeTLS acts identically to http.ListenAndServe, except that it expects HTTPS connections. Additionally, files containing a certificate and matching private key for the server must be provided. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate, any intermediates, and the CA's certificate.

func NewBufioReaderWithBytes added in v1.1.0

func NewBufioReaderWithBytes(buf []byte, contentLength int, rd io.Reader) *bufio.Reader

func Port added in v0.2.0

func Port(Host string) (port string)

"[::1]:5678" => "5678"

func Redirect added in v0.2.0

func Redirect(w http.ResponseWriter, code int, url string)

Redirect without HTTP body.

func RedirectToHttps added in v0.2.0

func RedirectToHttps(w http.ResponseWriter, r *http.Request, code int)

Redirect without HTTP body.

func ReplaceHostname added in v0.2.0

func ReplaceHostname(Host string, name string) string

"[::1]:5678", "localhost" => "localhost:5678"

func ReplacePort added in v0.2.0

func ReplacePort(Host string, port string) string

"[::1]:5678", "7890" => "localhost:7890"

func ServeTLS

func ServeTLS(l net.Listener, handler http.Handler, certFile, keyFile string) error

ServeTLS accepts incoming HTTPS connections on the listener l, creating a new service goroutine for each. The service goroutines read requests and then call handler to reply to them.

The handler is typically nil, in which case http.DefaultServeMux is used.

Additionally, files containing a certificate and matching private key for the server must be provided. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate, any intermediates, and the CA's certificate.

ServeTLS always returns a non-nil error.

func SplitHostnamePort added in v0.2.0

func SplitHostnamePort(Host string) (hostname string, port string)

"[::1]:5678" => "[::1]", "5678"

Types

type Response added in v0.1.0

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

Using for interface http.ResponseWriter, io.StringWriter, io.ByteWriter.

func NewResponse added in v0.1.0

func NewResponse(c net.Conn, ConnectionHeaderSetClose bool) *Response

func (*Response) Flush added in v1.2.3

func (r *Response) Flush()

Flush flushes buffered data to the client.

func (*Response) FlushError added in v1.3.4

func (r *Response) FlushError() error

func (*Response) Header added in v1.2.3

func (r *Response) Header() http.Header

func (*Response) SetDeadline added in v1.3.4

func (r *Response) SetDeadline(t time.Time) error

func (*Response) SetReadDeadline added in v1.3.4

func (r *Response) SetReadDeadline(t time.Time) error

func (*Response) SetWriteDeadline added in v1.3.4

func (r *Response) SetWriteDeadline(t time.Time) error

func (*Response) Write added in v0.1.0

func (r *Response) Write(b []byte) (int, error)

func (*Response) WriteByte added in v1.2.5

func (r *Response) WriteByte(c byte) error

func (*Response) WriteHeader added in v1.2.3

func (r *Response) WriteHeader(statusCode int)

Set status code and lock header, if header does not locked.

func (*Response) WriteString added in v1.2.3

func (r *Response) WriteString(s string) (int, error)

type Server

type Server struct {
	*http.Server

	// HttpOnHttpsPortErrorHandler handles HTTP requests sent to an HTTPS port.
	// See https://github.com/bddjr/hlfhr#httponhttpsporterrorhandler-example
	HttpOnHttpsPortErrorHandler http.Handler
}

func New

func New(s *http.Server) *Server

New hlfhr Server

func NewServer

func NewServer(s *http.Server) *Server

New hlfhr Server

func (*Server) IsShuttingDown added in v0.2.0

func (s *Server) IsShuttingDown() bool

func (*Server) ListenAndServeTLS

func (s *Server) ListenAndServeTLS(certFile string, keyFile string) error

ListenAndServeTLS listens on the TCP network address srv.Addr and then calls ServeTLS to handle requests on incoming TLS connections. Accepted connections are configured to enable TCP keep-alives.

Filenames containing a certificate and matching private key for the server must be provided if neither the Server's TLSConfig.Certificates nor TLSConfig.GetCertificate are populated. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate, any intermediates, and the CA's certificate.

If srv.Addr is blank, ":https" is used.

ListenAndServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the returned error is http.ErrServerClosed.

func (*Server) ServeTLS

func (s *Server) ServeTLS(l net.Listener, certFile string, keyFile string) error

ServeTLS accepts incoming connections on the Listener l, creating a new service goroutine for each. The service goroutines perform TLS setup and then read requests, calling srv.Handler to reply to them.

Files containing a certificate and matching private key for the server must be provided if neither the Server's TLSConfig.Certificates nor TLSConfig.GetCertificate are populated. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate, any intermediates, and the CA's certificate.

ServeTLS always returns a non-nil error. After [Server.Shutdown] or [Server.Close], the returned error is http.ErrServerClosed.

type TLSListener added in v1.3.0

type TLSListener struct {
	net.Listener
	TLSConf *tls.Config
	Server  *Server
}

func (*TLSListener) Accept added in v1.3.0

func (l *TLSListener) Accept() (net.Conn, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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