Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-pages.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app.go46
-rw-r--r--app_config.go16
-rw-r--r--main.go99
-rw-r--r--server.go59
4 files changed, 161 insertions, 59 deletions
diff --git a/app.go b/app.go
index 08e82042..a3fc8335 100644
--- a/app.go
+++ b/app.go
@@ -2,15 +2,18 @@ package main
import (
"crypto/tls"
+ "log"
"net/http"
"strings"
"sync"
+ "time"
)
const xForwardedProto = "X-Forwarded-Proto"
const xForwardedProtoHTTPS = "https"
type theApp struct {
+ appConfig
domains domains
lock sync.RWMutex
}
@@ -78,3 +81,46 @@ func (a *theApp) UpdateDomains(domains domains) {
defer a.lock.Unlock()
a.domains = domains
}
+
+func (a *theApp) Run() {
+ var wg sync.WaitGroup
+
+ if a.ListenHTTP != 0 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ err := listenAndServe(a.ListenHTTP, a.ServeHTTP, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }()
+ }
+
+ // Listen for HTTPS
+ if a.ListenHTTPS != 0 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ err := listenAndServeTLS(a.ListenHTTPS, a.RootCertificate, a.RootKey, a.ServeHTTP, a.ServeTLS)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }()
+ }
+
+ // Listen for HTTP proxy requests
+ if a.listenProxy != 0 {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ err := listenAndServe(a.listenProxy, a.ServeProxy, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }()
+ }
+
+ go watchDomains(a.UpdateDomains, time.Second)
+
+ wg.Wait()
+}
diff --git a/app_config.go b/app_config.go
new file mode 100644
index 00000000..d007ca39
--- /dev/null
+++ b/app_config.go
@@ -0,0 +1,16 @@
+package main
+
+type appConfig struct {
+ Domain string
+ RootDir string
+
+ RootCertificate []byte
+ RootKey []byte
+
+ ListenHTTP uintptr
+ ListenHTTPS uintptr
+ listenProxy uintptr
+
+ HTTP2 bool
+ ServeHTTP bool
+}
diff --git a/main.go b/main.go
index 30cbb5de..5799f380 100644
--- a/main.go
+++ b/main.go
@@ -5,8 +5,8 @@ import (
"fmt"
"log"
"path/filepath"
- "sync"
- "time"
+ "io/ioutil"
+ "net"
)
// VERSION stores the information about the semantic version of application
@@ -15,70 +15,81 @@ var VERSION = "dev"
// REVISION stores the information about the git revision of application
var REVISION = "HEAD"
-var listenHTTP = flag.String("listen-http", ":80", "The address to listen for HTTP requests")
-var listenHTTPS = flag.String("listen-https", "", "The address to listen for HTTPS requests")
-var listenProxy = flag.String("listen-proxy", "", "The address to listen for proxy requests")
var pagesDomain = flag.String("pages-domain", "gitlab-example.com", "The domain to serve static pages")
-var pagesRootCert = flag.String("root-cert", "", "The default path to file certificate to serve static pages")
-var pagesRootKey = flag.String("root-key", "", "The default path to file certificate to serve static pages")
var serverHTTP = flag.Bool("serve-http", true, "Serve the pages under HTTP")
var http2proto = flag.Bool("http2", true, "Enable HTTP2 support")
var pagesRoot = flag.String("pages-root", "shared/pages", "The directory where pages are stored")
-func resolve() {
- fullPath, err := filepath.EvalSymlinks(*pagesRoot)
+func evalSymlinks(directory string) (result string) {
+ result, err := filepath.EvalSymlinks(directory)
if err != nil {
log.Fatalln(err)
}
- *pagesRoot = fullPath
+ return
+}
+
+func readFile(file string) (result []byte) {
+ result, err := ioutil.ReadFile(file)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ return
+}
+
+func createSocket(addr string) (l net.Listener, fd uintptr) {
+ l, err := net.Listen("tcp", addr)
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ f, err := l.(*net.TCPListener).File()
+ if err != nil {
+ log.Fatalln(err)
+ }
+
+ fd = f.Fd()
+ return
}
func main() {
- var wg sync.WaitGroup
- var app theApp
+ var listenHTTP = flag.String("listen-http", ":80", "The address to listen for HTTP requests")
+ var listenHTTPS = flag.String("listen-https", "", "The address to listen for HTTPS requests")
+ var listenProxy = flag.String("listen-proxy", "", "The address to listen for proxy requests")
+ var pagesRootCert = flag.String("root-cert", "", "The default path to file certificate to serve static pages")
+ var pagesRootKey = flag.String("root-key", "", "The default path to file certificate to serve static pages")
fmt.Printf("GitLab Pages Daemon %s (%s)", VERSION, REVISION)
fmt.Printf("URL: https://gitlab.com/gitlab-org/gitlab-pages")
flag.Parse()
- resolve()
- // Listen for HTTP
+ var app theApp
+
+ app.Domain = *pagesDomain
+ app.RootDir = evalSymlinks(*pagesRoot)
+
+ if *pagesRootCert != "" {
+ app.RootCertificate = readFile(*pagesRootCert)
+ }
+
+ if *pagesRootKey != "" {
+ app.RootKey = readFile(*pagesRootKey)
+ }
+
if *listenHTTP != "" {
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := listenAndServe(*listenHTTP, app.ServeHTTP)
- if err != nil {
- log.Fatal(err)
- }
- }()
+ var l net.Listener
+ l, app.ListenHTTP = createSocket(*listenHTTP)
+ defer l.Close()
}
- // Listen for HTTPS
if *listenHTTPS != "" {
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := listenAndServeTLS(*listenHTTPS, *pagesRootCert, *pagesRootKey, app.ServeHTTP, app.ServeTLS)
- if err != nil {
- log.Fatal(err)
- }
- }()
+ var l net.Listener
+ l, app.ListenHTTPS = createSocket(*listenHTTPS)
+ defer l.Close()
}
- // Listen for HTTP proxy requests
if *listenProxy != "" {
- wg.Add(1)
- go func() {
- defer wg.Done()
- err := listenAndServe(*listenProxy, app.ServeProxy)
- if err != nil {
- log.Fatal(err)
- }
- }()
+ var l net.Listener
+ l, app.ListenHTTPS = createSocket(*listenProxy)
+ defer l.Close()
}
-
- go watchDomains(app.UpdateDomains, time.Second)
-
- wg.Wait()
}
diff --git a/server.go b/server.go
index e46bb686..f3408f25 100644
--- a/server.go
+++ b/server.go
@@ -4,29 +4,31 @@ import (
"crypto/tls"
"golang.org/x/net/http2"
"net/http"
+"net"
+ "time"
+ "os"
+ "fmt"
)
type tlsHandlerFunc func(*tls.ClientHelloInfo) (*tls.Certificate, error)
-func listenAndServe(addr string, handler http.HandlerFunc) error {
- // create server
- server := &http.Server{Addr: addr, Handler: handler}
+type tcpKeepAliveListener struct {
+ *net.TCPListener
+}
- if *http2proto {
- err := http2.ConfigureServer(server, &http2.Server{})
- if err != nil {
- return err
- }
+func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
+ tc, err := ln.AcceptTCP()
+ if err != nil {
+ return
}
-
- return server.ListenAndServe()
+ tc.SetKeepAlive(true)
+ tc.SetKeepAlivePeriod(3 * time.Minute)
+ return tc, nil
}
-func listenAndServeTLS(addr string, certFile, keyFile string, handler http.HandlerFunc, tlsHandler tlsHandlerFunc) error {
+func listenAndServe(fd uintptr, handler http.HandlerFunc, tlsConfig *tls.Config) error {
// create server
- server := &http.Server{Addr: addr, Handler: handler}
- server.TLSConfig = &tls.Config{}
- server.TLSConfig.GetCertificate = tlsHandler
+ server := &http.Server{Handler: handler, TLSConfig: tlsConfig}
if *http2proto {
err := http2.ConfigureServer(server, &http2.Server{})
@@ -35,5 +37,32 @@ func listenAndServeTLS(addr string, certFile, keyFile string, handler http.Handl
}
}
- return server.ListenAndServeTLS(certFile, keyFile)
+ l, err := net.FileListener(os.NewFile(fd, "[socket]"))
+ if err != nil {
+ return fmt.Errorf("failed to listen on FD %d: %v", fd, err)
+ }
+
+ if tlsConfig != nil {
+ tlsListener := tls.NewListener(tcpKeepAliveListener{l.(*net.TCPListener)}, server.TLSConfig)
+ return server.Serve(tlsListener)
+ } else {
+ return server.Serve(&tcpKeepAliveListener{l.(*net.TCPListener)})
+ }
+}
+
+func listenAndServeTLS(fd uintptr, cert, key []byte, handler http.HandlerFunc, tlsHandler tlsHandlerFunc) error {
+ certificate, err := tls.X509KeyPair(cert, key)
+ if err != nil {
+ return err
+ }
+
+ tlsConfig := &tls.Config{}
+ tlsConfig.GetCertificate = tlsHandler
+ tlsConfig.NextProtos = []string {
+ "http/1.1",
+ }
+ tlsConfig.Certificates = []tls.Certificate{
+ certificate,
+ }
+ return listenAndServe(fd, handler, tlsConfig)
}