server.go 1.8 KB
Newer Older
1 2 3 4
package main

import (
	"crypto/tls"
Kamil Trzciński's avatar
Kamil Trzciński committed
5 6
	"fmt"
	"net"
7
	"net/http"
8
	"os"
Kamil Trzciński's avatar
Kamil Trzciński committed
9
	"time"
Nick Thomas's avatar
Nick Thomas committed
10

11
	"github.com/gorilla/context"
Nick Thomas's avatar
Nick Thomas committed
12
	"golang.org/x/net/http2"
13 14

	"gitlab.com/gitlab-org/gitlab-pages/internal/netutil"
15 16
)

17
type tlsHandlerFunc func(*tls.ClientHelloInfo) (*tls.Certificate, error)
18

19 20 21 22 23 24 25
type keepAliveListener struct {
	net.Listener
}

type keepAliveSetter interface {
	SetKeepAlive(bool) error
	SetKeepAlivePeriod(time.Duration) error
26
}
27

28 29
func (ln *keepAliveListener) Accept() (net.Conn, error) {
	conn, err := ln.Listener.Accept()
30
	if err != nil {
31
		return nil, err
32
	}
33 34 35 36 37 38

	kc := conn.(keepAliveSetter)
	kc.SetKeepAlive(true)
	kc.SetKeepAlivePeriod(3 * time.Minute)

	return conn, nil
39 40
}

41
func listenAndServe(fd uintptr, handler http.HandlerFunc, useHTTP2 bool, tlsConfig *tls.Config, limiter *netutil.Limiter) error {
42
	// create server
43
	server := &http.Server{Handler: context.ClearHandler(handler), TLSConfig: tlsConfig}
44

45
	if useHTTP2 {
46 47 48 49 50 51
		err := http2.ConfigureServer(server, &http2.Server{})
		if err != nil {
			return err
		}
	}

52 53 54 55 56
	l, err := net.FileListener(os.NewFile(fd, "[socket]"))
	if err != nil {
		return fmt.Errorf("failed to listen on FD %d: %v", fd, err)
	}

57 58 59 60
	if limiter != nil {
		l = netutil.SharedLimitListener(l, limiter)
	}

61
	if tlsConfig != nil {
62
		tlsListener := tls.NewListener(&keepAliveListener{l}, server.TLSConfig)
63 64
		return server.Serve(tlsListener)
	}
65
	return server.Serve(&keepAliveListener{l})
66 67
}

68
func listenAndServeTLS(fd uintptr, cert, key []byte, handler http.HandlerFunc, tlsHandler tlsHandlerFunc, useHTTP2 bool, limiter *netutil.Limiter) error {
69 70 71 72 73 74 75 76 77 78
	certificate, err := tls.X509KeyPair(cert, key)
	if err != nil {
		return err
	}

	tlsConfig := &tls.Config{}
	tlsConfig.GetCertificate = tlsHandler
	tlsConfig.Certificates = []tls.Certificate{
		certificate,
	}
79
	return listenAndServe(fd, handler, useHTTP2, tlsConfig, limiter)
80
}