github.com/IBM-Bluemix/golang-openssl-wrapper@v0.0.0-20160104220506-7f2d5273b515/ssl/httpsserver.go (about)

     1  package ssl
     2  
     3  import (
     4  	"bufio"
     5  	"errors"
     6  	"fmt"
     7  	"log"
     8  	"net"
     9  	"net/http"
    10  	"os"
    11  	"path/filepath"
    12  )
    13  
    14  /*
    15  	Handle is shorthand for:
    16  		http.DefaultServeMux.Handle(pattern, handler)
    17  */
    18  func Handle(pattern string, handler http.Handler) {
    19  	http.DefaultServeMux.Handle(pattern, handler)
    20  }
    21  
    22  /*
    23  	HandleFunc is shorthand for:
    24  		http.DefaultServeMux.Handler(pattern, handler)
    25  */
    26  func HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
    27  	http.DefaultServeMux.HandleFunc(pattern, handler)
    28  }
    29  
    30  /*
    31  	Conn is used for incoming server connections.
    32  */
    33  type Conn struct {
    34  	net.Conn
    35  
    36  	ctx SSL
    37  	f   *os.File
    38  	fd  int
    39  }
    40  
    41  /*
    42  	Close will free any contexts, files, and connections that are
    43  	associated with the Conn.
    44  */
    45  func (c Conn) Close() error {
    46  	var e error
    47  
    48  	SSL_free(c.ctx)
    49  
    50  	if e = c.Conn.Close(); e != nil {
    51  		return e
    52  	}
    53  	if e = c.f.Close(); e != nil {
    54  		return e
    55  	}
    56  	return nil
    57  }
    58  
    59  func (c Conn) getHandshake() error {
    60  	if SSL_accept(c.ctx) < 0 {
    61  		return errors.New("SSL handshake unsuccessful")
    62  	}
    63  
    64  	return nil
    65  }
    66  
    67  /*
    68  	Read will use SSL_read to read directly from the file descriptor
    69  	of the open connection.
    70  */
    71  func (c Conn) Read(buf []byte) (int, error) {
    72  	result := SSL_read(c.ctx, buf, len(buf))
    73  	if result > 0 {
    74  		return result, nil
    75  	}
    76  	return 0, errors.New("Unable to read from connection.")
    77  }
    78  
    79  /*
    80  	Write will use SSL_write to write directly to the file descriptor
    81  	of the open connection.
    82  */
    83  func (c Conn) Write(buf []byte) (int, error) {
    84  	result := SSL_write(c.ctx, buf, len(buf))
    85  	if result > 0 {
    86  		return result, nil
    87  	}
    88  	return 0, errors.New("Unable to write to connection.")
    89  }
    90  
    91  type response struct {
    92  	Conn
    93  
    94  	Headers http.Header
    95  
    96  	req          *http.Request
    97  	sentStatus   bool
    98  	wroteHeaders bool
    99  }
   100  
   101  func (r *response) Close() error {
   102  	if e := r.req.Body.Close(); e != nil {
   103  		return e
   104  	}
   105  	return r.Conn.Close()
   106  }
   107  
   108  func (r *response) Header() http.Header {
   109  	return r.Headers
   110  }
   111  
   112  func (r *response) Write(buf []byte) (int, error) {
   113  	if !r.sentStatus {
   114  		r.WriteHeader(http.StatusOK)
   115  	}
   116  
   117  	if !r.wroteHeaders {
   118  		r.wroteHeaders = true
   119  		r.Headers.Write(r.Conn)
   120  		r.Write([]byte("\r\n"))
   121  	}
   122  
   123  	return r.Conn.Write(buf)
   124  }
   125  
   126  func (r *response) WriteHeader(s int) {
   127  	r.sentStatus = true
   128  	r.Conn.Write([]byte(fmt.Sprintf("HTTP/1.1 %d %s\r\n", s, http.StatusText(s))))
   129  }
   130  
   131  /*
   132  	Server mimics the original http.Server. It provides the same methods
   133  	as the original http.Server to be a drop-in replacement.
   134  */
   135  type Server struct {
   136  	Addr     string
   137  	Handler  http.Handler
   138  	ErrorLog *log.Logger
   139  
   140  	ctx       SSL_CTX
   141  	listener  net.Listener
   142  	method    SSL_METHOD
   143  	keepalive bool
   144  }
   145  
   146  /*
   147  	ListenAndServeTLS will create a new Server and call ListenAndServeTLS
   148  	on the Server instance.
   149  
   150  	cf should be an absolute or relative path to the certificate file.
   151  	kf should be an absolute or relative path to the key file.
   152  */
   153  func ListenAndServeTLS(addr, cf, kf string, handler http.Handler) (*Server, error) {
   154  	s := &Server{
   155  		Addr:    addr,
   156  		Handler: handler,
   157  	}
   158  
   159  	return s, s.ListenAndServeTLS(cf, kf)
   160  }
   161  
   162  /*
   163  	ListenAndServe is not supported by this package and will always return
   164  	a hardcoded error saying so. We do not support unencrypted traffic in
   165  	this module.
   166  */
   167  func (s *Server) ListenAndServe() error {
   168  	return errors.New("You must use ListenAndServeTLS with this package. It does not support unencrypted HTTP traffic.")
   169  }
   170  
   171  /*
   172  	ListenAndServeTLS will setup default values, contexts, the certificate,
   173  	and key file. It will then listen on the Addr set in the Server instance and
   174  	call Server.Serve.
   175  
   176  	cf should be an absolute or relative path to the certificate file.
   177  	kf should be an absolute or relative path to the key file.
   178  */
   179  func (s *Server) ListenAndServeTLS(cf, kf string) error {
   180  	var (
   181  		e error
   182  	)
   183  
   184  	if s.method == nil {
   185  		s.method = SSLv23_server_method()
   186  	}
   187  
   188  	if s.Handler == nil {
   189  		s.Handler = http.DefaultServeMux
   190  	}
   191  
   192  	if s.ErrorLog == nil {
   193  		s.ErrorLog = log.New(os.Stdout, "server: ", log.LstdFlags|log.Lshortfile)
   194  	}
   195  
   196  	cf, e = filepath.Abs(cf)
   197  	if e != nil {
   198  		return e
   199  	}
   200  
   201  	kf, e = filepath.Abs(kf)
   202  	if e != nil {
   203  		return e
   204  	}
   205  
   206  	ctx, e := ctxInit("", s.method)
   207  	if e != nil {
   208  		return e
   209  	}
   210  
   211  	if SSL_CTX_use_certificate_file(ctx, cf, SSL_FILETYPE_PEM) <= 0 {
   212  		return errors.New("Could not use certificate file")
   213  	}
   214  
   215  	if SSL_CTX_use_PrivateKey_file(ctx, kf, SSL_FILETYPE_PEM) <= 0 {
   216  		return errors.New("Could not use key file")
   217  	}
   218  
   219  	if SSL_CTX_check_private_key(ctx) < 1 {
   220  		return errors.New("Private key does not match the public certificate")
   221  	}
   222  
   223  	l, e := net.Listen("tcp", s.Addr)
   224  	if e != nil {
   225  		return e
   226  	}
   227  
   228  	s.ctx = ctx
   229  
   230  	return s.Serve(l)
   231  }
   232  
   233  /*
   234  	Serve will accept connections on the net.Listener provided. It will then call
   235  	Server.Handler.ServeHTTP on the resulting connection.
   236  
   237  	You should not close the connection in Server.Handler.ServeHTTP. The
   238  	connection will be automatically closed once Server.Handler.ServeHTTP
   239  	has finished.
   240  */
   241  func (s *Server) Serve(l net.Listener) error {
   242  	var (
   243  		c net.Conn
   244  		e error
   245  		f *os.File
   246  	)
   247  
   248  	check := func(e error) {
   249  		if e != nil {
   250  			s.ErrorLog.Printf("ERROR: %s\n", e)
   251  		}
   252  	}
   253  
   254  	s.listener = l
   255  
   256  	for {
   257  		c, e = s.listener.Accept()
   258  		check(e)
   259  
   260  		switch c.(type) {
   261  		case *net.IPConn:
   262  			f, e = c.(*net.IPConn).File()
   263  		case *net.TCPConn:
   264  			f, e = c.(*net.TCPConn).File()
   265  		case *net.UDPConn:
   266  			f, e = c.(*net.UDPConn).File()
   267  		case *net.UnixConn:
   268  			f, e = c.(*net.UnixConn).File()
   269  		}
   270  
   271  		check(e)
   272  
   273  		c = Conn{
   274  			Conn: c,
   275  			ctx:  SSL_new(s.ctx),
   276  			f:    f,
   277  			fd:   int(f.Fd()),
   278  		}
   279  
   280  		oc := c.(Conn)
   281  		SSL_set_fd(oc.ctx, oc.fd)
   282  
   283  		check(oc.getHandshake())
   284  
   285  		buf := bufio.NewReader(oc)
   286  		req, e := http.ReadRequest(buf)
   287  		check(e)
   288  
   289  		res := &response{
   290  			Conn:    oc,
   291  			Headers: make(http.Header),
   292  			req:     req,
   293  		}
   294  
   295  		s.Handler.ServeHTTP(res, req)
   296  
   297  		check(req.Body.Close())
   298  
   299  		check(oc.Close())
   300  	}
   301  
   302  	return nil
   303  }
   304  
   305  func (s *Server) SetKeepAlivesEnabled(v bool) {
   306  	s.keepalive = v
   307  }