github.com/alejandroEsc/spdy@v0.0.0-20200317064415-01a02f0eb389/server.go (about)

     1  // Copyright 2013 Jamie Hall. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package spdy
     6  
     7  import (
     8  	"crypto/tls"
     9  	"errors"
    10  	"net"
    11  	"net/http"
    12  	"time"
    13  
    14  	"github.com/SlyMarbo/spdy/common"
    15  	"github.com/SlyMarbo/spdy/spdy2"
    16  	"github.com/SlyMarbo/spdy/spdy3"
    17  )
    18  
    19  // NewServerConn is used to create a SPDY connection, using the given
    20  // net.Conn for the underlying connection, and the given http.Server to
    21  // configure the request serving.
    22  func NewServerConn(conn net.Conn, server *http.Server, version, subversion int) (common.Conn, error) {
    23  	if conn == nil {
    24  		return nil, errors.New("Error: Connection initialised with nil net.conn.")
    25  	}
    26  	if server == nil {
    27  		return nil, errors.New("Error: Connection initialised with nil server.")
    28  	}
    29  
    30  	switch version {
    31  	case 3:
    32  		return spdy3.NewConn(conn, server, subversion), nil
    33  
    34  	case 2:
    35  		return spdy2.NewConn(conn, server), nil
    36  
    37  	default:
    38  		return nil, errors.New("Error: Unsupported SPDY version.")
    39  	}
    40  }
    41  
    42  // ListenAndServeTLS listens on the TCP network address addr
    43  // and then calls Serve with handler to handle requests on
    44  // incoming connections.  Handler is typically nil, in which
    45  // case the DefaultServeMux is used. Additionally, files
    46  // containing a certificate and matching private key for the
    47  // server must be provided. If the certificate is signed by
    48  // a certificate authority, the certFile should be the
    49  // concatenation of the server's certificate followed by the
    50  // CA's certificate.
    51  //
    52  // See examples/server/server.go for a simple example server.
    53  func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error {
    54  	npnStrings := npn()
    55  	server := &http.Server{
    56  		Addr:    addr,
    57  		Handler: handler,
    58  		TLSConfig: &tls.Config{
    59  			NextProtos: npnStrings,
    60  		},
    61  		TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
    62  	}
    63  
    64  	for _, str := range npnStrings {
    65  		switch str {
    66  		case "spdy/2":
    67  			server.TLSNextProto[str] = spdy2.NextProto
    68  		case "spdy/3":
    69  			server.TLSNextProto[str] = spdy3.NextProto
    70  		case "spdy/3.1":
    71  			server.TLSNextProto[str] = spdy3.NextProto1
    72  		}
    73  	}
    74  
    75  	return server.ListenAndServeTLS(certFile, keyFile)
    76  }
    77  
    78  // ListenAndServeSpdyOnly listens on the TCP network address addr
    79  // and then calls Serve with handler to handle requests on
    80  // incoming connections.  Handler is typically nil, in which
    81  // case the DefaultServeMux is used. Additionally, files
    82  // containing a certificate and matching private key for the
    83  // server must be provided. If the certificate is signed by
    84  // a certificate authority, the certFile should be the
    85  // concatenation of the server's certificate followed by the
    86  // CA's certificate.
    87  //
    88  // IMPORTANT NOTE: Unlike spdy.ListenAndServeTLS, this function
    89  // will ONLY serve SPDY. HTTPS requests are refused.
    90  //
    91  // See examples/spdy_only_server/server.go for a simple example server.
    92  func ListenAndServeSpdyOnly(addr string, certFile string, keyFile string, handler http.Handler) error {
    93  	npnStrings := npn()
    94  	if addr == "" {
    95  		addr = ":https"
    96  	}
    97  	if handler == nil {
    98  		handler = http.DefaultServeMux
    99  	}
   100  	server := &http.Server{
   101  		Addr:    addr,
   102  		Handler: handler,
   103  		TLSConfig: &tls.Config{
   104  			NextProtos:   npnStrings,
   105  			Certificates: make([]tls.Certificate, 1),
   106  		},
   107  		TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
   108  	}
   109  
   110  	for _, str := range npnStrings {
   111  		switch str {
   112  		case "spdy/2":
   113  			server.TLSNextProto[str] = spdy2.NextProto
   114  		case "spdy/3":
   115  			server.TLSNextProto[str] = spdy3.NextProto
   116  		case "spdy/3.1":
   117  			server.TLSNextProto[str] = spdy3.NextProto1
   118  		}
   119  	}
   120  
   121  	var err error
   122  
   123  	if certFile != "" || keyFile != "" {
   124  		var err error
   125  		server.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
   126  		if err != nil {
   127  			return err
   128  		}
   129  	}
   130  
   131  	conn, err := net.Listen("tcp", addr)
   132  	if err != nil {
   133  		return err
   134  	}
   135  
   136  	tlsListener := tls.NewListener(conn, server.TLSConfig)
   137  	defer tlsListener.Close()
   138  
   139  	// Main loop
   140  	var tempDelay time.Duration
   141  	for {
   142  		rw, e := tlsListener.Accept()
   143  		if e != nil {
   144  			if ne, ok := e.(net.Error); ok && ne.Temporary() {
   145  				if tempDelay == 0 {
   146  					tempDelay = 5 * time.Millisecond
   147  				} else {
   148  					tempDelay *= 2
   149  				}
   150  				if max := 1 * time.Second; tempDelay > max {
   151  					tempDelay = max
   152  				}
   153  				log.Printf("Accept error: %v; retrying in %v", e, tempDelay)
   154  				time.Sleep(tempDelay)
   155  				continue
   156  			}
   157  			return e
   158  		}
   159  		tempDelay = 0
   160  		go serveSPDY(rw, server)
   161  	}
   162  }
   163  
   164  // ListenAndServeSPDYNoNPN creates a server that listens exclusively
   165  // for SPDY and (unlike the rest of the package) will not support
   166  // HTTPS.
   167  func ListenAndServeSPDYNoNPN(addr string, certFile string, keyFile string, handler http.Handler, version, subversion int) error {
   168  	if addr == "" {
   169  		addr = ":https"
   170  	}
   171  	if handler == nil {
   172  		handler = http.DefaultServeMux
   173  	}
   174  	server := &http.Server{
   175  		Addr:    addr,
   176  		Handler: handler,
   177  		TLSConfig: &tls.Config{
   178  			Certificates: make([]tls.Certificate, 1),
   179  		},
   180  	}
   181  
   182  	var err error
   183  	server.TLSConfig.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
   184  	if err != nil {
   185  		return err
   186  	}
   187  
   188  	conn, err := net.Listen("tcp", addr)
   189  	if err != nil {
   190  		return err
   191  	}
   192  
   193  	tlsListener := tls.NewListener(conn, server.TLSConfig)
   194  	defer tlsListener.Close()
   195  
   196  	// Main loop
   197  	var tempDelay time.Duration
   198  	for {
   199  		rw, e := tlsListener.Accept()
   200  		if e != nil {
   201  			if ne, ok := e.(net.Error); ok && ne.Temporary() {
   202  				if tempDelay == 0 {
   203  					tempDelay = 5 * time.Millisecond
   204  				} else {
   205  					tempDelay *= 2
   206  				}
   207  				if max := 1 * time.Second; tempDelay > max {
   208  					tempDelay = max
   209  				}
   210  				log.Printf("Accept error: %v; retrying in %v", e, tempDelay)
   211  				time.Sleep(tempDelay)
   212  				continue
   213  			}
   214  			return e
   215  		}
   216  		tempDelay = 0
   217  		go serveSPDYNoNPN(rw, server, version, subversion)
   218  	}
   219  }
   220  
   221  func serveSPDY(conn net.Conn, srv *http.Server) {
   222  	defer common.Recover()
   223  
   224  	tlsConn, ok := conn.(*tls.Conn)
   225  	if !ok { // Only allow TLS connections.
   226  		return
   227  	}
   228  
   229  	if d := srv.ReadTimeout; d != 0 {
   230  		conn.SetReadDeadline(time.Now().Add(d))
   231  	}
   232  	if d := srv.WriteTimeout; d != 0 {
   233  		conn.SetWriteDeadline(time.Now().Add(d))
   234  	}
   235  	if err := tlsConn.Handshake(); err != nil {
   236  		return
   237  	}
   238  
   239  	tlsState := new(tls.ConnectionState)
   240  	*tlsState = tlsConn.ConnectionState()
   241  	proto := tlsState.NegotiatedProtocol
   242  	if fn := srv.TLSNextProto[proto]; fn != nil {
   243  		fn(srv, tlsConn, nil)
   244  	}
   245  	return
   246  }
   247  
   248  func serveSPDYNoNPN(conn net.Conn, srv *http.Server, version, subversion int) {
   249  	defer common.Recover()
   250  
   251  	tlsConn, ok := conn.(*tls.Conn)
   252  	if !ok { // Only allow TLS connections.
   253  		return
   254  	}
   255  
   256  	if d := srv.ReadTimeout; d != 0 {
   257  		conn.SetReadDeadline(time.Now().Add(d))
   258  	}
   259  	if d := srv.WriteTimeout; d != 0 {
   260  		conn.SetWriteDeadline(time.Now().Add(d))
   261  	}
   262  	if err := tlsConn.Handshake(); err != nil {
   263  		return
   264  	}
   265  
   266  	serverConn, err := NewServerConn(tlsConn, srv, version, subversion)
   267  	if err != nil {
   268  		log.Println(err)
   269  		return
   270  	}
   271  	serverConn.Run()
   272  }