storage: Add emulator host to reader and writer

Change-Id: I41cd692ddb9ac95b916b106dfadccf7d213646d8
Reviewed-on: https://code-review.googlesource.com/c/gocloud/+/42970
Reviewed-by: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jean de Klerk <deklerk@google.com>
diff --git a/storage/reader.go b/storage/reader.go
index 50f381f..dbed8ac 100644
--- a/storage/reader.go
+++ b/storage/reader.go
@@ -95,8 +95,8 @@
 		}
 	}
 	u := &url.URL{
-		Scheme: "https",
-		Host:   "storage.googleapis.com",
+		Scheme: o.c.scheme,
+		Host:   o.c.readHost,
 		Path:   fmt.Sprintf("/%s/%s", o.bucket, o.object),
 	}
 	verb := "GET"
diff --git a/storage/storage.go b/storage/storage.go
index c5c5c59..d35bd75 100644
--- a/storage/storage.go
+++ b/storage/storage.go
@@ -29,6 +29,7 @@
 	"fmt"
 	"net/http"
 	"net/url"
+	"os"
 	"reflect"
 	"regexp"
 	"sort"
@@ -82,6 +83,12 @@
 type Client struct {
 	hc  *http.Client
 	raw *raw.Service
+	// Scheme describes the scheme under the current host.
+	scheme string
+	// EnvHost is the host set on the STORAGE_EMULATOR_HOST variable.
+	envHost string
+	// ReadHost is the default host used on the reader.
+	readHost string
 }
 
 // NewClient creates a new Google Cloud Storage client.
@@ -103,9 +110,20 @@
 	if ep != "" {
 		rawService.BasePath = ep
 	}
+	scheme := "https"
+	var host, readHost string
+	if host = os.Getenv("STORAGE_EMULATOR_HOST"); host != "" {
+		scheme = "http"
+		readHost = host
+	} else {
+		readHost = "storage.googleapis.com"
+	}
 	return &Client{
-		hc:  hc,
-		raw: rawService,
+		hc:       hc,
+		raw:      rawService,
+		scheme:   scheme,
+		envHost:  host,
+		readHost: readHost,
 	}, nil
 }
 
diff --git a/storage/writer.go b/storage/writer.go
index 3a58c40..0f52414 100644
--- a/storage/writer.go
+++ b/storage/writer.go
@@ -117,10 +117,14 @@
 		if w.MD5 != nil {
 			rawObj.Md5Hash = base64.StdEncoding.EncodeToString(w.MD5)
 		}
+		if w.o.c.envHost != "" {
+			w.o.c.raw.BasePath = fmt.Sprintf("%s://%s", w.o.c.scheme, w.o.c.envHost)
+		}
 		call := w.o.c.raw.Objects.Insert(w.o.bucket, rawObj).
 			Media(pr, mediaOpts...).
 			Projection("full").
 			Context(w.ctx)
+
 		if w.ProgressFunc != nil {
 			call.ProgressUpdater(func(n, _ int64) { w.ProgressFunc(n) })
 		}