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 }