vendor: update vendored upspin.io to 6449eee

Change-Id: Ia12bf67a10f9d2eea4eeced4cf1881edc35cd6d0
Reviewed-on: https://upspin-review.googlesource.com/18144
Reviewed-by: Rob Pike <r@golang.org>
diff --git a/Gopkg.lock b/Gopkg.lock
index b69b0e7..646a1be 100644
--- a/Gopkg.lock
+++ b/Gopkg.lock
@@ -35,7 +35,7 @@
   branch = "master"
   name = "golang.org/x/crypto"
   packages = ["acme","acme/autocert","hkdf"]
-  revision = "2509b142fb2b797aa7587dad548f113b2c0f20ce"
+  revision = "13931e22f9e72ea58bb73048bc752b48c6d4d4ac"
 
 [[projects]]
   branch = "master"
@@ -95,7 +95,7 @@
   branch = "master"
   name = "upspin.io"
   packages = ["access","bind","cache","client","client/clientutil","client/file","cloud/https","cloud/mail","cloud/mail/sendgrid","cloud/storage","config","dir/inprocess","dir/remote","dir/server","dir/server/serverlog","dir/server/tree","dir/unassigned","errors","factotum","flags","key/inprocess","key/remote","key/server","key/sha256key","key/transports","key/unassigned","key/usercache","log","metric","pack","pack/ee","pack/eeintegrity","pack/internal","pack/packutil","pack/plain","path","rpc","rpc/dirserver","rpc/keyserver","rpc/local","rpc/storeserver","serverutil","serverutil/dirserver","serverutil/frontend","serverutil/keyserver","serverutil/perm","serverutil/signup","serverutil/storeserver","serverutil/upspinserver","serverutil/web","shutdown","store/inprocess","store/remote","store/server","store/transports","store/unassigned","subcmd","test/testutil","transports","upspin","upspin/proto","user","valid","version"]
-  revision = "57ddb83c6c6783ca881be6aa11169fc32d8b12c1"
+  revision = "6449eeed647988952316dc9dc9e323d06851125c"
 
 [solve-meta]
   analyzer-name = "dep"
diff --git a/vendor/golang.org/x/crypto/acme/autocert/autocert.go b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
index 94edba9..453e722 100644
--- a/vendor/golang.org/x/crypto/acme/autocert/autocert.go
+++ b/vendor/golang.org/x/crypto/acme/autocert/autocert.go
@@ -24,7 +24,9 @@
 	"fmt"
 	"io"
 	mathrand "math/rand"
+	"net"
 	"net/http"
+	"path"
 	"strconv"
 	"strings"
 	"sync"
@@ -80,8 +82,9 @@
 }
 
 // Manager is a stateful certificate manager built on top of acme.Client.
-// It obtains and refreshes certificates automatically,
-// as well as providing them to a TLS server via tls.Config.
+// It obtains and refreshes certificates automatically using "tls-sni-01",
+// "tls-sni-02" and "http-01" challenge types, as well as providing them
+// to a TLS server via tls.Config.
 //
 // You must specify a cache implementation, such as DirCache,
 // to reuse obtained certificates across program restarts.
@@ -150,15 +153,26 @@
 	stateMu sync.Mutex
 	state   map[string]*certState // keyed by domain name
 
-	// tokenCert is keyed by token domain name, which matches server name
-	// of ClientHello. Keys always have ".acme.invalid" suffix.
-	tokenCertMu sync.RWMutex
-	tokenCert   map[string]*tls.Certificate
-
 	// renewal tracks the set of domains currently running renewal timers.
 	// It is keyed by domain name.
 	renewalMu sync.Mutex
 	renewal   map[string]*domainRenewal
+
+	// tokensMu guards the rest of the fields: tryHTTP01, certTokens and httpTokens.
+	tokensMu sync.RWMutex
+	// tryHTTP01 indicates whether the Manager should try "http-01" challenge type
+	// during the authorization flow.
+	tryHTTP01 bool
+	// httpTokens contains response body values for http-01 challenges
+	// and is keyed by the URL path at which a challenge response is expected
+	// to be provisioned.
+	// The entries are stored for the duration of the authorization flow.
+	httpTokens map[string][]byte
+	// certTokens contains temporary certificates for tls-sni challenges
+	// and is keyed by token domain name, which matches server name of ClientHello.
+	// Keys always have ".acme.invalid" suffix.
+	// The entries are stored for the duration of the authorization flow.
+	certTokens map[string]*tls.Certificate
 }
 
 // GetCertificate implements the tls.Config.GetCertificate hook.
@@ -185,14 +199,16 @@
 		return nil, errors.New("acme/autocert: server name contains invalid character")
 	}
 
+	// In the worst-case scenario, the timeout needs to account for caching, host policy,
+	// domain ownership verification and certificate issuance.
 	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)
 	defer cancel()
 
 	// check whether this is a token cert requested for TLS-SNI challenge
 	if strings.HasSuffix(name, ".acme.invalid") {
-		m.tokenCertMu.RLock()
-		defer m.tokenCertMu.RUnlock()
-		if cert := m.tokenCert[name]; cert != nil {
+		m.tokensMu.RLock()
+		defer m.tokensMu.RUnlock()
+		if cert := m.certTokens[name]; cert != nil {
 			return cert, nil
 		}
 		if cert, err := m.cacheGet(ctx, name); err == nil {
@@ -224,6 +240,68 @@
 	return cert, nil
 }
 
+// HTTPHandler configures the Manager to provision ACME "http-01" challenge responses.
+// It returns an http.Handler that responds to the challenges and must be
+// running on port 80. If it receives a request that is not an ACME challenge,
+// it delegates the request to the optional fallback handler.
+//
+// If fallback is nil, the returned handler redirects all GET and HEAD requests
+// to the default TLS port 443 with 302 Found status code, preserving the original
+// request path and query. It responds with 400 Bad Request to all other HTTP methods.
+// The fallback is not protected by the optional HostPolicy.
+//
+// Because the fallback handler is run with unencrypted port 80 requests,
+// the fallback should not serve TLS-only requests.
+//
+// If HTTPHandler is never called, the Manager will only use TLS SNI
+// challenges for domain verification.
+func (m *Manager) HTTPHandler(fallback http.Handler) http.Handler {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	m.tryHTTP01 = true
+
+	if fallback == nil {
+		fallback = http.HandlerFunc(handleHTTPRedirect)
+	}
+	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+		if !strings.HasPrefix(r.URL.Path, "/.well-known/acme-challenge/") {
+			fallback.ServeHTTP(w, r)
+			return
+		}
+		// A reasonable context timeout for cache and host policy only,
+		// because we don't wait for a new certificate issuance here.
+		ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
+		defer cancel()
+		if err := m.hostPolicy()(ctx, r.Host); err != nil {
+			http.Error(w, err.Error(), http.StatusForbidden)
+			return
+		}
+		data, err := m.httpToken(ctx, r.URL.Path)
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusNotFound)
+			return
+		}
+		w.Write(data)
+	})
+}
+
+func handleHTTPRedirect(w http.ResponseWriter, r *http.Request) {
+	if r.Method != "GET" && r.Method != "HEAD" {
+		http.Error(w, "Use HTTPS", http.StatusBadRequest)
+		return
+	}
+	target := "https://" + stripPort(r.Host) + r.URL.RequestURI()
+	http.Redirect(w, r, target, http.StatusFound)
+}
+
+func stripPort(hostport string) string {
+	host, _, err := net.SplitHostPort(hostport)
+	if err != nil {
+		return hostport
+	}
+	return net.JoinHostPort(host, "443")
+}
+
 // cert returns an existing certificate either from m.state or cache.
 // If a certificate is found in cache but not in m.state, the latter will be filled
 // with the cached value.
@@ -442,13 +520,14 @@
 // authorizedCert starts the domain ownership verification process and requests a new cert upon success.
 // The key argument is the certificate private key.
 func (m *Manager) authorizedCert(ctx context.Context, key crypto.Signer, domain string) (der [][]byte, leaf *x509.Certificate, err error) {
-	if err := m.verify(ctx, domain); err != nil {
-		return nil, nil, err
-	}
 	client, err := m.acmeClient(ctx)
 	if err != nil {
 		return nil, nil, err
 	}
+
+	if err := m.verify(ctx, client, domain); err != nil {
+		return nil, nil, err
+	}
 	csr, err := certRequest(key, domain)
 	if err != nil {
 		return nil, nil, err
@@ -464,98 +543,171 @@
 	return der, leaf, nil
 }
 
-// verify starts a new identifier (domain) authorization flow.
-// It prepares a challenge response and then blocks until the authorization
-// is marked as "completed" by the CA (either succeeded or failed).
-//
-// verify returns nil iff the verification was successful.
-func (m *Manager) verify(ctx context.Context, domain string) error {
-	client, err := m.acmeClient(ctx)
-	if err != nil {
-		return err
+// verify runs the identifier (domain) authorization flow
+// using each applicable ACME challenge type.
+func (m *Manager) verify(ctx context.Context, client *acme.Client, domain string) error {
+	// The list of challenge types we'll try to fulfill
+	// in this specific order.
+	challengeTypes := []string{"tls-sni-02", "tls-sni-01"}
+	m.tokensMu.RLock()
+	if m.tryHTTP01 {
+		challengeTypes = append(challengeTypes, "http-01")
 	}
+	m.tokensMu.RUnlock()
 
-	// start domain authorization and get the challenge
-	authz, err := client.Authorize(ctx, domain)
-	if err != nil {
-		return err
-	}
-	// maybe don't need to at all
-	if authz.Status == acme.StatusValid {
-		return nil
-	}
-
-	// pick a challenge: prefer tls-sni-02 over tls-sni-01
-	// TODO: consider authz.Combinations
-	var chal *acme.Challenge
-	for _, c := range authz.Challenges {
-		if c.Type == "tls-sni-02" {
-			chal = c
-			break
+	var nextTyp int // challengeType index of the next challenge type to try
+	for {
+		// Start domain authorization and get the challenge.
+		authz, err := client.Authorize(ctx, domain)
+		if err != nil {
+			return err
 		}
-		if c.Type == "tls-sni-01" {
-			chal = c
+		// No point in accepting challenges if the authorization status
+		// is in a final state.
+		switch authz.Status {
+		case acme.StatusValid:
+			return nil // already authorized
+		case acme.StatusInvalid:
+			return fmt.Errorf("acme/autocert: invalid authorization %q", authz.URI)
+		}
+
+		// Pick the next preferred challenge.
+		var chal *acme.Challenge
+		for chal == nil && nextTyp < len(challengeTypes) {
+			chal = pickChallenge(challengeTypes[nextTyp], authz.Challenges)
+			nextTyp++
+		}
+		if chal == nil {
+			return fmt.Errorf("acme/autocert: unable to authorize %q; tried %q", domain, challengeTypes)
+		}
+		cleanup, err := m.fulfill(ctx, client, chal)
+		if err != nil {
+			continue
+		}
+		defer cleanup()
+		if _, err := client.Accept(ctx, chal); err != nil {
+			continue
+		}
+
+		// A challenge is fulfilled and accepted: wait for the CA to validate.
+		if _, err := client.WaitAuthorization(ctx, authz.URI); err == nil {
+			return nil
 		}
 	}
-	if chal == nil {
-		return errors.New("acme/autocert: no supported challenge type found")
-	}
-
-	// create a token cert for the challenge response
-	var (
-		cert tls.Certificate
-		name string
-	)
-	switch chal.Type {
-	case "tls-sni-01":
-		cert, name, err = client.TLSSNI01ChallengeCert(chal.Token)
-	case "tls-sni-02":
-		cert, name, err = client.TLSSNI02ChallengeCert(chal.Token)
-	default:
-		err = fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
-	}
-	if err != nil {
-		return err
-	}
-	m.putTokenCert(ctx, name, &cert)
-	defer func() {
-		// verification has ended at this point
-		// don't need token cert anymore
-		go m.deleteTokenCert(name)
-	}()
-
-	// ready to fulfill the challenge
-	if _, err := client.Accept(ctx, chal); err != nil {
-		return err
-	}
-	// wait for the CA to validate
-	_, err = client.WaitAuthorization(ctx, authz.URI)
-	return err
 }
 
-// putTokenCert stores the cert under the named key in both m.tokenCert map
-// and m.Cache.
-func (m *Manager) putTokenCert(ctx context.Context, name string, cert *tls.Certificate) {
-	m.tokenCertMu.Lock()
-	defer m.tokenCertMu.Unlock()
-	if m.tokenCert == nil {
-		m.tokenCert = make(map[string]*tls.Certificate)
+// fulfill provisions a response to the challenge chal.
+// The cleanup is non-nil only if provisioning succeeded.
+func (m *Manager) fulfill(ctx context.Context, client *acme.Client, chal *acme.Challenge) (cleanup func(), err error) {
+	switch chal.Type {
+	case "tls-sni-01":
+		cert, name, err := client.TLSSNI01ChallengeCert(chal.Token)
+		if err != nil {
+			return nil, err
+		}
+		m.putCertToken(ctx, name, &cert)
+		return func() { go m.deleteCertToken(name) }, nil
+	case "tls-sni-02":
+		cert, name, err := client.TLSSNI02ChallengeCert(chal.Token)
+		if err != nil {
+			return nil, err
+		}
+		m.putCertToken(ctx, name, &cert)
+		return func() { go m.deleteCertToken(name) }, nil
+	case "http-01":
+		resp, err := client.HTTP01ChallengeResponse(chal.Token)
+		if err != nil {
+			return nil, err
+		}
+		p := client.HTTP01ChallengePath(chal.Token)
+		m.putHTTPToken(ctx, p, resp)
+		return func() { go m.deleteHTTPToken(p) }, nil
 	}
-	m.tokenCert[name] = cert
+	return nil, fmt.Errorf("acme/autocert: unknown challenge type %q", chal.Type)
+}
+
+func pickChallenge(typ string, chal []*acme.Challenge) *acme.Challenge {
+	for _, c := range chal {
+		if c.Type == typ {
+			return c
+		}
+	}
+	return nil
+}
+
+// putCertToken stores the cert under the named key in both m.certTokens map
+// and m.Cache.
+func (m *Manager) putCertToken(ctx context.Context, name string, cert *tls.Certificate) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	if m.certTokens == nil {
+		m.certTokens = make(map[string]*tls.Certificate)
+	}
+	m.certTokens[name] = cert
 	m.cachePut(ctx, name, cert)
 }
 
-// deleteTokenCert removes the token certificate for the specified domain name
-// from both m.tokenCert map and m.Cache.
-func (m *Manager) deleteTokenCert(name string) {
-	m.tokenCertMu.Lock()
-	defer m.tokenCertMu.Unlock()
-	delete(m.tokenCert, name)
+// deleteCertToken removes the token certificate for the specified domain name
+// from both m.certTokens map and m.Cache.
+func (m *Manager) deleteCertToken(name string) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	delete(m.certTokens, name)
 	if m.Cache != nil {
 		m.Cache.Delete(context.Background(), name)
 	}
 }
 
+// httpToken retrieves an existing http-01 token value from an in-memory map
+// or the optional cache.
+func (m *Manager) httpToken(ctx context.Context, tokenPath string) ([]byte, error) {
+	m.tokensMu.RLock()
+	defer m.tokensMu.RUnlock()
+	if v, ok := m.httpTokens[tokenPath]; ok {
+		return v, nil
+	}
+	if m.Cache == nil {
+		return nil, fmt.Errorf("acme/autocert: no token at %q", tokenPath)
+	}
+	return m.Cache.Get(ctx, httpTokenCacheKey(tokenPath))
+}
+
+// putHTTPToken stores an http-01 token value using tokenPath as key
+// in both in-memory map and the optional Cache.
+//
+// It ignores any error returned from Cache.Put.
+func (m *Manager) putHTTPToken(ctx context.Context, tokenPath, val string) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	if m.httpTokens == nil {
+		m.httpTokens = make(map[string][]byte)
+	}
+	b := []byte(val)
+	m.httpTokens[tokenPath] = b
+	if m.Cache != nil {
+		m.Cache.Put(ctx, httpTokenCacheKey(tokenPath), b)
+	}
+}
+
+// deleteHTTPToken removes an http-01 token value from both in-memory map
+// and the optional Cache, ignoring any error returned from the latter.
+//
+// If m.Cache is non-nil, it blocks until Cache.Delete returns without a timeout.
+func (m *Manager) deleteHTTPToken(tokenPath string) {
+	m.tokensMu.Lock()
+	defer m.tokensMu.Unlock()
+	delete(m.httpTokens, tokenPath)
+	if m.Cache != nil {
+		m.Cache.Delete(context.Background(), httpTokenCacheKey(tokenPath))
+	}
+}
+
+// httpTokenCacheKey returns a key at which an http-01 token value may be stored
+// in the Manager's optional Cache.
+func httpTokenCacheKey(tokenPath string) string {
+	return "http-01-" + path.Base(tokenPath)
+}
+
 // renew starts a cert renewal timer loop, one per domain.
 //
 // The loop is scheduled in two cases:
diff --git a/vendor/upspin.io/Gopkg.lock b/vendor/upspin.io/Gopkg.lock
index 938da47..be77bcb 100644
--- a/vendor/upspin.io/Gopkg.lock
+++ b/vendor/upspin.io/Gopkg.lock
@@ -29,7 +29,7 @@
   branch = "master"
   name = "golang.org/x/crypto"
   packages = ["acme","acme/autocert","hkdf"]
-  revision = "2509b142fb2b797aa7587dad548f113b2c0f20ce"
+  revision = "13931e22f9e72ea58bb73048bc752b48c6d4d4ac"
 
 [[projects]]
   branch = "master"
diff --git a/vendor/upspin.io/README.binary b/vendor/upspin.io/README.binary
index 6e43d88..ce30f8a 100644
--- a/vendor/upspin.io/README.binary
+++ b/vendor/upspin.io/README.binary
@@ -39,4 +39,9 @@
 
 	https://godoc.org/upspin.io/cmd/upspinfs
 
+upspin-audit
+	Audit provides subcommands for auditing storage consumption.
+
+	https://godoc.org/upspin.io/cmd/upspin-audit
+
 These binaries were built for {{.OSArch}} at{{range .Commits}} {{.Repo}}/{{.ShortHash}}{{end}}.
diff --git a/vendor/upspin.io/cloud/https/https.go b/vendor/upspin.io/cloud/https/https.go
index b3997b5..d19e68f 100644
--- a/vendor/upspin.io/cloud/https/https.go
+++ b/vendor/upspin.io/cloud/https/https.go
@@ -28,9 +28,16 @@
 // outside GCE. The default is the self-signed certificate in
 // upspin.io/rpc/testdata.
 type Options struct {
-	// Addr specifies the host and port on which the server should listen.
+	// Addr specifies the host and port on which the server should serve
+	// HTTPS requests (or HTTP requests if InsecureHTTP is set).
+	// If empty, ":443" is used.
 	Addr string
 
+	// HTTPAddr specifies the host and port on which the server should
+	// serve HTTP requests. If empty and InsecureHTTP is true, Addr is
+	// used.  If empty otherwise, ":80" is used.
+	HTTPAddr string
+
 	// AutocertCache provides a cache for use with Let's Encrypt.
 	// If non-nil, enables Let's Encrypt certificates for this server.
 	// See the comment on ErrAutocertCacheMiss before usin this feature.
@@ -89,6 +96,16 @@
 }
 
 func (opt *Options) applyDefaults() {
+	if opt.Addr == "" {
+		opt.Addr = ":443"
+	}
+	if opt.HTTPAddr == "" {
+		if opt.InsecureHTTP {
+			opt.HTTPAddr = opt.Addr
+		} else {
+			opt.HTTPAddr = ":80"
+		}
+	}
 	if opt.CertFile == "" {
 		opt.CertFile = defaultOptions.CertFile
 	}
@@ -108,12 +125,9 @@
 		}
 		hosts = []string{host}
 	}
-	addr := flags.HTTPSAddr
-	if flags.InsecureHTTP {
-		addr = flags.HTTPAddr
-	}
 	return &Options{
-		Addr:             addr,
+		Addr:             flags.HTTPSAddr,
+		HTTPAddr:         flags.HTTPAddr,
 		LetsEncryptCache: flags.LetsEncryptCache,
 		LetsEncryptHosts: hosts,
 		CertFile:         flags.TLSCertFile,
@@ -147,10 +161,10 @@
 	hasAutocertCache := opt.AutocertCache != nil
 	hasCert := opt.CertFile != defaultOptions.CertFile || opt.KeyFile != defaultOptions.KeyFile
 
-	var m autocert.Manager
-	m.Prompt = autocert.AcceptTOS
+	var manager autocert.Manager
+	manager.Prompt = autocert.AcceptTOS
 	if h := opt.LetsEncryptHosts; len(h) > 0 {
-		m.HostPolicy = autocert.HostWhitelist(h...)
+		manager.HostPolicy = autocert.HostWhitelist(h...)
 	}
 
 	addr := opt.Addr
@@ -172,15 +186,14 @@
 		log.Info.Printf("https: serving HTTPS on %q using Let's Encrypt certificates", addr)
 		log.Info.Printf("https: caching Let's Encrypt certificates in %v", dir)
 		if err := os.MkdirAll(dir, 0700); err != nil {
-			log.Fatalf("https: could not create or read -letscache directory: %v", err)
+			log.Fatalf("https: could not create -letscache directory: %v", err)
 		}
-		m.Cache = autocert.DirCache(dir)
-		config = &tls.Config{GetCertificate: m.GetCertificate}
+		manager.Cache = autocert.DirCache(dir)
+		config = &tls.Config{GetCertificate: manager.GetCertificate}
 	case hasAutocertCache:
-		addr = ":443"
 		log.Info.Printf("https: serving HTTPS on %q using Let's Encrypt certificates", addr)
-		m.Cache = opt.AutocertCache
-		config = &tls.Config{GetCertificate: m.GetCertificate}
+		manager.Cache = opt.AutocertCache
+		config = &tls.Config{GetCertificate: manager.GetCertificate}
 	default:
 		log.Info.Printf("https: serving HTTPS on %q using provided certificates", addr)
 		if opt.CertFile == defaultOptions.CertFile || opt.KeyFile == defaultOptions.KeyFile {
@@ -192,36 +205,57 @@
 			log.Fatalf("https: setting up TLS config: %v", err)
 		}
 	}
-	// WriteTimeout is set to 0 because it also pertains to streaming
-	// replies, e.g., the DirServer.Watch interface.
+
+	// Set up the main listener for HTTPS (or HTTP if InsecureHTTP is set).
+	ln, err := net.Listen("tcp", addr)
+	if err != nil {
+		log.Fatalf("https: %v", err)
+	}
+	shutdown.Handle(func() { ln.Close() })
+
+	if manager.Cache != nil {
+		// If we're using LetsEncrypt then we need to serve the http-01
+		// challenge by plain HTTP. We also serve a redirect to HTTPS
+		// for all other requests.
+		httpLn, err := net.Listen("tcp", opt.HTTPAddr)
+		if err != nil {
+			log.Fatalf("https: %v", err)
+		}
+		shutdown.Handle(func() { httpLn.Close() })
+		httpServer := &http.Server{Handler: manager.HTTPHandler(nil)}
+		go func() {
+			err := httpServer.Serve(httpLn)
+			log.Printf("https: %v", err)
+			shutdown.Now(1)
+		}()
+	}
+
+	if ready != nil {
+		// Notify the calling packages that
+		// we're ready to accept requests.
+		close(ready)
+	}
+
+	// If we're serving HTTPS then wrap the listener with a TLS listener.
+	if !opt.InsecureHTTP {
+		ln = tls.NewListener(ln, config)
+	}
+
+	// Set up the main server.
 	server := &http.Server{
 		ReadHeaderTimeout: 5 * time.Second,
 		ReadTimeout:       15 * time.Second,
-		WriteTimeout:      0,
-		IdleTimeout:       60 * time.Second,
-		TLSConfig:         config,
+		// WriteTimeout is set to 0 because it also pertains to
+		// streaming replies, e.g., the DirServer.Watch interface.
+		WriteTimeout: 0,
+		IdleTimeout:  60 * time.Second,
+		TLSConfig:    config,
 	}
 	// TODO(adg): enable HTTP/2 once it's fast enough
 	//err := http2.ConfigureServer(server, nil)
 	//if err != nil {
 	//	log.Fatalf("https: %v", err)
 	//}
-
-	ln, err := net.Listen("tcp", addr)
-	if err != nil {
-		log.Fatalf("https: %v", err)
-	}
-	if ready != nil {
-		close(ready)
-	}
-	shutdown.Handle(func() {
-		// Stop accepting connections and forces the server to stop
-		// its serving loop.
-		ln.Close()
-	})
-	if !opt.InsecureHTTP {
-		ln = tls.NewListener(ln, config)
-	}
 	err = server.Serve(ln)
 	log.Printf("https: %v", err)
 	shutdown.Now(1)
diff --git a/vendor/upspin.io/dir/inprocess/watch.go b/vendor/upspin.io/dir/inprocess/watch.go
index 61a5b54..1a834dd 100644
--- a/vendor/upspin.io/dir/inprocess/watch.go
+++ b/vendor/upspin.io/dir/inprocess/watch.go
@@ -241,9 +241,9 @@
 
 	eventsSoFar := <-e.eventsSoFar
 
-	// A sequence other than the special cases 0 and -1 must exist.
+	// A sequence other than the special cases must exist.
 	// The special case of an invalid sequence is returned as an event with an "invalid" error.
-	if sequence != 0 && sequence != -1 {
+	if sequence != upspin.WatchCurrent && sequence != upspin.WatchStart && sequence != upspin.WatchNew {
 		if sequence < 0 || int64(len(eventsSoFar)) < sequence {
 			events <- upspin.Event{Error: errors.E(op, errors.Invalid, "bad sequence")}
 			close(events)
diff --git a/vendor/upspin.io/flags/flags.go b/vendor/upspin.io/flags/flags.go
index 629bdb6..3102210 100644
--- a/vendor/upspin.io/flags/flags.go
+++ b/vendor/upspin.io/flags/flags.go
@@ -33,6 +33,7 @@
 	defaultHTTPSAddr  = ":443"
 	defaultLog        = "info"
 	defaultServerKind = "inprocess"
+	defaultCacheSize  = int64(5e9)
 )
 
 var (
@@ -77,6 +78,10 @@
 	// caches.
 	CacheDir = defaultCacheDir
 
+	// CacheSize ("cachesize") specifies the maximum bytes used by
+	// the various file caches. This is only approximate.
+	CacheSize = defaultCacheSize
+
 	// Config ("config") names the Upspin configuration file to use.
 	Config = defaultConfig
 
@@ -147,9 +152,20 @@
 		},
 	},
 	"cachedir": strVar(&CacheDir, "cachedir", CacheDir, "`directory` containing all file caches"),
-	"config":   strVar(&Config, "config", Config, "user's configuration `file`"),
-	"http":     strVar(&HTTPAddr, "http", HTTPAddr, "`address` for incoming insecure network connections"),
-	"https":    strVar(&HTTPSAddr, "https", HTTPSAddr, "`address` for incoming secure network connections"),
+	"cachesize": &flagVar{
+		set: func(fs *flag.FlagSet) {
+			fs.Int64Var(&CacheSize, "cachesize", defaultCacheSize, "maximum bytes for file caches")
+		},
+		arg: func() string {
+			if CacheSize == defaultCacheSize {
+				return ""
+			}
+			return fmt.Sprintf("-cachesize=%d", CacheSize)
+		},
+	},
+	"config": strVar(&Config, "config", Config, "user's configuration `file`"),
+	"http":   strVar(&HTTPAddr, "http", HTTPAddr, "`address` for incoming insecure network connections"),
+	"https":  strVar(&HTTPSAddr, "https", HTTPSAddr, "`address` for incoming secure network connections"),
 	"insecure": &flagVar{
 		set: func(fs *flag.FlagSet) {
 			fs.BoolVar(&InsecureHTTP, "insecure", false, "whether to serve insecure HTTP instead of HTTPS")
diff --git a/vendor/upspin.io/rpc/client.go b/vendor/upspin.io/rpc/client.go
index 67aac91..3b2113d 100644
--- a/vendor/upspin.io/rpc/client.go
+++ b/vendor/upspin.io/rpc/client.go
@@ -127,6 +127,7 @@
 			KeepAlive: 30 * time.Second,
 		}).DialContext,
 		MaxIdleConns:          100,
+		MaxIdleConnsPerHost:   10,
 		IdleConnTimeout:       90 * time.Second,
 		TLSHandshakeTimeout:   10 * time.Second,
 		ExpectContinueTimeout: 1 * time.Second,
diff --git a/vendor/upspin.io/serverutil/frontend/frontend.go b/vendor/upspin.io/serverutil/frontend/frontend.go
index 60197d6..e4aed32 100644
--- a/vendor/upspin.io/serverutil/frontend/frontend.go
+++ b/vendor/upspin.io/serverutil/frontend/frontend.go
@@ -62,13 +62,6 @@
 		}
 		http.Handle("/", s)
 	}
-
-	if !flags.InsecureHTTP {
-		go func() {
-			log.Printf("Serving HTTP->HTTPS redirect on %q", flags.HTTPAddr)
-			log.Fatal(http.ListenAndServe(flags.HTTPAddr, http.HandlerFunc(redirectHTTP)))
-		}()
-	}
 }
 
 const (
@@ -101,18 +94,6 @@
 	return p.Dir
 }
 
-func redirectHTTP(w http.ResponseWriter, r *http.Request) {
-	if r.TLS != nil || r.Host == "" {
-		http.NotFound(w, r)
-		return
-	}
-
-	u := r.URL
-	u.Host = r.Host
-	u.Scheme = "https"
-	http.Redirect(w, r, u.String(), http.StatusFound)
-}
-
 type server struct {
 	handlers http.Handler // stack of wrapped http.Handlers
 	docHTML  map[string][]byte