func (p mockPlugin) file() fs.File { incomingR, incomingW := io.Pipe() outgoingR, outgoingW := io.Pipe() // TODO: This is a terrible hack of a little http server. Really, we should // implement some sort of fs.File -> net.Listener bridge and run an net/http // server on that. go func() { for { conn := httputil.NewServerConn(&ionet.Conn{R: incomingR, W: outgoingW}, nil) req, err := conn.Read() if err == io.EOF { outgoingW.Close() return } else if err != nil { p.t.Fatal(err) } resp := httptest.NewRecorder() p.Handler.ServeHTTP(resp, req) fmt.Fprintf(outgoingW, "HTTP/1.1 %d %s\nContent-Length: %d\n\n%s", resp.Code, http.StatusText(resp.Code), resp.Body.Len(), resp.Body.String()) } }() return fs.File{ FName: p.base(), FWriter: incomingW, FReader: outgoingR, FStat: syscall.Stat_t{Mode: syscall.S_IFSOCK}, } }
func (s *HTTPListener) handle(conn net.Conn, isTLS bool) { defer conn.Close() var r *httpRoute // For TLS, use the SNI hello to determine the domain. // At this stage, if we don't find a match, we simply // close the connection down. if isTLS { // Parse out host via SNI first vhostConn, err := vhost.TLS(conn) if err != nil { log.Println("Failed to decode TLS connection", err) return } host := vhostConn.Host() // Find a backend for the key r = s.findRouteForHost(host) if r == nil { return } if r.keypair == nil { log.Println("Cannot serve TLS, no certificate defined for this domain") return } // Init a TLS decryptor tlscfg := &tls.Config{Certificates: []tls.Certificate{*r.keypair}} conn = tls.Server(vhostConn, tlscfg) } sc := httputil.NewServerConn(conn, nil) for { req, err := sc.Read() if err != nil { if err != io.EOF && err != httputil.ErrPersistEOF { log.Println("client read err:", err) } return } if !isTLS { r = s.findRouteForHost(req.Host) if r == nil { fail(sc, req, 404, "Not Found") continue } } req.RemoteAddr = conn.RemoteAddr().String() if r.service.handle(req, sc, isTLS, r.Sticky) { return } } }
func (s *HTTPListener) handle(conn net.Conn, isTLS bool) { defer conn.Close() var r *httpRoute // For TLS, use the SNI hello to determine the domain. // At this stage, if we don't find a match, we simply // close the connection down. if isTLS { // Parse out host via SNI first vhostConn, err := vhost.TLS(conn) if err != nil { log.Println("Failed to decode TLS connection", err) return } host := vhostConn.Host() // Find a backend for the key r = s.findRouteForHost(host) if r == nil { return } if r.keypair == nil { log.Println("Cannot serve TLS, no certificate defined for this domain") return } // Init a TLS decryptor tlscfg := &tls.Config{Certificates: []tls.Certificate{*r.keypair}} conn = tls.Server(vhostConn, tlscfg) } // Decode the first request from the connection sc := httputil.NewServerConn(conn, nil) req, err := sc.Read() if err != nil { if err != httputil.ErrPersistEOF { // TODO: log error } return } // If we do not have a backend yet (unencrypted connection), // look at the host header to find one or 404 out. if r == nil { r = s.findRouteForHost(req.Host) if r == nil { fail(sc, req, 404, "Not Found") return } } r.service.handle(req, sc, isTLS, r.Sticky) }
func (s *HTTPListener) handle(conn net.Conn, isTLS bool) { defer conn.Close() var r *httpRoute if isTLS { certForHandshake := func(hello *tls.ClientHelloInfo) (*tls.Certificate, error) { r = s.findRouteForHost(hello.ServerName) if r == nil { return nil, errMissingTLS } if r.keypair == nil { return nil, errMissingTLS } return r.keypair, nil } conn = tls.Server(conn, &tls.Config{GetCertificate: certForHandshake, Certificates: []tls.Certificate{{}}}) } sc := httputil.NewServerConn(conn, nil) for { req, err := sc.Read() if err != nil { if err != io.EOF && err != httputil.ErrPersistEOF && err != errMissingTLS { log.Println("client read err:", err) } return } if !isTLS { r = s.findRouteForHost(req.Host) if r == nil { fail(sc, req, 404, "Not Found") continue } } req.RemoteAddr = conn.RemoteAddr().String() if r.service.handle(req, sc, isTLS, r.Sticky) { return } } }
func (s *HTTPFrontend) handle(conn net.Conn) { defer conn.Close() sc := httputil.NewServerConn(conn, nil) req, err := sc.Read() if err != nil { if err != httputil.ErrPersistEOF { // TODO: log error } return } s.mtx.RLock() // TODO: handle wildcard domains backend := s.domains[req.Host] s.mtx.RUnlock() log.Println(req, backend) if backend == nil { fail(sc, req, 404, "Not Found") return } _, tls := conn.(*tls.Conn) backend.handle(req, sc, tls) }