Moved to google.golang.org/genproto/googleapis/api/annotations
Fixes #52
This commit is contained in:
		
							
								
								
									
										5
									
								
								vendor/golang.org/x/net/http2/h2demo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								vendor/golang.org/x/net/http2/h2demo/.gitignore
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,5 @@
 | 
			
		||||
h2demo
 | 
			
		||||
h2demo.linux
 | 
			
		||||
client-id.dat
 | 
			
		||||
client-secret.dat
 | 
			
		||||
token.dat
 | 
			
		||||
							
								
								
									
										8
									
								
								vendor/golang.org/x/net/http2/h2demo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								vendor/golang.org/x/net/http2/h2demo/Makefile
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,8 @@
 | 
			
		||||
h2demo.linux: h2demo.go
 | 
			
		||||
	GOOS=linux go build --tags=h2demo -o h2demo.linux .
 | 
			
		||||
 | 
			
		||||
FORCE:
 | 
			
		||||
 | 
			
		||||
upload: FORCE
 | 
			
		||||
	go install golang.org/x/build/cmd/upload
 | 
			
		||||
	upload --verbose --osarch=linux-amd64 --tags=h2demo --file=go:golang.org/x/net/http2/h2demo --public http2-demo-server-tls/h2demo
 | 
			
		||||
							
								
								
									
										16
									
								
								vendor/golang.org/x/net/http2/h2demo/README
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								vendor/golang.org/x/net/http2/h2demo/README
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
 | 
			
		||||
Client:
 | 
			
		||||
 -- Firefox nightly with about:config network.http.spdy.enabled.http2draft set true
 | 
			
		||||
 -- Chrome: go to chrome://flags/#enable-spdy4, save and restart (button at bottom)
 | 
			
		||||
 | 
			
		||||
Make CA:
 | 
			
		||||
$ openssl genrsa -out rootCA.key 2048
 | 
			
		||||
$ openssl req -x509 -new -nodes -key rootCA.key -days 1024 -out rootCA.pem
 | 
			
		||||
... install that to Firefox
 | 
			
		||||
 | 
			
		||||
Make cert:
 | 
			
		||||
$ openssl genrsa -out server.key 2048
 | 
			
		||||
$ openssl req -new -key server.key -out server.csr
 | 
			
		||||
$ openssl x509 -req -in server.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out server.crt -days 500
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										538
									
								
								vendor/golang.org/x/net/http2/h2demo/h2demo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										538
									
								
								vendor/golang.org/x/net/http2/h2demo/h2demo.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,538 @@
 | 
			
		||||
// Copyright 2014 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build h2demo
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"crypto/tls"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"hash/crc32"
 | 
			
		||||
	"image"
 | 
			
		||||
	"image/jpeg"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"path"
 | 
			
		||||
	"regexp"
 | 
			
		||||
	"runtime"
 | 
			
		||||
	"strconv"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"sync"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"go4.org/syncutil/singleflight"
 | 
			
		||||
	"golang.org/x/crypto/acme/autocert"
 | 
			
		||||
	"golang.org/x/net/http2"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	prod = flag.Bool("prod", false, "Whether to configure itself to be the production http2.golang.org server.")
 | 
			
		||||
 | 
			
		||||
	httpsAddr = flag.String("https_addr", "localhost:4430", "TLS address to listen on ('host:port' or ':port'). Required.")
 | 
			
		||||
	httpAddr  = flag.String("http_addr", "", "Plain HTTP address to listen on ('host:port', or ':port'). Empty means no HTTP.")
 | 
			
		||||
 | 
			
		||||
	hostHTTP  = flag.String("http_host", "", "Optional host or host:port to use for http:// links to this service. By default, this is implied from -http_addr.")
 | 
			
		||||
	hostHTTPS = flag.String("https_host", "", "Optional host or host:port to use for http:// links to this service. By default, this is implied from -https_addr.")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func homeOldHTTP(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	io.WriteString(w, `<html>
 | 
			
		||||
<body>
 | 
			
		||||
<h1>Go + HTTP/2</h1>
 | 
			
		||||
<p>Welcome to <a href="https://golang.org/">the Go language</a>'s <a href="https://http2.github.io/">HTTP/2</a> demo & interop server.</p>
 | 
			
		||||
<p>Unfortunately, you're <b>not</b> using HTTP/2 right now. To do so:</p>
 | 
			
		||||
<ul>
 | 
			
		||||
   <li>Use Firefox Nightly or go to <b>about:config</b> and enable "network.http.spdy.enabled.http2draft"</li>
 | 
			
		||||
   <li>Use Google Chrome Canary and/or go to <b>chrome://flags/#enable-spdy4</b> to <i>Enable SPDY/4</i> (Chrome's name for HTTP/2)</li>
 | 
			
		||||
</ul>
 | 
			
		||||
<p>See code & instructions for connecting at <a href="https://github.com/golang/net/tree/master/http2">https://github.com/golang/net/tree/master/http2</a>.</p>
 | 
			
		||||
 | 
			
		||||
</body></html>`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func home(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.URL.Path != "/" {
 | 
			
		||||
		http.NotFound(w, r)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	io.WriteString(w, `<html>
 | 
			
		||||
<body>
 | 
			
		||||
<h1>Go + HTTP/2</h1>
 | 
			
		||||
 | 
			
		||||
<p>Welcome to <a href="https://golang.org/">the Go language</a>'s <a
 | 
			
		||||
href="https://http2.github.io/">HTTP/2</a> demo & interop server.</p>
 | 
			
		||||
 | 
			
		||||
<p>Congratulations, <b>you're using HTTP/2 right now</b>.</p>
 | 
			
		||||
 | 
			
		||||
<p>This server exists for others in the HTTP/2 community to test their HTTP/2 client implementations and point out flaws in our server.</p>
 | 
			
		||||
 | 
			
		||||
<p>
 | 
			
		||||
The code is at <a href="https://golang.org/x/net/http2">golang.org/x/net/http2</a> and
 | 
			
		||||
is used transparently by the Go standard library from Go 1.6 and later.
 | 
			
		||||
</p>
 | 
			
		||||
 | 
			
		||||
<p>Contact info: <i>bradfitz@golang.org</i>, or <a
 | 
			
		||||
href="https://golang.org/s/http2bug">file a bug</a>.</p>
 | 
			
		||||
 | 
			
		||||
<h2>Handlers for testing</h2>
 | 
			
		||||
<ul>
 | 
			
		||||
  <li>GET <a href="/reqinfo">/reqinfo</a> to dump the request + headers received</li>
 | 
			
		||||
  <li>GET <a href="/clockstream">/clockstream</a> streams the current time every second</li>
 | 
			
		||||
  <li>GET <a href="/gophertiles">/gophertiles</a> to see a page with a bunch of images</li>
 | 
			
		||||
  <li>GET <a href="/serverpush">/serverpush</a> to see a page with server push</li>
 | 
			
		||||
  <li>GET <a href="/file/gopher.png">/file/gopher.png</a> for a small file (does If-Modified-Since, Content-Range, etc)</li>
 | 
			
		||||
  <li>GET <a href="/file/go.src.tar.gz">/file/go.src.tar.gz</a> for a larger file (~10 MB)</li>
 | 
			
		||||
  <li>GET <a href="/redirect">/redirect</a> to redirect back to / (this page)</li>
 | 
			
		||||
  <li>GET <a href="/goroutines">/goroutines</a> to see all active goroutines in this server</li>
 | 
			
		||||
  <li>PUT something to <a href="/crc32">/crc32</a> to get a count of number of bytes and its CRC-32</li>
 | 
			
		||||
  <li>PUT something to <a href="/ECHO">/ECHO</a> and it will be streamed back to you capitalized</li>
 | 
			
		||||
</ul>
 | 
			
		||||
 | 
			
		||||
</body></html>`)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func reqInfoHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	w.Header().Set("Content-Type", "text/plain")
 | 
			
		||||
	fmt.Fprintf(w, "Method: %s\n", r.Method)
 | 
			
		||||
	fmt.Fprintf(w, "Protocol: %s\n", r.Proto)
 | 
			
		||||
	fmt.Fprintf(w, "Host: %s\n", r.Host)
 | 
			
		||||
	fmt.Fprintf(w, "RemoteAddr: %s\n", r.RemoteAddr)
 | 
			
		||||
	fmt.Fprintf(w, "RequestURI: %q\n", r.RequestURI)
 | 
			
		||||
	fmt.Fprintf(w, "URL: %#v\n", r.URL)
 | 
			
		||||
	fmt.Fprintf(w, "Body.ContentLength: %d (-1 means unknown)\n", r.ContentLength)
 | 
			
		||||
	fmt.Fprintf(w, "Close: %v (relevant for HTTP/1 only)\n", r.Close)
 | 
			
		||||
	fmt.Fprintf(w, "TLS: %#v\n", r.TLS)
 | 
			
		||||
	fmt.Fprintf(w, "\nHeaders:\n")
 | 
			
		||||
	r.Header.Write(w)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func crcHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.Method != "PUT" {
 | 
			
		||||
		http.Error(w, "PUT required.", 400)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	crc := crc32.NewIEEE()
 | 
			
		||||
	n, err := io.Copy(crc, r.Body)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		w.Header().Set("Content-Type", "text/plain")
 | 
			
		||||
		fmt.Fprintf(w, "bytes=%d, CRC32=%x", n, crc.Sum(nil))
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type capitalizeReader struct {
 | 
			
		||||
	r io.Reader
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (cr capitalizeReader) Read(p []byte) (n int, err error) {
 | 
			
		||||
	n, err = cr.r.Read(p)
 | 
			
		||||
	for i, b := range p[:n] {
 | 
			
		||||
		if b >= 'a' && b <= 'z' {
 | 
			
		||||
			p[i] = b - ('a' - 'A')
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type flushWriter struct {
 | 
			
		||||
	w io.Writer
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (fw flushWriter) Write(p []byte) (n int, err error) {
 | 
			
		||||
	n, err = fw.w.Write(p)
 | 
			
		||||
	if f, ok := fw.w.(http.Flusher); ok {
 | 
			
		||||
		f.Flush()
 | 
			
		||||
	}
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func echoCapitalHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	if r.Method != "PUT" {
 | 
			
		||||
		http.Error(w, "PUT required.", 400)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	io.Copy(flushWriter{w}, capitalizeReader{r.Body})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	fsGrp   singleflight.Group
 | 
			
		||||
	fsMu    sync.Mutex // guards fsCache
 | 
			
		||||
	fsCache = map[string]http.Handler{}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// fileServer returns a file-serving handler that proxies URL.
 | 
			
		||||
// It lazily fetches URL on the first access and caches its contents forever.
 | 
			
		||||
func fileServer(url string, latency time.Duration) http.Handler {
 | 
			
		||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		if latency > 0 {
 | 
			
		||||
			time.Sleep(latency)
 | 
			
		||||
		}
 | 
			
		||||
		hi, err := fsGrp.Do(url, func() (interface{}, error) {
 | 
			
		||||
			fsMu.Lock()
 | 
			
		||||
			if h, ok := fsCache[url]; ok {
 | 
			
		||||
				fsMu.Unlock()
 | 
			
		||||
				return h, nil
 | 
			
		||||
			}
 | 
			
		||||
			fsMu.Unlock()
 | 
			
		||||
 | 
			
		||||
			res, err := http.Get(url)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
			defer res.Body.Close()
 | 
			
		||||
			slurp, err := ioutil.ReadAll(res.Body)
 | 
			
		||||
			if err != nil {
 | 
			
		||||
				return nil, err
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			modTime := time.Now()
 | 
			
		||||
			var h http.Handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
				http.ServeContent(w, r, path.Base(url), modTime, bytes.NewReader(slurp))
 | 
			
		||||
			})
 | 
			
		||||
			fsMu.Lock()
 | 
			
		||||
			fsCache[url] = h
 | 
			
		||||
			fsMu.Unlock()
 | 
			
		||||
			return h, nil
 | 
			
		||||
		})
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			http.Error(w, err.Error(), 500)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		hi.(http.Handler).ServeHTTP(w, r)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func clockStreamHandler(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
	clientGone := w.(http.CloseNotifier).CloseNotify()
 | 
			
		||||
	w.Header().Set("Content-Type", "text/plain")
 | 
			
		||||
	ticker := time.NewTicker(1 * time.Second)
 | 
			
		||||
	defer ticker.Stop()
 | 
			
		||||
	fmt.Fprintf(w, "# ~1KB of junk to force browsers to start rendering immediately: \n")
 | 
			
		||||
	io.WriteString(w, strings.Repeat("# xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n", 13))
 | 
			
		||||
 | 
			
		||||
	for {
 | 
			
		||||
		fmt.Fprintf(w, "%v\n", time.Now())
 | 
			
		||||
		w.(http.Flusher).Flush()
 | 
			
		||||
		select {
 | 
			
		||||
		case <-ticker.C:
 | 
			
		||||
		case <-clientGone:
 | 
			
		||||
			log.Printf("Client %v disconnected from the clock", r.RemoteAddr)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func registerHandlers() {
 | 
			
		||||
	tiles := newGopherTilesHandler()
 | 
			
		||||
	push := newPushHandler()
 | 
			
		||||
 | 
			
		||||
	mux2 := http.NewServeMux()
 | 
			
		||||
	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		switch {
 | 
			
		||||
		case r.URL.Path == "/gophertiles":
 | 
			
		||||
			tiles.ServeHTTP(w, r) // allow HTTP/2 + HTTP/1.x
 | 
			
		||||
			return
 | 
			
		||||
		case strings.HasPrefix(r.URL.Path, "/serverpush"):
 | 
			
		||||
			push.ServeHTTP(w, r) // allow HTTP/2 + HTTP/1.x
 | 
			
		||||
			return
 | 
			
		||||
		case r.TLS == nil: // do not allow HTTP/1.x for anything else
 | 
			
		||||
			http.Redirect(w, r, "https://"+httpsHost()+"/", http.StatusFound)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		if r.ProtoMajor == 1 {
 | 
			
		||||
			if r.URL.Path == "/reqinfo" {
 | 
			
		||||
				reqInfoHandler(w, r)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
			homeOldHTTP(w, r)
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		mux2.ServeHTTP(w, r)
 | 
			
		||||
	})
 | 
			
		||||
	mux2.HandleFunc("/", home)
 | 
			
		||||
	mux2.Handle("/file/gopher.png", fileServer("https://golang.org/doc/gopher/frontpage.png", 0))
 | 
			
		||||
	mux2.Handle("/file/go.src.tar.gz", fileServer("https://storage.googleapis.com/golang/go1.4.1.src.tar.gz", 0))
 | 
			
		||||
	mux2.HandleFunc("/reqinfo", reqInfoHandler)
 | 
			
		||||
	mux2.HandleFunc("/crc32", crcHandler)
 | 
			
		||||
	mux2.HandleFunc("/ECHO", echoCapitalHandler)
 | 
			
		||||
	mux2.HandleFunc("/clockstream", clockStreamHandler)
 | 
			
		||||
	mux2.Handle("/gophertiles", tiles)
 | 
			
		||||
	mux2.HandleFunc("/redirect", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		http.Redirect(w, r, "/", http.StatusFound)
 | 
			
		||||
	})
 | 
			
		||||
	stripHomedir := regexp.MustCompile(`/(Users|home)/\w+`)
 | 
			
		||||
	mux2.HandleFunc("/goroutines", func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		w.Header().Set("Content-Type", "text/plain; charset=utf-8")
 | 
			
		||||
		buf := make([]byte, 2<<20)
 | 
			
		||||
		w.Write(stripHomedir.ReplaceAll(buf[:runtime.Stack(buf, true)], nil))
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var pushResources = map[string]http.Handler{
 | 
			
		||||
	"/serverpush/static/jquery.min.js": fileServer("https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js", 100*time.Millisecond),
 | 
			
		||||
	"/serverpush/static/godocs.js":     fileServer("https://golang.org/lib/godoc/godocs.js", 100*time.Millisecond),
 | 
			
		||||
	"/serverpush/static/playground.js": fileServer("https://golang.org/lib/godoc/playground.js", 100*time.Millisecond),
 | 
			
		||||
	"/serverpush/static/style.css":     fileServer("https://golang.org/lib/godoc/style.css", 100*time.Millisecond),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newPushHandler() http.Handler {
 | 
			
		||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		for path, handler := range pushResources {
 | 
			
		||||
			if r.URL.Path == path {
 | 
			
		||||
				handler.ServeHTTP(w, r)
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		cacheBust := time.Now().UnixNano()
 | 
			
		||||
		if pusher, ok := w.(http.Pusher); ok {
 | 
			
		||||
			for path := range pushResources {
 | 
			
		||||
				url := fmt.Sprintf("%s?%d", path, cacheBust)
 | 
			
		||||
				if err := pusher.Push(url, nil); err != nil {
 | 
			
		||||
					log.Printf("Failed to push %v: %v", path, err)
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		time.Sleep(100 * time.Millisecond) // fake network latency + parsing time
 | 
			
		||||
		if err := pushTmpl.Execute(w, struct {
 | 
			
		||||
			CacheBust int64
 | 
			
		||||
			HTTPSHost string
 | 
			
		||||
			HTTPHost  string
 | 
			
		||||
		}{
 | 
			
		||||
			CacheBust: cacheBust,
 | 
			
		||||
			HTTPSHost: httpsHost(),
 | 
			
		||||
			HTTPHost:  httpHost(),
 | 
			
		||||
		}); err != nil {
 | 
			
		||||
			log.Printf("Executing server push template: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func newGopherTilesHandler() http.Handler {
 | 
			
		||||
	const gopherURL = "https://blog.golang.org/go-programming-language-turns-two_gophers.jpg"
 | 
			
		||||
	res, err := http.Get(gopherURL)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if res.StatusCode != 200 {
 | 
			
		||||
		log.Fatalf("Error fetching %s: %v", gopherURL, res.Status)
 | 
			
		||||
	}
 | 
			
		||||
	slurp, err := ioutil.ReadAll(res.Body)
 | 
			
		||||
	res.Body.Close()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	im, err := jpeg.Decode(bytes.NewReader(slurp))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if len(slurp) > 1024 {
 | 
			
		||||
			slurp = slurp[:1024]
 | 
			
		||||
		}
 | 
			
		||||
		log.Fatalf("Failed to decode gopher image: %v (got %q)", err, slurp)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	type subImager interface {
 | 
			
		||||
		SubImage(image.Rectangle) image.Image
 | 
			
		||||
	}
 | 
			
		||||
	const tileSize = 32
 | 
			
		||||
	xt := im.Bounds().Max.X / tileSize
 | 
			
		||||
	yt := im.Bounds().Max.Y / tileSize
 | 
			
		||||
	var tile [][][]byte // y -> x -> jpeg bytes
 | 
			
		||||
	for yi := 0; yi < yt; yi++ {
 | 
			
		||||
		var row [][]byte
 | 
			
		||||
		for xi := 0; xi < xt; xi++ {
 | 
			
		||||
			si := im.(subImager).SubImage(image.Rectangle{
 | 
			
		||||
				Min: image.Point{xi * tileSize, yi * tileSize},
 | 
			
		||||
				Max: image.Point{(xi + 1) * tileSize, (yi + 1) * tileSize},
 | 
			
		||||
			})
 | 
			
		||||
			buf := new(bytes.Buffer)
 | 
			
		||||
			if err := jpeg.Encode(buf, si, &jpeg.Options{Quality: 90}); err != nil {
 | 
			
		||||
				log.Fatal(err)
 | 
			
		||||
			}
 | 
			
		||||
			row = append(row, buf.Bytes())
 | 
			
		||||
		}
 | 
			
		||||
		tile = append(tile, row)
 | 
			
		||||
	}
 | 
			
		||||
	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 | 
			
		||||
		ms, _ := strconv.Atoi(r.FormValue("latency"))
 | 
			
		||||
		const nanosPerMilli = 1e6
 | 
			
		||||
		if r.FormValue("x") != "" {
 | 
			
		||||
			x, _ := strconv.Atoi(r.FormValue("x"))
 | 
			
		||||
			y, _ := strconv.Atoi(r.FormValue("y"))
 | 
			
		||||
			if ms <= 1000 {
 | 
			
		||||
				time.Sleep(time.Duration(ms) * nanosPerMilli)
 | 
			
		||||
			}
 | 
			
		||||
			if x >= 0 && x < xt && y >= 0 && y < yt {
 | 
			
		||||
				http.ServeContent(w, r, "", time.Time{}, bytes.NewReader(tile[y][x]))
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		io.WriteString(w, "<html><body onload='showtimes()'>")
 | 
			
		||||
		fmt.Fprintf(w, "A grid of %d tiled images is below. Compare:<p>", xt*yt)
 | 
			
		||||
		for _, ms := range []int{0, 30, 200, 1000} {
 | 
			
		||||
			d := time.Duration(ms) * nanosPerMilli
 | 
			
		||||
			fmt.Fprintf(w, "[<a href='https://%s/gophertiles?latency=%d'>HTTP/2, %v latency</a>] [<a href='http://%s/gophertiles?latency=%d'>HTTP/1, %v latency</a>]<br>\n",
 | 
			
		||||
				httpsHost(), ms, d,
 | 
			
		||||
				httpHost(), ms, d,
 | 
			
		||||
			)
 | 
			
		||||
		}
 | 
			
		||||
		io.WriteString(w, "<p>\n")
 | 
			
		||||
		cacheBust := time.Now().UnixNano()
 | 
			
		||||
		for y := 0; y < yt; y++ {
 | 
			
		||||
			for x := 0; x < xt; x++ {
 | 
			
		||||
				fmt.Fprintf(w, "<img width=%d height=%d src='/gophertiles?x=%d&y=%d&cachebust=%d&latency=%d'>",
 | 
			
		||||
					tileSize, tileSize, x, y, cacheBust, ms)
 | 
			
		||||
			}
 | 
			
		||||
			io.WriteString(w, "<br/>\n")
 | 
			
		||||
		}
 | 
			
		||||
		io.WriteString(w, `<p><div id='loadtimes'></div></p>
 | 
			
		||||
<script>
 | 
			
		||||
function showtimes() {
 | 
			
		||||
	var times = 'Times from connection start:<br>'
 | 
			
		||||
	times += 'DOM loaded: ' + (window.performance.timing.domContentLoadedEventEnd - window.performance.timing.connectStart) + 'ms<br>'
 | 
			
		||||
	times += 'DOM complete (images loaded): ' + (window.performance.timing.domComplete - window.performance.timing.connectStart) + 'ms<br>'
 | 
			
		||||
	document.getElementById('loadtimes').innerHTML = times
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
<hr><a href='/'><< Back to Go HTTP/2 demo server</a></body></html>`)
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func httpsHost() string {
 | 
			
		||||
	if *hostHTTPS != "" {
 | 
			
		||||
		return *hostHTTPS
 | 
			
		||||
	}
 | 
			
		||||
	if v := *httpsAddr; strings.HasPrefix(v, ":") {
 | 
			
		||||
		return "localhost" + v
 | 
			
		||||
	} else {
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func httpHost() string {
 | 
			
		||||
	if *hostHTTP != "" {
 | 
			
		||||
		return *hostHTTP
 | 
			
		||||
	}
 | 
			
		||||
	if v := *httpAddr; strings.HasPrefix(v, ":") {
 | 
			
		||||
		return "localhost" + v
 | 
			
		||||
	} else {
 | 
			
		||||
		return v
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveProdTLS() error {
 | 
			
		||||
	const cacheDir = "/var/cache/autocert"
 | 
			
		||||
	if err := os.MkdirAll(cacheDir, 0700); err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	m := autocert.Manager{
 | 
			
		||||
		Cache:      autocert.DirCache(cacheDir),
 | 
			
		||||
		Prompt:     autocert.AcceptTOS,
 | 
			
		||||
		HostPolicy: autocert.HostWhitelist("http2.golang.org"),
 | 
			
		||||
	}
 | 
			
		||||
	srv := &http.Server{
 | 
			
		||||
		TLSConfig: &tls.Config{
 | 
			
		||||
			GetCertificate: m.GetCertificate,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
	http2.ConfigureServer(srv, &http2.Server{
 | 
			
		||||
		NewWriteScheduler: func() http2.WriteScheduler {
 | 
			
		||||
			return http2.NewPriorityWriteScheduler(nil)
 | 
			
		||||
		},
 | 
			
		||||
	})
 | 
			
		||||
	ln, err := net.Listen("tcp", ":443")
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return srv.Serve(tls.NewListener(tcpKeepAliveListener{ln.(*net.TCPListener)}, srv.TLSConfig))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tcpKeepAliveListener struct {
 | 
			
		||||
	*net.TCPListener
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (ln tcpKeepAliveListener) Accept() (c net.Conn, err error) {
 | 
			
		||||
	tc, err := ln.AcceptTCP()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	tc.SetKeepAlive(true)
 | 
			
		||||
	tc.SetKeepAlivePeriod(3 * time.Minute)
 | 
			
		||||
	return tc, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func serveProd() error {
 | 
			
		||||
	errc := make(chan error, 2)
 | 
			
		||||
	go func() { errc <- http.ListenAndServe(":80", nil) }()
 | 
			
		||||
	go func() { errc <- serveProdTLS() }()
 | 
			
		||||
	return <-errc
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const idleTimeout = 5 * time.Minute
 | 
			
		||||
const activeTimeout = 10 * time.Minute
 | 
			
		||||
 | 
			
		||||
// TODO: put this into the standard library and actually send
 | 
			
		||||
// PING frames and GOAWAY, etc: golang.org/issue/14204
 | 
			
		||||
func idleTimeoutHook() func(net.Conn, http.ConnState) {
 | 
			
		||||
	var mu sync.Mutex
 | 
			
		||||
	m := map[net.Conn]*time.Timer{}
 | 
			
		||||
	return func(c net.Conn, cs http.ConnState) {
 | 
			
		||||
		mu.Lock()
 | 
			
		||||
		defer mu.Unlock()
 | 
			
		||||
		if t, ok := m[c]; ok {
 | 
			
		||||
			delete(m, c)
 | 
			
		||||
			t.Stop()
 | 
			
		||||
		}
 | 
			
		||||
		var d time.Duration
 | 
			
		||||
		switch cs {
 | 
			
		||||
		case http.StateNew, http.StateIdle:
 | 
			
		||||
			d = idleTimeout
 | 
			
		||||
		case http.StateActive:
 | 
			
		||||
			d = activeTimeout
 | 
			
		||||
		default:
 | 
			
		||||
			return
 | 
			
		||||
		}
 | 
			
		||||
		m[c] = time.AfterFunc(d, func() {
 | 
			
		||||
			log.Printf("closing idle conn %v after %v", c.RemoteAddr(), d)
 | 
			
		||||
			go c.Close()
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	var srv http.Server
 | 
			
		||||
	flag.BoolVar(&http2.VerboseLogs, "verbose", false, "Verbose HTTP/2 debugging.")
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	srv.Addr = *httpsAddr
 | 
			
		||||
	srv.ConnState = idleTimeoutHook()
 | 
			
		||||
 | 
			
		||||
	registerHandlers()
 | 
			
		||||
 | 
			
		||||
	if *prod {
 | 
			
		||||
		*hostHTTP = "http2.golang.org"
 | 
			
		||||
		*hostHTTPS = "http2.golang.org"
 | 
			
		||||
		log.Fatal(serveProd())
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	url := "https://" + httpsHost() + "/"
 | 
			
		||||
	log.Printf("Listening on " + url)
 | 
			
		||||
	http2.ConfigureServer(&srv, &http2.Server{})
 | 
			
		||||
 | 
			
		||||
	if *httpAddr != "" {
 | 
			
		||||
		go func() {
 | 
			
		||||
			log.Printf("Listening on http://" + httpHost() + "/ (for unencrypted HTTP/1)")
 | 
			
		||||
			log.Fatal(http.ListenAndServe(*httpAddr, nil))
 | 
			
		||||
		}()
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	go func() {
 | 
			
		||||
		log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key"))
 | 
			
		||||
	}()
 | 
			
		||||
	select {}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										302
									
								
								vendor/golang.org/x/net/http2/h2demo/launch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										302
									
								
								vendor/golang.org/x/net/http2/h2demo/launch.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,302 @@
 | 
			
		||||
// Copyright 2014 The Go Authors. All rights reserved.
 | 
			
		||||
// Use of this source code is governed by a BSD-style
 | 
			
		||||
// license that can be found in the LICENSE file.
 | 
			
		||||
 | 
			
		||||
// +build ignore
 | 
			
		||||
 | 
			
		||||
package main
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bufio"
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"encoding/json"
 | 
			
		||||
	"flag"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"io"
 | 
			
		||||
	"io/ioutil"
 | 
			
		||||
	"log"
 | 
			
		||||
	"net/http"
 | 
			
		||||
	"os"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	"golang.org/x/oauth2"
 | 
			
		||||
	"golang.org/x/oauth2/google"
 | 
			
		||||
	compute "google.golang.org/api/compute/v1"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var (
 | 
			
		||||
	proj     = flag.String("project", "symbolic-datum-552", "name of Project")
 | 
			
		||||
	zone     = flag.String("zone", "us-central1-a", "GCE zone")
 | 
			
		||||
	mach     = flag.String("machinetype", "n1-standard-1", "Machine type")
 | 
			
		||||
	instName = flag.String("instance_name", "http2-demo", "Name of VM instance.")
 | 
			
		||||
	sshPub   = flag.String("ssh_public_key", "", "ssh public key file to authorize. Can modify later in Google's web UI anyway.")
 | 
			
		||||
	staticIP = flag.String("static_ip", "130.211.116.44", "Static IP to use. If empty, automatic.")
 | 
			
		||||
 | 
			
		||||
	writeObject  = flag.String("write_object", "", "If non-empty, a VM isn't created and the flag value is Google Cloud Storage bucket/object to write. The contents from stdin.")
 | 
			
		||||
	publicObject = flag.Bool("write_object_is_public", false, "Whether the object created by --write_object should be public.")
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func readFile(v string) string {
 | 
			
		||||
	slurp, err := ioutil.ReadFile(v)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Error reading %s: %v", v, err)
 | 
			
		||||
	}
 | 
			
		||||
	return strings.TrimSpace(string(slurp))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var config = &oauth2.Config{
 | 
			
		||||
	// The client-id and secret should be for an "Installed Application" when using
 | 
			
		||||
	// the CLI. Later we'll use a web application with a callback.
 | 
			
		||||
	ClientID:     readFile("client-id.dat"),
 | 
			
		||||
	ClientSecret: readFile("client-secret.dat"),
 | 
			
		||||
	Endpoint:     google.Endpoint,
 | 
			
		||||
	Scopes: []string{
 | 
			
		||||
		compute.DevstorageFullControlScope,
 | 
			
		||||
		compute.ComputeScope,
 | 
			
		||||
		"https://www.googleapis.com/auth/sqlservice",
 | 
			
		||||
		"https://www.googleapis.com/auth/sqlservice.admin",
 | 
			
		||||
	},
 | 
			
		||||
	RedirectURL: "urn:ietf:wg:oauth:2.0:oob",
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const baseConfig = `#cloud-config
 | 
			
		||||
coreos:
 | 
			
		||||
  units:
 | 
			
		||||
    - name: h2demo.service
 | 
			
		||||
      command: start
 | 
			
		||||
      content: |
 | 
			
		||||
        [Unit]
 | 
			
		||||
        Description=HTTP2 Demo
 | 
			
		||||
        
 | 
			
		||||
        [Service]
 | 
			
		||||
        ExecStartPre=/bin/bash -c 'mkdir -p /opt/bin && curl -s -o /opt/bin/h2demo http://storage.googleapis.com/http2-demo-server-tls/h2demo && chmod +x /opt/bin/h2demo'
 | 
			
		||||
        ExecStart=/opt/bin/h2demo --prod
 | 
			
		||||
        RestartSec=5s
 | 
			
		||||
        Restart=always
 | 
			
		||||
        Type=simple
 | 
			
		||||
        
 | 
			
		||||
        [Install]
 | 
			
		||||
        WantedBy=multi-user.target
 | 
			
		||||
`
 | 
			
		||||
 | 
			
		||||
func main() {
 | 
			
		||||
	flag.Parse()
 | 
			
		||||
	if *proj == "" {
 | 
			
		||||
		log.Fatalf("Missing --project flag")
 | 
			
		||||
	}
 | 
			
		||||
	prefix := "https://www.googleapis.com/compute/v1/projects/" + *proj
 | 
			
		||||
	machType := prefix + "/zones/" + *zone + "/machineTypes/" + *mach
 | 
			
		||||
 | 
			
		||||
	const tokenFileName = "token.dat"
 | 
			
		||||
	tokenFile := tokenCacheFile(tokenFileName)
 | 
			
		||||
	tokenSource := oauth2.ReuseTokenSource(nil, tokenFile)
 | 
			
		||||
	token, err := tokenSource.Token()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		if *writeObject != "" {
 | 
			
		||||
			log.Fatalf("Can't use --write_object without a valid token.dat file already cached.")
 | 
			
		||||
		}
 | 
			
		||||
		log.Printf("Error getting token from %s: %v", tokenFileName, err)
 | 
			
		||||
		log.Printf("Get auth code from %v", config.AuthCodeURL("my-state"))
 | 
			
		||||
		fmt.Print("\nEnter auth code: ")
 | 
			
		||||
		sc := bufio.NewScanner(os.Stdin)
 | 
			
		||||
		sc.Scan()
 | 
			
		||||
		authCode := strings.TrimSpace(sc.Text())
 | 
			
		||||
		token, err = config.Exchange(oauth2.NoContext, authCode)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatalf("Error exchanging auth code for a token: %v", err)
 | 
			
		||||
		}
 | 
			
		||||
		if err := tokenFile.WriteToken(token); err != nil {
 | 
			
		||||
			log.Fatalf("Error writing to %s: %v", tokenFileName, err)
 | 
			
		||||
		}
 | 
			
		||||
		tokenSource = oauth2.ReuseTokenSource(token, nil)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	oauthClient := oauth2.NewClient(oauth2.NoContext, tokenSource)
 | 
			
		||||
 | 
			
		||||
	if *writeObject != "" {
 | 
			
		||||
		writeCloudStorageObject(oauthClient)
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	computeService, _ := compute.New(oauthClient)
 | 
			
		||||
 | 
			
		||||
	natIP := *staticIP
 | 
			
		||||
	if natIP == "" {
 | 
			
		||||
		// Try to find it by name.
 | 
			
		||||
		aggAddrList, err := computeService.Addresses.AggregatedList(*proj).Do()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatal(err)
 | 
			
		||||
		}
 | 
			
		||||
		// http://godoc.org/code.google.com/p/google-api-go-client/compute/v1#AddressAggregatedList
 | 
			
		||||
	IPLoop:
 | 
			
		||||
		for _, asl := range aggAddrList.Items {
 | 
			
		||||
			for _, addr := range asl.Addresses {
 | 
			
		||||
				if addr.Name == *instName+"-ip" && addr.Status == "RESERVED" {
 | 
			
		||||
					natIP = addr.Address
 | 
			
		||||
					break IPLoop
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	cloudConfig := baseConfig
 | 
			
		||||
	if *sshPub != "" {
 | 
			
		||||
		key := strings.TrimSpace(readFile(*sshPub))
 | 
			
		||||
		cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n    - %s\n", key)
 | 
			
		||||
	}
 | 
			
		||||
	if os.Getenv("USER") == "bradfitz" {
 | 
			
		||||
		cloudConfig += fmt.Sprintf("\nssh_authorized_keys:\n    - %s\n", "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEAwks9dwWKlRC+73gRbvYtVg0vdCwDSuIlyt4z6xa/YU/jTDynM4R4W10hm2tPjy8iR1k8XhDv4/qdxe6m07NjG/By1tkmGpm1mGwho4Pr5kbAAy/Qg+NLCSdAYnnE00FQEcFOC15GFVMOW2AzDGKisReohwH9eIzHPzdYQNPRWXE= bradfitz@papag.bradfitz.com")
 | 
			
		||||
	}
 | 
			
		||||
	const maxCloudConfig = 32 << 10 // per compute API docs
 | 
			
		||||
	if len(cloudConfig) > maxCloudConfig {
 | 
			
		||||
		log.Fatalf("cloud config length of %d bytes is over %d byte limit", len(cloudConfig), maxCloudConfig)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	instance := &compute.Instance{
 | 
			
		||||
		Name:        *instName,
 | 
			
		||||
		Description: "Go Builder",
 | 
			
		||||
		MachineType: machType,
 | 
			
		||||
		Disks:       []*compute.AttachedDisk{instanceDisk(computeService)},
 | 
			
		||||
		Tags: &compute.Tags{
 | 
			
		||||
			Items: []string{"http-server", "https-server"},
 | 
			
		||||
		},
 | 
			
		||||
		Metadata: &compute.Metadata{
 | 
			
		||||
			Items: []*compute.MetadataItems{
 | 
			
		||||
				{
 | 
			
		||||
					Key:   "user-data",
 | 
			
		||||
					Value: &cloudConfig,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		NetworkInterfaces: []*compute.NetworkInterface{
 | 
			
		||||
			{
 | 
			
		||||
				AccessConfigs: []*compute.AccessConfig{
 | 
			
		||||
					{
 | 
			
		||||
						Type:  "ONE_TO_ONE_NAT",
 | 
			
		||||
						Name:  "External NAT",
 | 
			
		||||
						NatIP: natIP,
 | 
			
		||||
					},
 | 
			
		||||
				},
 | 
			
		||||
				Network: prefix + "/global/networks/default",
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
		ServiceAccounts: []*compute.ServiceAccount{
 | 
			
		||||
			{
 | 
			
		||||
				Email: "default",
 | 
			
		||||
				Scopes: []string{
 | 
			
		||||
					compute.DevstorageFullControlScope,
 | 
			
		||||
					compute.ComputeScope,
 | 
			
		||||
				},
 | 
			
		||||
			},
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	log.Printf("Creating instance...")
 | 
			
		||||
	op, err := computeService.Instances.Insert(*proj, *zone, instance).Do()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Failed to create instance: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	opName := op.Name
 | 
			
		||||
	log.Printf("Created. Waiting on operation %v", opName)
 | 
			
		||||
OpLoop:
 | 
			
		||||
	for {
 | 
			
		||||
		time.Sleep(2 * time.Second)
 | 
			
		||||
		op, err := computeService.ZoneOperations.Get(*proj, *zone, opName).Do()
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			log.Fatalf("Failed to get op %s: %v", opName, err)
 | 
			
		||||
		}
 | 
			
		||||
		switch op.Status {
 | 
			
		||||
		case "PENDING", "RUNNING":
 | 
			
		||||
			log.Printf("Waiting on operation %v", opName)
 | 
			
		||||
			continue
 | 
			
		||||
		case "DONE":
 | 
			
		||||
			if op.Error != nil {
 | 
			
		||||
				for _, operr := range op.Error.Errors {
 | 
			
		||||
					log.Printf("Error: %+v", operr)
 | 
			
		||||
				}
 | 
			
		||||
				log.Fatalf("Failed to start.")
 | 
			
		||||
			}
 | 
			
		||||
			log.Printf("Success. %+v", op)
 | 
			
		||||
			break OpLoop
 | 
			
		||||
		default:
 | 
			
		||||
			log.Fatalf("Unknown status %q: %+v", op.Status, op)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	inst, err := computeService.Instances.Get(*proj, *zone, *instName).Do()
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatalf("Error getting instance after creation: %v", err)
 | 
			
		||||
	}
 | 
			
		||||
	ij, _ := json.MarshalIndent(inst, "", "    ")
 | 
			
		||||
	log.Printf("Instance: %s", ij)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func instanceDisk(svc *compute.Service) *compute.AttachedDisk {
 | 
			
		||||
	const imageURL = "https://www.googleapis.com/compute/v1/projects/coreos-cloud/global/images/coreos-stable-444-5-0-v20141016"
 | 
			
		||||
	diskName := *instName + "-disk"
 | 
			
		||||
 | 
			
		||||
	return &compute.AttachedDisk{
 | 
			
		||||
		AutoDelete: true,
 | 
			
		||||
		Boot:       true,
 | 
			
		||||
		Type:       "PERSISTENT",
 | 
			
		||||
		InitializeParams: &compute.AttachedDiskInitializeParams{
 | 
			
		||||
			DiskName:    diskName,
 | 
			
		||||
			SourceImage: imageURL,
 | 
			
		||||
			DiskSizeGb:  50,
 | 
			
		||||
		},
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func writeCloudStorageObject(httpClient *http.Client) {
 | 
			
		||||
	content := os.Stdin
 | 
			
		||||
	const maxSlurp = 1 << 20
 | 
			
		||||
	var buf bytes.Buffer
 | 
			
		||||
	n, err := io.CopyN(&buf, content, maxSlurp)
 | 
			
		||||
	if err != nil && err != io.EOF {
 | 
			
		||||
		log.Fatalf("Error reading from stdin: %v, %v", n, err)
 | 
			
		||||
	}
 | 
			
		||||
	contentType := http.DetectContentType(buf.Bytes())
 | 
			
		||||
 | 
			
		||||
	req, err := http.NewRequest("PUT", "https://storage.googleapis.com/"+*writeObject, io.MultiReader(&buf, content))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("x-goog-api-version", "2")
 | 
			
		||||
	if *publicObject {
 | 
			
		||||
		req.Header.Set("x-goog-acl", "public-read")
 | 
			
		||||
	}
 | 
			
		||||
	req.Header.Set("Content-Type", contentType)
 | 
			
		||||
	res, err := httpClient.Do(req)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		log.Fatal(err)
 | 
			
		||||
	}
 | 
			
		||||
	if res.StatusCode != 200 {
 | 
			
		||||
		res.Write(os.Stderr)
 | 
			
		||||
		log.Fatalf("Failed.")
 | 
			
		||||
	}
 | 
			
		||||
	log.Printf("Success.")
 | 
			
		||||
	os.Exit(0)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type tokenCacheFile string
 | 
			
		||||
 | 
			
		||||
func (f tokenCacheFile) Token() (*oauth2.Token, error) {
 | 
			
		||||
	slurp, err := ioutil.ReadFile(string(f))
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	t := new(oauth2.Token)
 | 
			
		||||
	if err := json.Unmarshal(slurp, t); err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return t, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func (f tokenCacheFile) WriteToken(t *oauth2.Token) error {
 | 
			
		||||
	jt, err := json.Marshal(t)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return err
 | 
			
		||||
	}
 | 
			
		||||
	return ioutil.WriteFile(string(f), jt, 0600)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/net/http2/h2demo/rootCA.key
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/net/http2/h2demo/rootCA.key
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEowIBAAKCAQEAt5fAjp4fTcekWUTfzsp0kyih1OYbsGL0KX1eRbSSR8Od0+9Q
 | 
			
		||||
62Hyny+GFwMTb4A/KU8mssoHvcceSAAbwfbxFK/+s51TobqUnORZrOoTZjkUygby
 | 
			
		||||
XDSK99YBbcR1Pip8vwMTm4XKuLtCigeBBdjjAQdgUO28LENGlsMnmeYkJfODVGnV
 | 
			
		||||
mr5Ltb9ANA8IKyTfsnHJ4iOCS/PlPbUj2q7YnoVLposUBMlgUb/CykX3mOoLb4yJ
 | 
			
		||||
JQyA/iST6ZxiIEj36D4yWZ5lg7YJl+UiiBQHGCnPdGyipqV06ex0heYWcaiW8LWZ
 | 
			
		||||
SUQ93jQ+WVCH8hT7DQO1dmsvUmXlq/JeAlwQ/QIDAQABAoIBAFFHV7JMAqPWnMYA
 | 
			
		||||
nezY6J81v9+XN+7xABNWM2Q8uv4WdksbigGLTXR3/680Z2hXqJ7LMeC5XJACFT/e
 | 
			
		||||
/Gr0vmpgOCygnCPfjGehGKpavtfksXV3edikUlnCXsOP1C//c1bFL+sMYmFCVgTx
 | 
			
		||||
qYdDK8yKzXNGrKYT6q5YG7IglyRNV1rsQa8lM/5taFYiD1Ck/3tQi3YIq8Lcuser
 | 
			
		||||
hrxsMABcQ6mi+EIvG6Xr4mfJug0dGJMHG4RG1UGFQn6RXrQq2+q53fC8ZbVUSi0j
 | 
			
		||||
NQ918aKFzktwv+DouKU0ME4I9toks03gM860bAL7zCbKGmwR3hfgX/TqzVCWpG9E
 | 
			
		||||
LDVfvekCgYEA8fk9N53jbBRmULUGEf4qWypcLGiZnNU0OeXWpbPV9aa3H0VDytA7
 | 
			
		||||
8fCN2dPAVDPqlthMDdVe983NCNwp2Yo8ZimDgowyIAKhdC25s1kejuaiH9OAPj3c
 | 
			
		||||
0f8KbriYX4n8zNHxFwK6Ae3pQ6EqOLJVCUsziUaZX9nyKY5aZlyX6xcCgYEAwjws
 | 
			
		||||
K62PjC64U5wYddNLp+kNdJ4edx+a7qBb3mEgPvSFT2RO3/xafJyG8kQB30Mfstjd
 | 
			
		||||
bRxyUV6N0vtX1zA7VQtRUAvfGCecpMo+VQZzcHXKzoRTnQ7eZg4Lmj5fQ9tOAKAo
 | 
			
		||||
QCVBoSW/DI4PZL26CAMDcAba4Pa22ooLapoRIQsCgYA6pIfkkbxLNkpxpt2YwLtt
 | 
			
		||||
Kr/590O7UaR9n6k8sW/aQBRDXNsILR1KDl2ifAIxpf9lnXgZJiwE7HiTfCAcW7c1
 | 
			
		||||
nzwDCI0hWuHcMTS/NYsFYPnLsstyyjVZI3FY0h4DkYKV9Q9z3zJLQ2hz/nwoD3gy
 | 
			
		||||
b2pHC7giFcTts1VPV4Nt8wKBgHeFn4ihHJweg76vZz3Z78w7VNRWGFklUalVdDK7
 | 
			
		||||
gaQ7w2y/ROn/146mo0OhJaXFIFRlrpvdzVrU3GDf2YXJYDlM5ZRkObwbZADjksev
 | 
			
		||||
WInzcgDy3KDg7WnPasRXbTfMU4t/AkW2p1QKbi3DnSVYuokDkbH2Beo45vxDxhKr
 | 
			
		||||
C69RAoGBAIyo3+OJenoZmoNzNJl2WPW5MeBUzSh8T/bgyjFTdqFHF5WiYRD/lfHj
 | 
			
		||||
x9Glyw2nutuT4hlOqHvKhgTYdDMsF2oQ72fe3v8Q5FU7FuKndNPEAyvKNXZaShVA
 | 
			
		||||
hnlhv5DjXKb0wFWnt5PCCiQLtzG0yyHaITrrEme7FikkIcTxaX/Y
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										26
									
								
								vendor/golang.org/x/net/http2/h2demo/rootCA.pem
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										26
									
								
								vendor/golang.org/x/net/http2/h2demo/rootCA.pem
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,26 @@
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIEWjCCA0KgAwIBAgIJALfRlWsI8YQHMA0GCSqGSIb3DQEBBQUAMHsxCzAJBgNV
 | 
			
		||||
BAYTAlVTMQswCQYDVQQIEwJDQTEWMBQGA1UEBxMNU2FuIEZyYW5jaXNjbzEUMBIG
 | 
			
		||||
A1UEChMLQnJhZGZpdHppbmMxEjAQBgNVBAMTCWxvY2FsaG9zdDEdMBsGCSqGSIb3
 | 
			
		||||
DQEJARYOYnJhZEBkYW5nYS5jb20wHhcNMTQwNzE1MjA0NjA1WhcNMTcwNTA0MjA0
 | 
			
		||||
NjA1WjB7MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBG
 | 
			
		||||
cmFuY2lzY28xFDASBgNVBAoTC0JyYWRmaXR6aW5jMRIwEAYDVQQDEwlsb2NhbGhv
 | 
			
		||||
c3QxHTAbBgkqhkiG9w0BCQEWDmJyYWRAZGFuZ2EuY29tMIIBIjANBgkqhkiG9w0B
 | 
			
		||||
AQEFAAOCAQ8AMIIBCgKCAQEAt5fAjp4fTcekWUTfzsp0kyih1OYbsGL0KX1eRbSS
 | 
			
		||||
R8Od0+9Q62Hyny+GFwMTb4A/KU8mssoHvcceSAAbwfbxFK/+s51TobqUnORZrOoT
 | 
			
		||||
ZjkUygbyXDSK99YBbcR1Pip8vwMTm4XKuLtCigeBBdjjAQdgUO28LENGlsMnmeYk
 | 
			
		||||
JfODVGnVmr5Ltb9ANA8IKyTfsnHJ4iOCS/PlPbUj2q7YnoVLposUBMlgUb/CykX3
 | 
			
		||||
mOoLb4yJJQyA/iST6ZxiIEj36D4yWZ5lg7YJl+UiiBQHGCnPdGyipqV06ex0heYW
 | 
			
		||||
caiW8LWZSUQ93jQ+WVCH8hT7DQO1dmsvUmXlq/JeAlwQ/QIDAQABo4HgMIHdMB0G
 | 
			
		||||
A1UdDgQWBBRcAROthS4P4U7vTfjByC569R7E6DCBrQYDVR0jBIGlMIGigBRcAROt
 | 
			
		||||
hS4P4U7vTfjByC569R7E6KF/pH0wezELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNB
 | 
			
		||||
MRYwFAYDVQQHEw1TYW4gRnJhbmNpc2NvMRQwEgYDVQQKEwtCcmFkZml0emluYzES
 | 
			
		||||
MBAGA1UEAxMJbG9jYWxob3N0MR0wGwYJKoZIhvcNAQkBFg5icmFkQGRhbmdhLmNv
 | 
			
		||||
bYIJALfRlWsI8YQHMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAG6h
 | 
			
		||||
U9f9sNH0/6oBbGGy2EVU0UgITUQIrFWo9rFkrW5k/XkDjQm+3lzjT0iGR4IxE/Ao
 | 
			
		||||
eU6sQhua7wrWeFEn47GL98lnCsJdD7oZNhFmQ95Tb/LnDUjs5Yj9brP0NWzXfYU4
 | 
			
		||||
UK2ZnINJRcJpB8iRCaCxE8DdcUF0XqIEq6pA272snoLmiXLMvNl3kYEdm+je6voD
 | 
			
		||||
58SNVEUsztzQyXmJEhCpwVI0A6QCjzXj+qvpmw3ZZHi8JwXei8ZZBLTSFBki8Z7n
 | 
			
		||||
sH9BBH38/SzUmAN4QHSPy1gjqm00OAE8NaYDkh/bzE4d7mLGGMWp/WE3KPSu82HF
 | 
			
		||||
kPe6XoSbiLm/kxk32T0=
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										1
									
								
								vendor/golang.org/x/net/http2/h2demo/rootCA.srl
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								vendor/golang.org/x/net/http2/h2demo/rootCA.srl
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
E2CE26BF3285059C
 | 
			
		||||
							
								
								
									
										20
									
								
								vendor/golang.org/x/net/http2/h2demo/server.crt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/golang.org/x/net/http2/h2demo/server.crt
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
			
		||||
-----BEGIN CERTIFICATE-----
 | 
			
		||||
MIIDPjCCAiYCCQDizia/MoUFnDANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJV
 | 
			
		||||
UzELMAkGA1UECBMCQ0ExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xFDASBgNVBAoT
 | 
			
		||||
C0JyYWRmaXR6aW5jMRIwEAYDVQQDEwlsb2NhbGhvc3QxHTAbBgkqhkiG9w0BCQEW
 | 
			
		||||
DmJyYWRAZGFuZ2EuY29tMB4XDTE0MDcxNTIwNTAyN1oXDTE1MTEyNzIwNTAyN1ow
 | 
			
		||||
RzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAkNBMQswCQYDVQQHEwJTRjEeMBwGA1UE
 | 
			
		||||
ChMVYnJhZGZpdHogaHR0cDIgc2VydmVyMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
 | 
			
		||||
MIIBCgKCAQEAs1Y9CyLFrdL8VQWN1WaifDqaZFnoqjHhCMlc1TfG2zA+InDifx2l
 | 
			
		||||
gZD3o8FeNnAcfM2sPlk3+ZleOYw9P/CklFVDlvqmpCv9ss/BEp/dDaWvy1LmJ4c2
 | 
			
		||||
dbQJfmTxn7CV1H3TsVJvKdwFmdoABb41NoBp6+NNO7OtDyhbIMiCI0pL3Nefb3HL
 | 
			
		||||
A7hIMo3DYbORTtJLTIH9W8YKrEWL0lwHLrYFx/UdutZnv+HjdmO6vCN4na55mjws
 | 
			
		||||
/vjKQUmc7xeY7Xe20xDEG2oDKVkL2eD7FfyrYMS3rO1ExP2KSqlXYG/1S9I/fz88
 | 
			
		||||
F0GK7HX55b5WjZCl2J3ERVdnv/0MQv+sYQIDAQABMA0GCSqGSIb3DQEBBQUAA4IB
 | 
			
		||||
AQC0zL+n/YpRZOdulSu9tS8FxrstXqGWoxfe+vIUgqfMZ5+0MkjJ/vW0FqlLDl2R
 | 
			
		||||
rn4XaR3e7FmWkwdDVbq/UB6lPmoAaFkCgh9/5oapMaclNVNnfF3fjCJfRr+qj/iD
 | 
			
		||||
EmJStTIN0ZuUjAlpiACmfnpEU55PafT5Zx+i1yE4FGjw8bJpFoyD4Hnm54nGjX19
 | 
			
		||||
KeCuvcYFUPnBm3lcL0FalF2AjqV02WTHYNQk7YF/oeO7NKBoEgvGvKG3x+xaOeBI
 | 
			
		||||
dwvdq175ZsGul30h+QjrRlXhH/twcuaT3GSdoysDl9cCYE8f1Mk8PD6gan3uBCJU
 | 
			
		||||
90p6/CbU71bGbfpM2PHot2fm
 | 
			
		||||
-----END CERTIFICATE-----
 | 
			
		||||
							
								
								
									
										27
									
								
								vendor/golang.org/x/net/http2/h2demo/server.key
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								vendor/golang.org/x/net/http2/h2demo/server.key
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,27 @@
 | 
			
		||||
-----BEGIN RSA PRIVATE KEY-----
 | 
			
		||||
MIIEowIBAAKCAQEAs1Y9CyLFrdL8VQWN1WaifDqaZFnoqjHhCMlc1TfG2zA+InDi
 | 
			
		||||
fx2lgZD3o8FeNnAcfM2sPlk3+ZleOYw9P/CklFVDlvqmpCv9ss/BEp/dDaWvy1Lm
 | 
			
		||||
J4c2dbQJfmTxn7CV1H3TsVJvKdwFmdoABb41NoBp6+NNO7OtDyhbIMiCI0pL3Nef
 | 
			
		||||
b3HLA7hIMo3DYbORTtJLTIH9W8YKrEWL0lwHLrYFx/UdutZnv+HjdmO6vCN4na55
 | 
			
		||||
mjws/vjKQUmc7xeY7Xe20xDEG2oDKVkL2eD7FfyrYMS3rO1ExP2KSqlXYG/1S9I/
 | 
			
		||||
fz88F0GK7HX55b5WjZCl2J3ERVdnv/0MQv+sYQIDAQABAoIBADQ2spUwbY+bcz4p
 | 
			
		||||
3M66ECrNQTBggP40gYl2XyHxGGOu2xhZ94f9ELf1hjRWU2DUKWco1rJcdZClV6q3
 | 
			
		||||
qwmXvcM2Q/SMS8JW0ImkNVl/0/NqPxGatEnj8zY30d/L8hGFb0orzFu/XYA5gCP4
 | 
			
		||||
NbN2WrXgk3ZLeqwcNxHHtSiJWGJ/fPyeDWAu/apy75u9Xf2GlzBZmV6HYD9EfK80
 | 
			
		||||
LTlI60f5FO487CrJnboL7ovPJrIHn+k05xRQqwma4orpz932rTXnTjs9Lg6KtbQN
 | 
			
		||||
a7PrqfAntIISgr11a66Mng3IYH1lYqJsWJJwX/xHT4WLEy0EH4/0+PfYemJekz2+
 | 
			
		||||
Co62drECgYEA6O9zVJZXrLSDsIi54cfxA7nEZWm5CAtkYWeAHa4EJ+IlZ7gIf9sL
 | 
			
		||||
W8oFcEfFGpvwVqWZ+AsQ70dsjXAv3zXaG0tmg9FtqWp7pzRSMPidifZcQwWkKeTO
 | 
			
		||||
gJnFmnVyed8h6GfjTEu4gxo1/S5U0V+mYSha01z5NTnN6ltKx1Or3b0CgYEAxRgm
 | 
			
		||||
S30nZxnyg/V7ys61AZhst1DG2tkZXEMcA7dYhabMoXPJAP/EfhlWwpWYYUs/u0gS
 | 
			
		||||
Wwmf5IivX5TlYScgmkvb/NYz0u4ZmOXkLTnLPtdKKFXhjXJcHjUP67jYmOxNlJLp
 | 
			
		||||
V4vLRnFxTpffAV+OszzRxsXX6fvruwZBANYJeXUCgYBVouLFsFgfWGYp2rpr9XP4
 | 
			
		||||
KK25kvrBqF6JKOIDB1zjxNJ3pUMKrl8oqccCFoCyXa4oTM2kUX0yWxHfleUjrMq4
 | 
			
		||||
yimwQKiOZmV7fVLSSjSw6e/VfBd0h3gb82ygcplZkN0IclkwTY5SNKqwn/3y07V5
 | 
			
		||||
drqdhkrgdJXtmQ6O5YYECQKBgATERcDToQ1USlI4sKrB/wyv1AlG8dg/IebiVJ4e
 | 
			
		||||
ZAyvcQmClFzq0qS+FiQUnB/WQw9TeeYrwGs1hxBHuJh16srwhLyDrbMvQP06qh8R
 | 
			
		||||
48F8UXXSRec22dV9MQphaROhu2qZdv1AC0WD3tqov6L33aqmEOi+xi8JgbT/PLk5
 | 
			
		||||
c/c1AoGBAI1A/02ryksW6/wc7/6SP2M2rTy4m1sD/GnrTc67EHnRcVBdKO6qH2RY
 | 
			
		||||
nqC8YcveC2ZghgPTDsA3VGuzuBXpwY6wTyV99q6jxQJ6/xcrD9/NUG6Uwv/xfCxl
 | 
			
		||||
IJLeBYEqQundSSny3VtaAUK8Ul1nxpTvVRNwtcyWTo8RHAAyNPWd
 | 
			
		||||
-----END RSA PRIVATE KEY-----
 | 
			
		||||
							
								
								
									
										1991
									
								
								vendor/golang.org/x/net/http2/h2demo/tmpl.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1991
									
								
								vendor/golang.org/x/net/http2/h2demo/tmpl.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user