[mirror] Scalable static site server for Git forges (like GitHub Pages)
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

at latest 90 lines 2.8 kB view raw
1package git_pages 2 3import ( 4 "context" 5 "crypto/tls" 6 "fmt" 7 "net" 8 "net/http" 9 "strings" 10) 11 12func ServeCaddy(w http.ResponseWriter, r *http.Request) { 13 domain := r.URL.Query().Get("domain") 14 if domain == "" { 15 http.Error(w, "domain parameter required", http.StatusBadRequest) 16 return 17 } 18 19 // Save the backend some effort from queries that are essentially guaranteed to fail. 20 // While TLS certificates may be provisionsed for IP addresses under special circumstances[^1], 21 // this isn't really what git-pages is designed for, and object store accesses can cost money. 22 // [^1]: https://letsencrypt.org/2025/07/01/issuing-our-first-ip-address-certificate 23 if ip := net.ParseIP(domain); ip != nil { 24 logc.Println(r.Context(), "caddy:", domain, 404, "(bare IP)") 25 w.WriteHeader(http.StatusNotFound) 26 return 27 } 28 29 var err error 30 domain = strings.ToLower(domain) 31 32 // Run a cheap check as to whether we might be serving the domain. 33 var found = domainCache.CheckDomain(r.Context(), domain) 34 35 if !found { 36 // Run an expensive check as to whether we are actually serving the domain. 37 found, err = backend.CheckDomain(r.Context(), domain) 38 } 39 40 if !found { 41 // If we don't serve the domain, but a fallback server does, then we should let our 42 // Caddy instance request a TLS certificate. Otherwise, we'll never have an opportunity 43 // to proxy the request further. (This functionality was originally added for Codeberg 44 // Pages v2, which would under some circumstances return certificates with subjectAltName 45 // not valid for the SNI. Go's TLS stack makes `tls.Dial` return an error for these, 46 // thankfully making it unnecessary to examine X.509 certificates manually here.) 47 found, err = tryDialWithSNI(r.Context(), domain) 48 if err != nil { 49 logc.Printf(r.Context(), "caddy err: check SNI: %s\n", err) 50 } 51 } 52 53 if found { 54 logc.Println(r.Context(), "caddy:", domain, 200) 55 w.WriteHeader(http.StatusOK) 56 } else if err == nil { 57 logc.Println(r.Context(), "caddy:", domain, 404) 58 w.WriteHeader(http.StatusNotFound) 59 } else { 60 logc.Println(r.Context(), "caddy:", domain, 500) 61 w.WriteHeader(http.StatusInternalServerError) 62 fmt.Fprintln(w, err) 63 } 64} 65 66func tryDialWithSNI(ctx context.Context, domain string) (bool, error) { 67 if config.Fallback.ProxyTo == nil { 68 return false, nil 69 } 70 71 fallbackURL := config.Fallback.ProxyTo 72 if fallbackURL.Scheme != "https" { 73 return false, nil 74 } 75 76 connectHost := fallbackURL.Host 77 if fallbackURL.Port() != "" { 78 connectHost += ":" + fallbackURL.Port() 79 } else { 80 connectHost += ":443" 81 } 82 83 logc.Printf(ctx, "caddy: check TLS %s", fallbackURL) 84 connection, err := tls.Dial("tcp", connectHost, &tls.Config{ServerName: domain}) 85 if err != nil { 86 return false, err 87 } 88 connection.Close() 89 return true, nil 90}