Commit 3824fc8c authored by Kamil Trzciński's avatar Kamil Trzciński

Move most of configuration to appConfig

parent ab00ebdb
......@@ -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()
}
package main
type appConfig struct {
Domain string
RootDir string
RootCertificate []byte
RootKey []byte
ListenHTTP uintptr
ListenHTTPS uintptr
listenProxy uintptr
HTTP2 bool
ServeHTTP bool
}
......@@ -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()
}
......@@ -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)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment