{"id":20806945,"url":"https://github.com/bddjr/hlfhr","last_synced_at":"2025-07-01T18:06:13.146Z","repository":{"id":230484310,"uuid":"779509273","full_name":"bddjr/hlfhr","owner":"bddjr","description":"🌐 Redirecting from HTTP to HTTPS on the same port, similar to nginx's error_page 497. It can also redirect from port 80 to port 443.","archived":false,"fork":false,"pushed_at":"2025-04-06T05:21:41.000Z","size":157,"stargazers_count":14,"open_issues_count":0,"forks_count":6,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-07T05:07:26.274Z","etag":null,"topics":["go","go-mod","go-module","go-package","golang","https","https-server","httpserver","redirect","ssl"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bddjr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2024-03-30T02:27:18.000Z","updated_at":"2025-04-13T05:14:09.000Z","dependencies_parsed_at":"2024-03-30T03:26:17.750Z","dependency_job_id":"e5e46450-127f-4d3d-81d5-7dfe29d5c43e","html_url":"https://github.com/bddjr/hlfhr","commit_stats":null,"previous_names":["bddjr/hlfhr"],"tags_count":43,"template":false,"template_full_name":null,"purl":"pkg:github/bddjr/hlfhr","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bddjr%2Fhlfhr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bddjr%2Fhlfhr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bddjr%2Fhlfhr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bddjr%2Fhlfhr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bddjr","download_url":"https://codeload.github.com/bddjr/hlfhr/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bddjr%2Fhlfhr/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263013712,"owners_count":23399813,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["go","go-mod","go-module","go-package","golang","https","https-server","httpserver","redirect","ssl"],"created_at":"2024-11-17T19:29:01.190Z","updated_at":"2025-07-01T18:06:13.119Z","avatar_url":"https://github.com/bddjr.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HTTPS Listener For HTTP Redirect\n\nRedirecting from HTTP to HTTPS on the ***same port***, similar to [nginx's `error_page 497`](https://github.com/bddjr/hlfhr/discussions/18).  \nIt can also redirect from port 80 to port 443.\n\n\u003e This is my original work - the first solution to [the issue](https://github.com/golang/go/issues/49310) without modifying the standard library.  \n\u003e If you like it, please give me a star⭐. Thanks! 😊  \n\n## Setup\n\n```\ngo get github.com/bddjr/hlfhr\n```\n\n```go\n// Use hlfhr.New\nsrv := hlfhr.New(\u0026http.Server{\n\t// Write something...\n})\n\n// Port 80 redirects to port 443.  \n// This option only takes effect when listening on port 443.\nsrv.Listen80RedirectTo443 = true\n\n// Then just use it like [http.Server]\nerr := srv.ListenAndServeTLS(\"example.crt\", \"example.key\")\n```\n\nFor example:\n- Listening on port 8443, `http://127.0.0.1:8443` will redirect to `https://127.0.0.1:8443`.  \n- Listening on port 443, `http://127.0.0.1` will redirect to `https://127.0.0.1`.  \n\nIf you need to customize the redirect handler, see [HttpOnHttpsPortErrorHandler Example](#httponhttpsporterrorhandler-example).\n\n---\n\n## Logic\n\n```mermaid\nflowchart TD\n\tRead(\"Hijacking net.Conn.Read\")\n\n\tIsLooksLikeHTTP(\"First byte looks like HTTP ?\")\n\n\tCancelHijacking([\"✅ Cancel hijacking...\"])\n\n\tReadRequest(\"🔍 Read request\")\n\n\tIsHandlerExist(\"`\n\tHttpOnHttpsPort\n\tErrorHandler\n\texist ?`\")\n\n\tRedirect{{\"🟡 307 Redirect\"}}\n\n\tHandler{{\"💡 Handler\"}}\n\n\tClose([\"❌ Close.\"])\n\n    Read --\u003e IsLooksLikeHTTP\n    IsLooksLikeHTTP -- \"🔐false\" --\u003e CancelHijacking\n    IsLooksLikeHTTP -- \"📄true\" --\u003e ReadRequest --\u003e IsHandlerExist\n\tIsHandlerExist -- \"✖false\" --\u003e Redirect --\u003e Close\n\tIsHandlerExist -- \"✅true\" --\u003e Handler --\u003e Close\n```\n\n---\n\n## HttpOnHttpsPortErrorHandler Example\n\n\u003e If you need `http.Hijacker` or `http.ResponseController.EnableFullDuplex`, please use [hahosp](https://github.com/bddjr/hahosp).\n\n```go\n// Check Host Header\nsrv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\thostname, port := hlfhr.SplitHostnamePort(r.Host)\n\tswitch hostname {\n\tcase \"localhost\":\n\t\t//\n\tcase \"www.localhost\", \"127.0.0.1\":\n\t\tr.Host = hlfhr.HostnameAppendPort(\"localhost\", port)\n\tdefault:\n\t\tw.WriteHeader(421)\n\t\treturn\n\t}\n\thlfhr.RedirectToHttps(w, r, 307)\n})\n```\n\n```go\n// Script Redirect\nsrv.HttpOnHttpsPortErrorHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n\tw.Header().Set(\"Content-Type\", \"text/html\")\n\tw.WriteHeader(300)\n\tio.WriteString(w, \"\u003cscript\u003elocation.protocol='https:'\u003c/script\u003e\")\n})\n```\n\n---\n\n## Method Example\n\n#### New\n\n```go\nsrv := hlfhr.New(\u0026http.Server{\n\t// Write something...\n})\n```\n\n#### NewServer\n\n```go\nsrv := hlfhr.NewServer(\u0026http.Server{\n\t// Write something...\n})\n```\n\n#### ListenAndServeTLS\n\n```go\n// Just use it like [http.ListenAndServeTLS]\nvar h http.Handler\nerr := hlfhr.ListenAndServeTLS(\":443\", \"localhost.crt\", \"localhost.key\", h)\n```\n\n#### ServeTLS\n\n```go\n// Just use it like [http.ServeTLS]\nvar l net.Listener\nvar h http.Handler\nerr := hlfhr.ServeTLS(l, h, \"localhost.crt\", \"localhost.key\")\n```\n\n#### Redirect\n\n```go\nvar w http.ResponseWriter\nhlfhr.Redirect(w, 307, \"https://example.com/\")\n```\n\n#### RedirectToHttps\n\n```go\nvar w http.ResponseWriter\nvar r *http.Request\nhlfhr.RedirectToHttps(w, r, 307)\n```\n\n#### SplitHostnamePort\n\n```go\nhostname, port := hlfhr.SplitHostnamePort(\"[::1]:5678\")\n// hostname: [::1]\n// port: 5678\n```\n\n#### Hostname\n\n```go\nhostname := hlfhr.Hostname(\"[::1]:5678\")\n// hostname: [::1]\n```\n\n#### Port\n\n```go\nport := hlfhr.Port(\"[::1]:5678\")\n// port: 5678\n```\n\n#### HostnameAppendPort\n\n```go\nHost := hlfhr.HostnameAppendPort(\"[::1]\", \"5678\")\n// Host: [::1]:5678\n```\n\n#### ReplaceHostname\n\n```go\nHost := hlfhr.ReplaceHostname(\"[::1]:5678\", \"localhost\")\n// Host: localhost:5678\n```\n\n#### ReplacePort\n\n```go\nHost := hlfhr.ReplacePort(\"[::1]:5678\", \"7890\")\n// Host: [::1]:7890\n```\n\n#### Ipv6CutPrefixSuffix\n\n```go\nv6 := hlfhr.Ipv6CutPrefixSuffix(\"[::1]\")\n// v6: ::1\n```\n\n#### IsHttpServerShuttingDown\n\n```go\nvar srv *http.Server\nisShuttingDown := hlfhr.IsHttpServerShuttingDown(srv)\n```\n\n#### Server.IsShuttingDown\n\n```go\nvar srv *hlfhr.Server\nisShuttingDown := srv.IsShuttingDown()\n```\n\n#### NewResponse\n\n```go\nvar c net.Conn\nvar h http.Handler\nvar r *http.Request\n\nw := NewResponse(c, true)\n\nh.ServeHTTP(w, r)\nerr := w.FlushError()\nc.Close()\n```\n\n#### ConnFirstByteLooksLikeHttp\n\n```go\nb := []byte(\"GET / HTTP/1.1\\r\\nHost: localhost\\r\\n\\r\\n\")\nlooksLikeHttp := hlfhr.ConnFirstByteLooksLikeHttp(b[0])\n```\n\n#### NewBufioReaderWithBytes\n\n```go\nvar c net.Conn\nvar b []byte\nn, err := c.Read(b)\nbr := hlfhr.NewBufioReaderWithBytes(b, n, c)\n```\n\n#### BufioSetReader\n\n```go\nvar r io.Reader\nlr := \u0026io.LimitedReader{R: r, N: 4096}\n// Read header\nbr := bufio.NewReader(lr)\n// Read body\nhlfhr.BufioSetReader(br, r)\n```\n\n---\n\n## Test\n\n```\ngit clone https://github.com/bddjr/hlfhr\ncd hlfhr\nchmod +x run.sh\n./run.sh\n```\n\nThen run the test command printed in the terminal to verify the response content is `Hello hlfhr!`.  \n\nThen access it via browser and use developer tools to confirm the protocol is `h2`.  \n\n---\n\n## Reference\n\nhttps://github.com/golang/go/issues/49310  \nhttps://github.com/golang/go\n\nhttps://tls12.xargs.org/#client-hello  \nhttps://tls13.xargs.org/#client-hello\n\nhttps://developer.mozilla.org/docs/Web/HTTP\n\nhttps://nginx.org/en/docs/http/ngx_http_ssl_module.html#errors\n\n---\n\n## License\n\n[BSD-3-clause license](LICENSE.txt)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbddjr%2Fhlfhr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbddjr%2Fhlfhr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbddjr%2Fhlfhr/lists"}