Browse code

vendor oauth2@96382aa0 and add its deps

Signed-off-by: Akihiro Suda <suda.akihiro@lab.ntt.co.jp>

Akihiro Suda authored on 2016/12/16 13:37:47
Showing 22 changed files
... ...
@@ -88,9 +88,12 @@ github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
88 88
 github.com/bsphere/le_go d3308aafe090956bc89a65f0769f58251a1b4f03
89 89
 
90 90
 # gcplogs deps
91
-golang.org/x/oauth2 2baa8a1b9338cf13d9eeb27696d761155fa480be
91
+golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
92 92
 google.golang.org/api dc6d2353af16e2a2b0ff6986af051d473a4ed468
93
+# TODO: remove google.golang.org/cloud, which has been replaced by cloud.google.com/go
93 94
 google.golang.org/cloud dae7e3d993bc3812a2185af60552bb6b847e52a0
95
+cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
96
+github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
94 97
 
95 98
 # native credentials
96 99
 github.com/docker/docker-credential-helpers f72c04f1d8e71959a6d103f808c50ccbad79b9fd
97 100
new file mode 100644
... ...
@@ -0,0 +1,202 @@
0
+
1
+                                 Apache License
2
+                           Version 2.0, January 2004
3
+                        http://www.apache.org/licenses/
4
+
5
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6
+
7
+   1. Definitions.
8
+
9
+      "License" shall mean the terms and conditions for use, reproduction,
10
+      and distribution as defined by Sections 1 through 9 of this document.
11
+
12
+      "Licensor" shall mean the copyright owner or entity authorized by
13
+      the copyright owner that is granting the License.
14
+
15
+      "Legal Entity" shall mean the union of the acting entity and all
16
+      other entities that control, are controlled by, or are under common
17
+      control with that entity. For the purposes of this definition,
18
+      "control" means (i) the power, direct or indirect, to cause the
19
+      direction or management of such entity, whether by contract or
20
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
21
+      outstanding shares, or (iii) beneficial ownership of such entity.
22
+
23
+      "You" (or "Your") shall mean an individual or Legal Entity
24
+      exercising permissions granted by this License.
25
+
26
+      "Source" form shall mean the preferred form for making modifications,
27
+      including but not limited to software source code, documentation
28
+      source, and configuration files.
29
+
30
+      "Object" form shall mean any form resulting from mechanical
31
+      transformation or translation of a Source form, including but
32
+      not limited to compiled object code, generated documentation,
33
+      and conversions to other media types.
34
+
35
+      "Work" shall mean the work of authorship, whether in Source or
36
+      Object form, made available under the License, as indicated by a
37
+      copyright notice that is included in or attached to the work
38
+      (an example is provided in the Appendix below).
39
+
40
+      "Derivative Works" shall mean any work, whether in Source or Object
41
+      form, that is based on (or derived from) the Work and for which the
42
+      editorial revisions, annotations, elaborations, or other modifications
43
+      represent, as a whole, an original work of authorship. For the purposes
44
+      of this License, Derivative Works shall not include works that remain
45
+      separable from, or merely link (or bind by name) to the interfaces of,
46
+      the Work and Derivative Works thereof.
47
+
48
+      "Contribution" shall mean any work of authorship, including
49
+      the original version of the Work and any modifications or additions
50
+      to that Work or Derivative Works thereof, that is intentionally
51
+      submitted to Licensor for inclusion in the Work by the copyright owner
52
+      or by an individual or Legal Entity authorized to submit on behalf of
53
+      the copyright owner. For the purposes of this definition, "submitted"
54
+      means any form of electronic, verbal, or written communication sent
55
+      to the Licensor or its representatives, including but not limited to
56
+      communication on electronic mailing lists, source code control systems,
57
+      and issue tracking systems that are managed by, or on behalf of, the
58
+      Licensor for the purpose of discussing and improving the Work, but
59
+      excluding communication that is conspicuously marked or otherwise
60
+      designated in writing by the copyright owner as "Not a Contribution."
61
+
62
+      "Contributor" shall mean Licensor and any individual or Legal Entity
63
+      on behalf of whom a Contribution has been received by Licensor and
64
+      subsequently incorporated within the Work.
65
+
66
+   2. Grant of Copyright License. Subject to the terms and conditions of
67
+      this License, each Contributor hereby grants to You a perpetual,
68
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69
+      copyright license to reproduce, prepare Derivative Works of,
70
+      publicly display, publicly perform, sublicense, and distribute the
71
+      Work and such Derivative Works in Source or Object form.
72
+
73
+   3. Grant of Patent License. Subject to the terms and conditions of
74
+      this License, each Contributor hereby grants to You a perpetual,
75
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76
+      (except as stated in this section) patent license to make, have made,
77
+      use, offer to sell, sell, import, and otherwise transfer the Work,
78
+      where such license applies only to those patent claims licensable
79
+      by such Contributor that are necessarily infringed by their
80
+      Contribution(s) alone or by combination of their Contribution(s)
81
+      with the Work to which such Contribution(s) was submitted. If You
82
+      institute patent litigation against any entity (including a
83
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
84
+      or a Contribution incorporated within the Work constitutes direct
85
+      or contributory patent infringement, then any patent licenses
86
+      granted to You under this License for that Work shall terminate
87
+      as of the date such litigation is filed.
88
+
89
+   4. Redistribution. You may reproduce and distribute copies of the
90
+      Work or Derivative Works thereof in any medium, with or without
91
+      modifications, and in Source or Object form, provided that You
92
+      meet the following conditions:
93
+
94
+      (a) You must give any other recipients of the Work or
95
+          Derivative Works a copy of this License; and
96
+
97
+      (b) You must cause any modified files to carry prominent notices
98
+          stating that You changed the files; and
99
+
100
+      (c) You must retain, in the Source form of any Derivative Works
101
+          that You distribute, all copyright, patent, trademark, and
102
+          attribution notices from the Source form of the Work,
103
+          excluding those notices that do not pertain to any part of
104
+          the Derivative Works; and
105
+
106
+      (d) If the Work includes a "NOTICE" text file as part of its
107
+          distribution, then any Derivative Works that You distribute must
108
+          include a readable copy of the attribution notices contained
109
+          within such NOTICE file, excluding those notices that do not
110
+          pertain to any part of the Derivative Works, in at least one
111
+          of the following places: within a NOTICE text file distributed
112
+          as part of the Derivative Works; within the Source form or
113
+          documentation, if provided along with the Derivative Works; or,
114
+          within a display generated by the Derivative Works, if and
115
+          wherever such third-party notices normally appear. The contents
116
+          of the NOTICE file are for informational purposes only and
117
+          do not modify the License. You may add Your own attribution
118
+          notices within Derivative Works that You distribute, alongside
119
+          or as an addendum to the NOTICE text from the Work, provided
120
+          that such additional attribution notices cannot be construed
121
+          as modifying the License.
122
+
123
+      You may add Your own copyright statement to Your modifications and
124
+      may provide additional or different license terms and conditions
125
+      for use, reproduction, or distribution of Your modifications, or
126
+      for any such Derivative Works as a whole, provided Your use,
127
+      reproduction, and distribution of the Work otherwise complies with
128
+      the conditions stated in this License.
129
+
130
+   5. Submission of Contributions. Unless You explicitly state otherwise,
131
+      any Contribution intentionally submitted for inclusion in the Work
132
+      by You to the Licensor shall be under the terms and conditions of
133
+      this License, without any additional terms or conditions.
134
+      Notwithstanding the above, nothing herein shall supersede or modify
135
+      the terms of any separate license agreement you may have executed
136
+      with Licensor regarding such Contributions.
137
+
138
+   6. Trademarks. This License does not grant permission to use the trade
139
+      names, trademarks, service marks, or product names of the Licensor,
140
+      except as required for reasonable and customary use in describing the
141
+      origin of the Work and reproducing the content of the NOTICE file.
142
+
143
+   7. Disclaimer of Warranty. Unless required by applicable law or
144
+      agreed to in writing, Licensor provides the Work (and each
145
+      Contributor provides its Contributions) on an "AS IS" BASIS,
146
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147
+      implied, including, without limitation, any warranties or conditions
148
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149
+      PARTICULAR PURPOSE. You are solely responsible for determining the
150
+      appropriateness of using or redistributing the Work and assume any
151
+      risks associated with Your exercise of permissions under this License.
152
+
153
+   8. Limitation of Liability. In no event and under no legal theory,
154
+      whether in tort (including negligence), contract, or otherwise,
155
+      unless required by applicable law (such as deliberate and grossly
156
+      negligent acts) or agreed to in writing, shall any Contributor be
157
+      liable to You for damages, including any direct, indirect, special,
158
+      incidental, or consequential damages of any character arising as a
159
+      result of this License or out of the use or inability to use the
160
+      Work (including but not limited to damages for loss of goodwill,
161
+      work stoppage, computer failure or malfunction, or any and all
162
+      other commercial damages or losses), even if such Contributor
163
+      has been advised of the possibility of such damages.
164
+
165
+   9. Accepting Warranty or Additional Liability. While redistributing
166
+      the Work or Derivative Works thereof, You may choose to offer,
167
+      and charge a fee for, acceptance of support, warranty, indemnity,
168
+      or other liability obligations and/or rights consistent with this
169
+      License. However, in accepting such obligations, You may act only
170
+      on Your own behalf and on Your sole responsibility, not on behalf
171
+      of any other Contributor, and only if You agree to indemnify,
172
+      defend, and hold each Contributor harmless for any liability
173
+      incurred by, or claims asserted against, such Contributor by reason
174
+      of your accepting any such warranty or additional liability.
175
+
176
+   END OF TERMS AND CONDITIONS
177
+
178
+   APPENDIX: How to apply the Apache License to your work.
179
+
180
+      To apply the Apache License to your work, attach the following
181
+      boilerplate notice, with the fields enclosed by brackets "[]"
182
+      replaced with your own identifying information. (Don't include
183
+      the brackets!)  The text should be enclosed in the appropriate
184
+      comment syntax for the file format. We also recommend that a
185
+      file or class name and description of purpose be included on the
186
+      same "printed page" as the copyright notice for easier
187
+      identification within third-party archives.
188
+
189
+   Copyright 2014 Google Inc.
190
+
191
+   Licensed under the Apache License, Version 2.0 (the "License");
192
+   you may not use this file except in compliance with the License.
193
+   You may obtain a copy of the License at
194
+
195
+       http://www.apache.org/licenses/LICENSE-2.0
196
+
197
+   Unless required by applicable law or agreed to in writing, software
198
+   distributed under the License is distributed on an "AS IS" BASIS,
199
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200
+   See the License for the specific language governing permissions and
201
+   limitations under the License.
0 202
new file mode 100644
... ...
@@ -0,0 +1,438 @@
0
+// Copyright 2014 Google Inc. All Rights Reserved.
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//      http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+// Package metadata provides access to Google Compute Engine (GCE)
15
+// metadata and API service accounts.
16
+//
17
+// This package is a wrapper around the GCE metadata service,
18
+// as documented at https://developers.google.com/compute/docs/metadata.
19
+package metadata // import "cloud.google.com/go/compute/metadata"
20
+
21
+import (
22
+	"encoding/json"
23
+	"fmt"
24
+	"io/ioutil"
25
+	"net"
26
+	"net/http"
27
+	"net/url"
28
+	"os"
29
+	"runtime"
30
+	"strings"
31
+	"sync"
32
+	"time"
33
+
34
+	"golang.org/x/net/context"
35
+	"golang.org/x/net/context/ctxhttp"
36
+
37
+	"cloud.google.com/go/internal"
38
+)
39
+
40
+const (
41
+	// metadataIP is the documented metadata server IP address.
42
+	metadataIP = "169.254.169.254"
43
+
44
+	// metadataHostEnv is the environment variable specifying the
45
+	// GCE metadata hostname.  If empty, the default value of
46
+	// metadataIP ("169.254.169.254") is used instead.
47
+	// This is variable name is not defined by any spec, as far as
48
+	// I know; it was made up for the Go package.
49
+	metadataHostEnv = "GCE_METADATA_HOST"
50
+)
51
+
52
+type cachedValue struct {
53
+	k    string
54
+	trim bool
55
+	mu   sync.Mutex
56
+	v    string
57
+}
58
+
59
+var (
60
+	projID  = &cachedValue{k: "project/project-id", trim: true}
61
+	projNum = &cachedValue{k: "project/numeric-project-id", trim: true}
62
+	instID  = &cachedValue{k: "instance/id", trim: true}
63
+)
64
+
65
+var (
66
+	metaClient = &http.Client{
67
+		Transport: &internal.Transport{
68
+			Base: &http.Transport{
69
+				Dial: (&net.Dialer{
70
+					Timeout:   2 * time.Second,
71
+					KeepAlive: 30 * time.Second,
72
+				}).Dial,
73
+				ResponseHeaderTimeout: 2 * time.Second,
74
+			},
75
+		},
76
+	}
77
+	subscribeClient = &http.Client{
78
+		Transport: &internal.Transport{
79
+			Base: &http.Transport{
80
+				Dial: (&net.Dialer{
81
+					Timeout:   2 * time.Second,
82
+					KeepAlive: 30 * time.Second,
83
+				}).Dial,
84
+			},
85
+		},
86
+	}
87
+)
88
+
89
+// NotDefinedError is returned when requested metadata is not defined.
90
+//
91
+// The underlying string is the suffix after "/computeMetadata/v1/".
92
+//
93
+// This error is not returned if the value is defined to be the empty
94
+// string.
95
+type NotDefinedError string
96
+
97
+func (suffix NotDefinedError) Error() string {
98
+	return fmt.Sprintf("metadata: GCE metadata %q not defined", string(suffix))
99
+}
100
+
101
+// Get returns a value from the metadata service.
102
+// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
103
+//
104
+// If the GCE_METADATA_HOST environment variable is not defined, a default of
105
+// 169.254.169.254 will be used instead.
106
+//
107
+// If the requested metadata is not defined, the returned error will
108
+// be of type NotDefinedError.
109
+func Get(suffix string) (string, error) {
110
+	val, _, err := getETag(metaClient, suffix)
111
+	return val, err
112
+}
113
+
114
+// getETag returns a value from the metadata service as well as the associated
115
+// ETag using the provided client. This func is otherwise equivalent to Get.
116
+func getETag(client *http.Client, suffix string) (value, etag string, err error) {
117
+	// Using a fixed IP makes it very difficult to spoof the metadata service in
118
+	// a container, which is an important use-case for local testing of cloud
119
+	// deployments. To enable spoofing of the metadata service, the environment
120
+	// variable GCE_METADATA_HOST is first inspected to decide where metadata
121
+	// requests shall go.
122
+	host := os.Getenv(metadataHostEnv)
123
+	if host == "" {
124
+		// Using 169.254.169.254 instead of "metadata" here because Go
125
+		// binaries built with the "netgo" tag and without cgo won't
126
+		// know the search suffix for "metadata" is
127
+		// ".google.internal", and this IP address is documented as
128
+		// being stable anyway.
129
+		host = metadataIP
130
+	}
131
+	url := "http://" + host + "/computeMetadata/v1/" + suffix
132
+	req, _ := http.NewRequest("GET", url, nil)
133
+	req.Header.Set("Metadata-Flavor", "Google")
134
+	res, err := client.Do(req)
135
+	if err != nil {
136
+		return "", "", err
137
+	}
138
+	defer res.Body.Close()
139
+	if res.StatusCode == http.StatusNotFound {
140
+		return "", "", NotDefinedError(suffix)
141
+	}
142
+	if res.StatusCode != 200 {
143
+		return "", "", fmt.Errorf("status code %d trying to fetch %s", res.StatusCode, url)
144
+	}
145
+	all, err := ioutil.ReadAll(res.Body)
146
+	if err != nil {
147
+		return "", "", err
148
+	}
149
+	return string(all), res.Header.Get("Etag"), nil
150
+}
151
+
152
+func getTrimmed(suffix string) (s string, err error) {
153
+	s, err = Get(suffix)
154
+	s = strings.TrimSpace(s)
155
+	return
156
+}
157
+
158
+func (c *cachedValue) get() (v string, err error) {
159
+	defer c.mu.Unlock()
160
+	c.mu.Lock()
161
+	if c.v != "" {
162
+		return c.v, nil
163
+	}
164
+	if c.trim {
165
+		v, err = getTrimmed(c.k)
166
+	} else {
167
+		v, err = Get(c.k)
168
+	}
169
+	if err == nil {
170
+		c.v = v
171
+	}
172
+	return
173
+}
174
+
175
+var (
176
+	onGCEOnce sync.Once
177
+	onGCE     bool
178
+)
179
+
180
+// OnGCE reports whether this process is running on Google Compute Engine.
181
+func OnGCE() bool {
182
+	onGCEOnce.Do(initOnGCE)
183
+	return onGCE
184
+}
185
+
186
+func initOnGCE() {
187
+	onGCE = testOnGCE()
188
+}
189
+
190
+func testOnGCE() bool {
191
+	// The user explicitly said they're on GCE, so trust them.
192
+	if os.Getenv(metadataHostEnv) != "" {
193
+		return true
194
+	}
195
+
196
+	ctx, cancel := context.WithCancel(context.Background())
197
+	defer cancel()
198
+
199
+	resc := make(chan bool, 2)
200
+
201
+	// Try two strategies in parallel.
202
+	// See https://github.com/GoogleCloudPlatform/google-cloud-go/issues/194
203
+	go func() {
204
+		res, err := ctxhttp.Get(ctx, metaClient, "http://"+metadataIP)
205
+		if err != nil {
206
+			resc <- false
207
+			return
208
+		}
209
+		defer res.Body.Close()
210
+		resc <- res.Header.Get("Metadata-Flavor") == "Google"
211
+	}()
212
+
213
+	go func() {
214
+		addrs, err := net.LookupHost("metadata.google.internal")
215
+		if err != nil || len(addrs) == 0 {
216
+			resc <- false
217
+			return
218
+		}
219
+		resc <- strsContains(addrs, metadataIP)
220
+	}()
221
+
222
+	tryHarder := systemInfoSuggestsGCE()
223
+	if tryHarder {
224
+		res := <-resc
225
+		if res {
226
+			// The first strategy succeeded, so let's use it.
227
+			return true
228
+		}
229
+		// Wait for either the DNS or metadata server probe to
230
+		// contradict the other one and say we are running on
231
+		// GCE. Give it a lot of time to do so, since the system
232
+		// info already suggests we're running on a GCE BIOS.
233
+		timer := time.NewTimer(5 * time.Second)
234
+		defer timer.Stop()
235
+		select {
236
+		case res = <-resc:
237
+			return res
238
+		case <-timer.C:
239
+			// Too slow. Who knows what this system is.
240
+			return false
241
+		}
242
+	}
243
+
244
+	// There's no hint from the system info that we're running on
245
+	// GCE, so use the first probe's result as truth, whether it's
246
+	// true or false. The goal here is to optimize for speed for
247
+	// users who are NOT running on GCE. We can't assume that
248
+	// either a DNS lookup or an HTTP request to a blackholed IP
249
+	// address is fast. Worst case this should return when the
250
+	// metaClient's Transport.ResponseHeaderTimeout or
251
+	// Transport.Dial.Timeout fires (in two seconds).
252
+	return <-resc
253
+}
254
+
255
+// systemInfoSuggestsGCE reports whether the local system (without
256
+// doing network requests) suggests that we're running on GCE. If this
257
+// returns true, testOnGCE tries a bit harder to reach its metadata
258
+// server.
259
+func systemInfoSuggestsGCE() bool {
260
+	if runtime.GOOS != "linux" {
261
+		// We don't have any non-Linux clues available, at least yet.
262
+		return false
263
+	}
264
+	slurp, _ := ioutil.ReadFile("/sys/class/dmi/id/product_name")
265
+	name := strings.TrimSpace(string(slurp))
266
+	return name == "Google" || name == "Google Compute Engine"
267
+}
268
+
269
+// Subscribe subscribes to a value from the metadata service.
270
+// The suffix is appended to "http://${GCE_METADATA_HOST}/computeMetadata/v1/".
271
+// The suffix may contain query parameters.
272
+//
273
+// Subscribe calls fn with the latest metadata value indicated by the provided
274
+// suffix. If the metadata value is deleted, fn is called with the empty string
275
+// and ok false. Subscribe blocks until fn returns a non-nil error or the value
276
+// is deleted. Subscribe returns the error value returned from the last call to
277
+// fn, which may be nil when ok == false.
278
+func Subscribe(suffix string, fn func(v string, ok bool) error) error {
279
+	const failedSubscribeSleep = time.Second * 5
280
+
281
+	// First check to see if the metadata value exists at all.
282
+	val, lastETag, err := getETag(subscribeClient, suffix)
283
+	if err != nil {
284
+		return err
285
+	}
286
+
287
+	if err := fn(val, true); err != nil {
288
+		return err
289
+	}
290
+
291
+	ok := true
292
+	if strings.ContainsRune(suffix, '?') {
293
+		suffix += "&wait_for_change=true&last_etag="
294
+	} else {
295
+		suffix += "?wait_for_change=true&last_etag="
296
+	}
297
+	for {
298
+		val, etag, err := getETag(subscribeClient, suffix+url.QueryEscape(lastETag))
299
+		if err != nil {
300
+			if _, deleted := err.(NotDefinedError); !deleted {
301
+				time.Sleep(failedSubscribeSleep)
302
+				continue // Retry on other errors.
303
+			}
304
+			ok = false
305
+		}
306
+		lastETag = etag
307
+
308
+		if err := fn(val, ok); err != nil || !ok {
309
+			return err
310
+		}
311
+	}
312
+}
313
+
314
+// ProjectID returns the current instance's project ID string.
315
+func ProjectID() (string, error) { return projID.get() }
316
+
317
+// NumericProjectID returns the current instance's numeric project ID.
318
+func NumericProjectID() (string, error) { return projNum.get() }
319
+
320
+// InternalIP returns the instance's primary internal IP address.
321
+func InternalIP() (string, error) {
322
+	return getTrimmed("instance/network-interfaces/0/ip")
323
+}
324
+
325
+// ExternalIP returns the instance's primary external (public) IP address.
326
+func ExternalIP() (string, error) {
327
+	return getTrimmed("instance/network-interfaces/0/access-configs/0/external-ip")
328
+}
329
+
330
+// Hostname returns the instance's hostname. This will be of the form
331
+// "<instanceID>.c.<projID>.internal".
332
+func Hostname() (string, error) {
333
+	return getTrimmed("instance/hostname")
334
+}
335
+
336
+// InstanceTags returns the list of user-defined instance tags,
337
+// assigned when initially creating a GCE instance.
338
+func InstanceTags() ([]string, error) {
339
+	var s []string
340
+	j, err := Get("instance/tags")
341
+	if err != nil {
342
+		return nil, err
343
+	}
344
+	if err := json.NewDecoder(strings.NewReader(j)).Decode(&s); err != nil {
345
+		return nil, err
346
+	}
347
+	return s, nil
348
+}
349
+
350
+// InstanceID returns the current VM's numeric instance ID.
351
+func InstanceID() (string, error) {
352
+	return instID.get()
353
+}
354
+
355
+// InstanceName returns the current VM's instance ID string.
356
+func InstanceName() (string, error) {
357
+	host, err := Hostname()
358
+	if err != nil {
359
+		return "", err
360
+	}
361
+	return strings.Split(host, ".")[0], nil
362
+}
363
+
364
+// Zone returns the current VM's zone, such as "us-central1-b".
365
+func Zone() (string, error) {
366
+	zone, err := getTrimmed("instance/zone")
367
+	// zone is of the form "projects/<projNum>/zones/<zoneName>".
368
+	if err != nil {
369
+		return "", err
370
+	}
371
+	return zone[strings.LastIndex(zone, "/")+1:], nil
372
+}
373
+
374
+// InstanceAttributes returns the list of user-defined attributes,
375
+// assigned when initially creating a GCE VM instance. The value of an
376
+// attribute can be obtained with InstanceAttributeValue.
377
+func InstanceAttributes() ([]string, error) { return lines("instance/attributes/") }
378
+
379
+// ProjectAttributes returns the list of user-defined attributes
380
+// applying to the project as a whole, not just this VM.  The value of
381
+// an attribute can be obtained with ProjectAttributeValue.
382
+func ProjectAttributes() ([]string, error) { return lines("project/attributes/") }
383
+
384
+func lines(suffix string) ([]string, error) {
385
+	j, err := Get(suffix)
386
+	if err != nil {
387
+		return nil, err
388
+	}
389
+	s := strings.Split(strings.TrimSpace(j), "\n")
390
+	for i := range s {
391
+		s[i] = strings.TrimSpace(s[i])
392
+	}
393
+	return s, nil
394
+}
395
+
396
+// InstanceAttributeValue returns the value of the provided VM
397
+// instance attribute.
398
+//
399
+// If the requested attribute is not defined, the returned error will
400
+// be of type NotDefinedError.
401
+//
402
+// InstanceAttributeValue may return ("", nil) if the attribute was
403
+// defined to be the empty string.
404
+func InstanceAttributeValue(attr string) (string, error) {
405
+	return Get("instance/attributes/" + attr)
406
+}
407
+
408
+// ProjectAttributeValue returns the value of the provided
409
+// project attribute.
410
+//
411
+// If the requested attribute is not defined, the returned error will
412
+// be of type NotDefinedError.
413
+//
414
+// ProjectAttributeValue may return ("", nil) if the attribute was
415
+// defined to be the empty string.
416
+func ProjectAttributeValue(attr string) (string, error) {
417
+	return Get("project/attributes/" + attr)
418
+}
419
+
420
+// Scopes returns the service account scopes for the given account.
421
+// The account may be empty or the string "default" to use the instance's
422
+// main account.
423
+func Scopes(serviceAccount string) ([]string, error) {
424
+	if serviceAccount == "" {
425
+		serviceAccount = "default"
426
+	}
427
+	return lines("instance/service-accounts/" + serviceAccount + "/scopes")
428
+}
429
+
430
+func strsContains(ss []string, s string) bool {
431
+	for _, v := range ss {
432
+		if v == s {
433
+			return true
434
+		}
435
+	}
436
+	return false
437
+}
0 438
new file mode 100644
... ...
@@ -0,0 +1,64 @@
0
+// Copyright 2014 Google Inc. All Rights Reserved.
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//      http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+// Package internal provides support for the cloud packages.
15
+//
16
+// Users should not import this package directly.
17
+package internal
18
+
19
+import (
20
+	"fmt"
21
+	"net/http"
22
+)
23
+
24
+const userAgent = "gcloud-golang/0.1"
25
+
26
+// Transport is an http.RoundTripper that appends Google Cloud client's
27
+// user-agent to the original request's user-agent header.
28
+type Transport struct {
29
+	// TODO(bradfitz): delete internal.Transport. It's too wrappy for what it does.
30
+	// Do User-Agent some other way.
31
+
32
+	// Base is the actual http.RoundTripper
33
+	// requests will use. It must not be nil.
34
+	Base http.RoundTripper
35
+}
36
+
37
+// RoundTrip appends a user-agent to the existing user-agent
38
+// header and delegates the request to the base http.RoundTripper.
39
+func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
40
+	req = cloneRequest(req)
41
+	ua := req.Header.Get("User-Agent")
42
+	if ua == "" {
43
+		ua = userAgent
44
+	} else {
45
+		ua = fmt.Sprintf("%s %s", ua, userAgent)
46
+	}
47
+	req.Header.Set("User-Agent", ua)
48
+	return t.Base.RoundTrip(req)
49
+}
50
+
51
+// cloneRequest returns a clone of the provided *http.Request.
52
+// The clone is a shallow copy of the struct and its Header map.
53
+func cloneRequest(r *http.Request) *http.Request {
54
+	// shallow copy of the struct
55
+	r2 := new(http.Request)
56
+	*r2 = *r
57
+	// deep copy of the Header
58
+	r2.Header = make(http.Header)
59
+	for k, s := range r.Header {
60
+		r2.Header[k] = s
61
+	}
62
+	return r2
63
+}
0 64
new file mode 100644
... ...
@@ -0,0 +1,55 @@
0
+// Copyright 2016 Google Inc. All Rights Reserved.
1
+//
2
+// Licensed under the Apache License, Version 2.0 (the "License");
3
+// you may not use this file except in compliance with the License.
4
+// You may obtain a copy of the License at
5
+//
6
+//      http://www.apache.org/licenses/LICENSE-2.0
7
+//
8
+// Unless required by applicable law or agreed to in writing, software
9
+// distributed under the License is distributed on an "AS IS" BASIS,
10
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+// See the License for the specific language governing permissions and
12
+// limitations under the License.
13
+
14
+package internal
15
+
16
+import (
17
+	"fmt"
18
+	"time"
19
+
20
+	gax "github.com/googleapis/gax-go"
21
+
22
+	"golang.org/x/net/context"
23
+)
24
+
25
+// Retry calls the supplied function f repeatedly according to the provided
26
+// backoff parameters. It returns when one of the following occurs:
27
+// When f's first return value is true, Retry immediately returns with f's second
28
+// return value.
29
+// When the provided context is done, Retry returns with ctx.Err().
30
+func Retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error)) error {
31
+	return retry(ctx, bo, f, gax.Sleep)
32
+}
33
+
34
+func retry(ctx context.Context, bo gax.Backoff, f func() (stop bool, err error),
35
+	sleep func(context.Context, time.Duration) error) error {
36
+	var lastErr error
37
+	for {
38
+		stop, err := f()
39
+		if stop {
40
+			return err
41
+		}
42
+		// Remember the last "real" error from f.
43
+		if err != nil && err != context.Canceled && err != context.DeadlineExceeded {
44
+			lastErr = err
45
+		}
46
+		p := bo.Pause()
47
+		if cerr := sleep(ctx, p); cerr != nil {
48
+			if lastErr != nil {
49
+				return fmt.Errorf("%v; last function err: %v", cerr, lastErr)
50
+			}
51
+			return cerr
52
+		}
53
+	}
54
+}
0 55
new file mode 100644
... ...
@@ -0,0 +1,27 @@
0
+Copyright 2016, Google Inc.
1
+All rights reserved.
2
+Redistribution and use in source and binary forms, with or without
3
+modification, are permitted provided that the following conditions are
4
+met:
5
+
6
+   * Redistributions of source code must retain the above copyright
7
+notice, this list of conditions and the following disclaimer.
8
+   * Redistributions in binary form must reproduce the above
9
+copyright notice, this list of conditions and the following disclaimer
10
+in the documentation and/or other materials provided with the
11
+distribution.
12
+   * Neither the name of Google Inc. nor the names of its
13
+contributors may be used to endorse or promote products derived from
14
+this software without specific prior written permission.
15
+
16
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
0 27
new file mode 100644
... ...
@@ -0,0 +1,136 @@
0
+// Copyright 2016, Google Inc.
1
+// All rights reserved.
2
+//
3
+// Redistribution and use in source and binary forms, with or without
4
+// modification, are permitted provided that the following conditions are
5
+// met:
6
+//
7
+//     * Redistributions of source code must retain the above copyright
8
+// notice, this list of conditions and the following disclaimer.
9
+//     * Redistributions in binary form must reproduce the above
10
+// copyright notice, this list of conditions and the following disclaimer
11
+// in the documentation and/or other materials provided with the
12
+// distribution.
13
+//     * Neither the name of Google Inc. nor the names of its
14
+// contributors may be used to endorse or promote products derived from
15
+// this software without specific prior written permission.
16
+//
17
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+package gax
30
+
31
+import (
32
+	"math/rand"
33
+	"time"
34
+
35
+	"google.golang.org/grpc"
36
+	"google.golang.org/grpc/codes"
37
+)
38
+
39
+// CallOption is an option used by Invoke to control behaviors of RPC calls.
40
+// CallOption works by modifying relevant fields of CallSettings.
41
+type CallOption interface {
42
+	// Resolve applies the option by modifying cs.
43
+	Resolve(cs *CallSettings)
44
+}
45
+
46
+// Retryer is used by Invoke to determine retry behavior.
47
+type Retryer interface {
48
+	// Retry reports whether a request should be retriedand how long to pause before retrying
49
+	// if the previous attempt returned with err. Invoke never calls Retry with nil error.
50
+	Retry(err error) (pause time.Duration, shouldRetry bool)
51
+}
52
+
53
+type retryerOption func() Retryer
54
+
55
+func (o retryerOption) Resolve(s *CallSettings) {
56
+	s.Retry = o
57
+}
58
+
59
+// WithRetry sets CallSettings.Retry to fn.
60
+func WithRetry(fn func() Retryer) CallOption {
61
+	return retryerOption(fn)
62
+}
63
+
64
+// OnCodes returns a Retryer that retries if and only if
65
+// the previous attempt returns a GRPC error whose error code is stored in cc.
66
+// Pause times between retries are specified by bo.
67
+//
68
+// bo is only used for its parameters; each Retryer has its own copy.
69
+func OnCodes(cc []codes.Code, bo Backoff) Retryer {
70
+	return &boRetryer{
71
+		backoff: bo,
72
+		codes:   append([]codes.Code(nil), cc...),
73
+	}
74
+}
75
+
76
+type boRetryer struct {
77
+	backoff Backoff
78
+	codes   []codes.Code
79
+}
80
+
81
+func (r *boRetryer) Retry(err error) (time.Duration, bool) {
82
+	c := grpc.Code(err)
83
+	for _, rc := range r.codes {
84
+		if c == rc {
85
+			return r.backoff.Pause(), true
86
+		}
87
+	}
88
+	return 0, false
89
+}
90
+
91
+// Backoff implements exponential backoff.
92
+// The wait time between retries is a random value between 0 and the "retry envelope".
93
+// The envelope starts at Initial and increases by the factor of Multiplier every retry,
94
+// but is capped at Max.
95
+type Backoff struct {
96
+	// Initial is the initial value of the retry envelope, defaults to 1 second.
97
+	Initial time.Duration
98
+
99
+	// Max is the maximum value of the retry envelope, defaults to 30 seconds.
100
+	Max time.Duration
101
+
102
+	// Multiplier is the factor by which the retry envelope increases.
103
+	// It should be greater than 1 and defaults to 2.
104
+	Multiplier float64
105
+
106
+	// cur is the current retry envelope
107
+	cur time.Duration
108
+}
109
+
110
+func (bo *Backoff) Pause() time.Duration {
111
+	if bo.Initial == 0 {
112
+		bo.Initial = time.Second
113
+	}
114
+	if bo.cur == 0 {
115
+		bo.cur = bo.Initial
116
+	}
117
+	if bo.Max == 0 {
118
+		bo.Max = 30 * time.Second
119
+	}
120
+	if bo.Multiplier < 1 {
121
+		bo.Multiplier = 2
122
+	}
123
+	d := time.Duration(rand.Int63n(int64(bo.cur)))
124
+	bo.cur = time.Duration(float64(bo.cur) * bo.Multiplier)
125
+	if bo.cur > bo.Max {
126
+		bo.cur = bo.Max
127
+	}
128
+	return d
129
+}
130
+
131
+type CallSettings struct {
132
+	// Retry returns a Retryer to be used to control retry logic of a method call.
133
+	// If Retry is nil or the returned Retryer is nil, the call will not be retried.
134
+	Retry func() Retryer
135
+}
0 136
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Copyright 2016, Google Inc.
1
+// All rights reserved.
2
+//
3
+// Redistribution and use in source and binary forms, with or without
4
+// modification, are permitted provided that the following conditions are
5
+// met:
6
+//
7
+//     * Redistributions of source code must retain the above copyright
8
+// notice, this list of conditions and the following disclaimer.
9
+//     * Redistributions in binary form must reproduce the above
10
+// copyright notice, this list of conditions and the following disclaimer
11
+// in the documentation and/or other materials provided with the
12
+// distribution.
13
+//     * Neither the name of Google Inc. nor the names of its
14
+// contributors may be used to endorse or promote products derived from
15
+// this software without specific prior written permission.
16
+//
17
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+// Package gax contains a set of modules which aid the development of APIs
30
+// for clients and servers based on gRPC and Google API conventions.
31
+//
32
+// Application code will rarely need to use this library directly.
33
+// However, code generated automatically from API definition files can use it
34
+// to simplify code generation and to provide more convenient and idiomatic API surfaces.
35
+//
36
+// This project is currently experimental and not supported.
37
+package gax
38
+
39
+const Version = "0.1.0"
0 40
new file mode 100644
... ...
@@ -0,0 +1,90 @@
0
+// Copyright 2016, Google Inc.
1
+// All rights reserved.
2
+//
3
+// Redistribution and use in source and binary forms, with or without
4
+// modification, are permitted provided that the following conditions are
5
+// met:
6
+//
7
+//     * Redistributions of source code must retain the above copyright
8
+// notice, this list of conditions and the following disclaimer.
9
+//     * Redistributions in binary form must reproduce the above
10
+// copyright notice, this list of conditions and the following disclaimer
11
+// in the documentation and/or other materials provided with the
12
+// distribution.
13
+//     * Neither the name of Google Inc. nor the names of its
14
+// contributors may be used to endorse or promote products derived from
15
+// this software without specific prior written permission.
16
+//
17
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+package gax
30
+
31
+import (
32
+	"time"
33
+
34
+	"golang.org/x/net/context"
35
+)
36
+
37
+// A user defined call stub.
38
+type APICall func(context.Context) error
39
+
40
+// Invoke calls the given APICall,
41
+// performing retries as specified by opts, if any.
42
+func Invoke(ctx context.Context, call APICall, opts ...CallOption) error {
43
+	var settings CallSettings
44
+	for _, opt := range opts {
45
+		opt.Resolve(&settings)
46
+	}
47
+	return invoke(ctx, call, settings, Sleep)
48
+}
49
+
50
+// Sleep is similar to time.Sleep, but it can be interrupted by ctx.Done() closing.
51
+// If interrupted, Sleep returns ctx.Err().
52
+func Sleep(ctx context.Context, d time.Duration) error {
53
+	t := time.NewTimer(d)
54
+	select {
55
+	case <-ctx.Done():
56
+		t.Stop()
57
+		return ctx.Err()
58
+	case <-t.C:
59
+		return nil
60
+	}
61
+}
62
+
63
+type sleeper func(ctx context.Context, d time.Duration) error
64
+
65
+// invoke implements Invoke, taking an additional sleeper argument for testing.
66
+func invoke(ctx context.Context, call APICall, settings CallSettings, sp sleeper) error {
67
+	var retryer Retryer
68
+	for {
69
+		err := call(ctx)
70
+		if err == nil {
71
+			return nil
72
+		}
73
+		if settings.Retry == nil {
74
+			return err
75
+		}
76
+		if retryer == nil {
77
+			if r := settings.Retry(); r != nil {
78
+				retryer = r
79
+			} else {
80
+				return err
81
+			}
82
+		}
83
+		if d, ok := retryer.Retry(err); !ok {
84
+			return err
85
+		} else if err = sp(ctx, d); err != nil {
86
+			return err
87
+		}
88
+	}
89
+}
0 90
new file mode 100644
... ...
@@ -0,0 +1,176 @@
0
+// Copyright 2016, Google Inc.
1
+// All rights reserved.
2
+//
3
+// Redistribution and use in source and binary forms, with or without
4
+// modification, are permitted provided that the following conditions are
5
+// met:
6
+//
7
+//     * Redistributions of source code must retain the above copyright
8
+// notice, this list of conditions and the following disclaimer.
9
+//     * Redistributions in binary form must reproduce the above
10
+// copyright notice, this list of conditions and the following disclaimer
11
+// in the documentation and/or other materials provided with the
12
+// distribution.
13
+//     * Neither the name of Google Inc. nor the names of its
14
+// contributors may be used to endorse or promote products derived from
15
+// this software without specific prior written permission.
16
+//
17
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+package gax
30
+
31
+import (
32
+	"errors"
33
+	"fmt"
34
+	"strings"
35
+)
36
+
37
+type matcher interface {
38
+	match([]string) (int, error)
39
+	String() string
40
+}
41
+
42
+type segment struct {
43
+	matcher
44
+	name string
45
+}
46
+
47
+type labelMatcher string
48
+
49
+func (ls labelMatcher) match(segments []string) (int, error) {
50
+	if len(segments) == 0 {
51
+		return 0, fmt.Errorf("expected %s but no more segments found", ls)
52
+	}
53
+	if segments[0] != string(ls) {
54
+		return 0, fmt.Errorf("expected %s but got %s", ls, segments[0])
55
+	}
56
+	return 1, nil
57
+}
58
+
59
+func (ls labelMatcher) String() string {
60
+	return string(ls)
61
+}
62
+
63
+type wildcardMatcher int
64
+
65
+func (wm wildcardMatcher) match(segments []string) (int, error) {
66
+	if len(segments) == 0 {
67
+		return 0, errors.New("no more segments found")
68
+	}
69
+	return 1, nil
70
+}
71
+
72
+func (wm wildcardMatcher) String() string {
73
+	return "*"
74
+}
75
+
76
+type pathWildcardMatcher int
77
+
78
+func (pwm pathWildcardMatcher) match(segments []string) (int, error) {
79
+	length := len(segments) - int(pwm)
80
+	if length <= 0 {
81
+		return 0, errors.New("not sufficient segments are supplied for path wildcard")
82
+	}
83
+	return length, nil
84
+}
85
+
86
+func (pwm pathWildcardMatcher) String() string {
87
+	return "**"
88
+}
89
+
90
+type ParseError struct {
91
+	Pos      int
92
+	Template string
93
+	Message  string
94
+}
95
+
96
+func (pe ParseError) Error() string {
97
+	return fmt.Sprintf("at %d of template '%s', %s", pe.Pos, pe.Template, pe.Message)
98
+}
99
+
100
+// PathTemplate manages the template to build and match with paths used
101
+// by API services. It holds a template and variable names in it, and
102
+// it can extract matched patterns from a path string or build a path
103
+// string from a binding.
104
+//
105
+// See http.proto in github.com/googleapis/googleapis/ for the details of
106
+// the template syntax.
107
+type PathTemplate struct {
108
+	segments []segment
109
+}
110
+
111
+// NewPathTemplate parses a path template, and returns a PathTemplate
112
+// instance if successful.
113
+func NewPathTemplate(template string) (*PathTemplate, error) {
114
+	return parsePathTemplate(template)
115
+}
116
+
117
+// MustCompilePathTemplate is like NewPathTemplate but panics if the
118
+// expression cannot be parsed. It simplifies safe initialization of
119
+// global variables holding compiled regular expressions.
120
+func MustCompilePathTemplate(template string) *PathTemplate {
121
+	pt, err := NewPathTemplate(template)
122
+	if err != nil {
123
+		panic(err)
124
+	}
125
+	return pt
126
+}
127
+
128
+// Match attempts to match the given path with the template, and returns
129
+// the mapping of the variable name to the matched pattern string.
130
+func (pt *PathTemplate) Match(path string) (map[string]string, error) {
131
+	paths := strings.Split(path, "/")
132
+	values := map[string]string{}
133
+	for _, segment := range pt.segments {
134
+		length, err := segment.match(paths)
135
+		if err != nil {
136
+			return nil, err
137
+		}
138
+		if segment.name != "" {
139
+			value := strings.Join(paths[:length], "/")
140
+			if oldValue, ok := values[segment.name]; ok {
141
+				values[segment.name] = oldValue + "/" + value
142
+			} else {
143
+				values[segment.name] = value
144
+			}
145
+		}
146
+		paths = paths[length:]
147
+	}
148
+	if len(paths) != 0 {
149
+		return nil, fmt.Errorf("Trailing path %s remains after the matching", strings.Join(paths, "/"))
150
+	}
151
+	return values, nil
152
+}
153
+
154
+// Render creates a path string from its template and the binding from
155
+// the variable name to the value.
156
+func (pt *PathTemplate) Render(binding map[string]string) (string, error) {
157
+	result := make([]string, 0, len(pt.segments))
158
+	var lastVariableName string
159
+	for _, segment := range pt.segments {
160
+		name := segment.name
161
+		if lastVariableName != "" && name == lastVariableName {
162
+			continue
163
+		}
164
+		lastVariableName = name
165
+		if name == "" {
166
+			result = append(result, segment.String())
167
+		} else if value, ok := binding[name]; ok {
168
+			result = append(result, value)
169
+		} else {
170
+			return "", fmt.Errorf("%s is not found", name)
171
+		}
172
+	}
173
+	built := strings.Join(result, "/")
174
+	return built, nil
175
+}
0 176
new file mode 100644
... ...
@@ -0,0 +1,227 @@
0
+// Copyright 2016, Google Inc.
1
+// All rights reserved.
2
+//
3
+// Redistribution and use in source and binary forms, with or without
4
+// modification, are permitted provided that the following conditions are
5
+// met:
6
+//
7
+//     * Redistributions of source code must retain the above copyright
8
+// notice, this list of conditions and the following disclaimer.
9
+//     * Redistributions in binary form must reproduce the above
10
+// copyright notice, this list of conditions and the following disclaimer
11
+// in the documentation and/or other materials provided with the
12
+// distribution.
13
+//     * Neither the name of Google Inc. nor the names of its
14
+// contributors may be used to endorse or promote products derived from
15
+// this software without specific prior written permission.
16
+//
17
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+
29
+package gax
30
+
31
+import (
32
+	"fmt"
33
+	"io"
34
+	"strings"
35
+)
36
+
37
+// This parser follows the syntax of path templates, from
38
+// https://github.com/googleapis/googleapis/blob/master/google/api/http.proto.
39
+// The differences are that there is no custom verb, we allow the initial slash
40
+// to be absent, and that we are not strict as
41
+// https://tools.ietf.org/html/rfc6570 about the characters in identifiers and
42
+// literals.
43
+
44
+type pathTemplateParser struct {
45
+	r                *strings.Reader
46
+	runeCount        int             // the number of the current rune in the original string
47
+	nextVar          int             // the number to use for the next unnamed variable
48
+	seenName         map[string]bool // names we've seen already
49
+	seenPathWildcard bool            // have we seen "**" already?
50
+}
51
+
52
+func parsePathTemplate(template string) (pt *PathTemplate, err error) {
53
+	p := &pathTemplateParser{
54
+		r:        strings.NewReader(template),
55
+		seenName: map[string]bool{},
56
+	}
57
+
58
+	// Handle panics with strings like errors.
59
+	// See pathTemplateParser.error, below.
60
+	defer func() {
61
+		if x := recover(); x != nil {
62
+			errmsg, ok := x.(errString)
63
+			if !ok {
64
+				panic(x)
65
+			}
66
+			pt = nil
67
+			err = ParseError{p.runeCount, template, string(errmsg)}
68
+		}
69
+	}()
70
+
71
+	segs := p.template()
72
+	// If there is a path wildcard, set its length. We can't do this
73
+	// until we know how many segments we've got all together.
74
+	for i, seg := range segs {
75
+		if _, ok := seg.matcher.(pathWildcardMatcher); ok {
76
+			segs[i].matcher = pathWildcardMatcher(len(segs) - i - 1)
77
+			break
78
+		}
79
+	}
80
+	return &PathTemplate{segments: segs}, nil
81
+
82
+}
83
+
84
+// Used to indicate errors "thrown" by this parser. We don't use string because
85
+// many parts of the standard library panic with strings.
86
+type errString string
87
+
88
+// Terminates parsing immediately with an error.
89
+func (p *pathTemplateParser) error(msg string) {
90
+	panic(errString(msg))
91
+}
92
+
93
+// Template = [ "/" ] Segments
94
+func (p *pathTemplateParser) template() []segment {
95
+	var segs []segment
96
+	if p.consume('/') {
97
+		// Initial '/' needs an initial empty matcher.
98
+		segs = append(segs, segment{matcher: labelMatcher("")})
99
+	}
100
+	return append(segs, p.segments("")...)
101
+}
102
+
103
+// Segments = Segment { "/" Segment }
104
+func (p *pathTemplateParser) segments(name string) []segment {
105
+	var segs []segment
106
+	for {
107
+		subsegs := p.segment(name)
108
+		segs = append(segs, subsegs...)
109
+		if !p.consume('/') {
110
+			break
111
+		}
112
+	}
113
+	return segs
114
+}
115
+
116
+// Segment  = "*" | "**" | LITERAL | Variable
117
+func (p *pathTemplateParser) segment(name string) []segment {
118
+	if p.consume('*') {
119
+		if name == "" {
120
+			name = fmt.Sprintf("$%d", p.nextVar)
121
+			p.nextVar++
122
+		}
123
+		if p.consume('*') {
124
+			if p.seenPathWildcard {
125
+				p.error("multiple '**' disallowed")
126
+			}
127
+			p.seenPathWildcard = true
128
+			// We'll change 0 to the right number at the end.
129
+			return []segment{{name: name, matcher: pathWildcardMatcher(0)}}
130
+		}
131
+		return []segment{{name: name, matcher: wildcardMatcher(0)}}
132
+	}
133
+	if p.consume('{') {
134
+		if name != "" {
135
+			p.error("recursive named bindings are not allowed")
136
+		}
137
+		return p.variable()
138
+	}
139
+	return []segment{{name: name, matcher: labelMatcher(p.literal())}}
140
+}
141
+
142
+// Variable = "{" FieldPath [ "=" Segments ] "}"
143
+// "{" is already consumed.
144
+func (p *pathTemplateParser) variable() []segment {
145
+	// Simplification: treat FieldPath as LITERAL, instead of IDENT { '.' IDENT }
146
+	name := p.literal()
147
+	if p.seenName[name] {
148
+		p.error(name + " appears multiple times")
149
+	}
150
+	p.seenName[name] = true
151
+	var segs []segment
152
+	if p.consume('=') {
153
+		segs = p.segments(name)
154
+	} else {
155
+		// "{var}" is equivalent to "{var=*}"
156
+		segs = []segment{{name: name, matcher: wildcardMatcher(0)}}
157
+	}
158
+	if !p.consume('}') {
159
+		p.error("expected '}'")
160
+	}
161
+	return segs
162
+}
163
+
164
+// A literal is any sequence of characters other than a few special ones.
165
+// The list of stop characters is not quite the same as in the template RFC.
166
+func (p *pathTemplateParser) literal() string {
167
+	lit := p.consumeUntil("/*}{=")
168
+	if lit == "" {
169
+		p.error("empty literal")
170
+	}
171
+	return lit
172
+}
173
+
174
+// Read runes until EOF or one of the runes in stopRunes is encountered.
175
+// If the latter, unread the stop rune. Return the accumulated runes as a string.
176
+func (p *pathTemplateParser) consumeUntil(stopRunes string) string {
177
+	var runes []rune
178
+	for {
179
+		r, ok := p.readRune()
180
+		if !ok {
181
+			break
182
+		}
183
+		if strings.IndexRune(stopRunes, r) >= 0 {
184
+			p.unreadRune()
185
+			break
186
+		}
187
+		runes = append(runes, r)
188
+	}
189
+	return string(runes)
190
+}
191
+
192
+// If the next rune is r, consume it and return true.
193
+// Otherwise, leave the input unchanged and return false.
194
+func (p *pathTemplateParser) consume(r rune) bool {
195
+	rr, ok := p.readRune()
196
+	if !ok {
197
+		return false
198
+	}
199
+	if r == rr {
200
+		return true
201
+	}
202
+	p.unreadRune()
203
+	return false
204
+}
205
+
206
+// Read the next rune from the input. Return it.
207
+// The second return value is false at EOF.
208
+func (p *pathTemplateParser) readRune() (rune, bool) {
209
+	r, _, err := p.r.ReadRune()
210
+	if err == io.EOF {
211
+		return r, false
212
+	}
213
+	if err != nil {
214
+		p.error(err.Error())
215
+	}
216
+	p.runeCount++
217
+	return r, true
218
+}
219
+
220
+// Put the last rune that was read back on the input.
221
+func (p *pathTemplateParser) unreadRune() {
222
+	if err := p.r.UnreadRune(); err != nil {
223
+		p.error(err.Error())
224
+	}
225
+	p.runeCount--
226
+}
... ...
@@ -20,6 +20,9 @@ var appengineVM bool
20 20
 // Set at init time by appengine_hook.go. If nil, we're not on App Engine.
21 21
 var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
22 22
 
23
+// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
24
+var appengineAppIDFunc func(c context.Context) string
25
+
23 26
 // AppEngineTokenSource returns a token source that fetches tokens
24 27
 // issued to the current App Engine application's service account.
25 28
 // If you are implementing a 3-legged OAuth 2.0 flow on App Engine
... ...
@@ -10,4 +10,5 @@ import "google.golang.org/appengine"
10 10
 
11 11
 func init() {
12 12
 	appengineTokenFunc = appengine.AccessToken
13
+	appengineAppIDFunc = appengine.AppID
13 14
 }
... ...
@@ -11,4 +11,5 @@ import "google.golang.org/appengine"
11 11
 func init() {
12 12
 	appengineVM = true
13 13
 	appengineTokenFunc = appengine.AccessToken
14
+	appengineAppIDFunc = appengine.AppID
14 15
 }
... ...
@@ -6,7 +6,6 @@ package google
6 6
 
7 7
 import (
8 8
 	"encoding/json"
9
-	"errors"
10 9
 	"fmt"
11 10
 	"io/ioutil"
12 11
 	"net/http"
... ...
@@ -14,22 +13,21 @@ import (
14 14
 	"path/filepath"
15 15
 	"runtime"
16 16
 
17
+	"cloud.google.com/go/compute/metadata"
17 18
 	"golang.org/x/net/context"
18 19
 	"golang.org/x/oauth2"
19
-	"golang.org/x/oauth2/jwt"
20
-	"google.golang.org/cloud/compute/metadata"
21 20
 )
22 21
 
23
-// DefaultClient returns an HTTP Client that uses the
24
-// DefaultTokenSource to obtain authentication credentials.
25
-//
26
-// This client should be used when developing services
27
-// that run on Google App Engine or Google Compute Engine
28
-// and use "Application Default Credentials."
29
-//
22
+// DefaultCredentials holds "Application Default Credentials".
30 23
 // For more details, see:
31 24
 // https://developers.google.com/accounts/docs/application-default-credentials
32
-//
25
+type DefaultCredentials struct {
26
+	ProjectID   string // may be empty
27
+	TokenSource oauth2.TokenSource
28
+}
29
+
30
+// DefaultClient returns an HTTP Client that uses the
31
+// DefaultTokenSource to obtain authentication credentials.
33 32
 func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
34 33
 	ts, err := DefaultTokenSource(ctx, scope...)
35 34
 	if err != nil {
... ...
@@ -38,8 +36,18 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
38 38
 	return oauth2.NewClient(ctx, ts), nil
39 39
 }
40 40
 
41
-// DefaultTokenSource is a token source that uses
41
+// DefaultTokenSource returns the token source for
42 42
 // "Application Default Credentials".
43
+// It is a shortcut for FindDefaultCredentials(ctx, scope).TokenSource.
44
+func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
45
+	creds, err := FindDefaultCredentials(ctx, scope...)
46
+	if err != nil {
47
+		return nil, err
48
+	}
49
+	return creds.TokenSource, nil
50
+}
51
+
52
+// FindDefaultCredentials searches for "Application Default Credentials".
43 53
 //
44 54
 // It looks for credentials in the following places,
45 55
 // preferring the first location found:
... ...
@@ -53,45 +61,40 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
53 53
 //   4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
54 54
 //      credentials from the metadata server.
55 55
 //      (In this final case any provided scopes are ignored.)
56
-//
57
-// For more details, see:
58
-// https://developers.google.com/accounts/docs/application-default-credentials
59
-//
60
-func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSource, error) {
56
+func FindDefaultCredentials(ctx context.Context, scope ...string) (*DefaultCredentials, error) {
61 57
 	// First, try the environment variable.
62 58
 	const envVar = "GOOGLE_APPLICATION_CREDENTIALS"
63 59
 	if filename := os.Getenv(envVar); filename != "" {
64
-		ts, err := tokenSourceFromFile(ctx, filename, scope)
60
+		creds, err := readCredentialsFile(ctx, filename, scope)
65 61
 		if err != nil {
66 62
 			return nil, fmt.Errorf("google: error getting credentials using %v environment variable: %v", envVar, err)
67 63
 		}
68
-		return ts, nil
64
+		return creds, nil
69 65
 	}
70 66
 
71 67
 	// Second, try a well-known file.
72 68
 	filename := wellKnownFile()
73
-	_, err := os.Stat(filename)
74
-	if err == nil {
75
-		ts, err2 := tokenSourceFromFile(ctx, filename, scope)
76
-		if err2 == nil {
77
-			return ts, nil
78
-		}
79
-		err = err2
80
-	} else if os.IsNotExist(err) {
81
-		err = nil // ignore this error
82
-	}
83
-	if err != nil {
69
+	if creds, err := readCredentialsFile(ctx, filename, scope); err == nil {
70
+		return creds, nil
71
+	} else if !os.IsNotExist(err) {
84 72
 		return nil, fmt.Errorf("google: error getting credentials using well-known file (%v): %v", filename, err)
85 73
 	}
86 74
 
87 75
 	// Third, if we're on Google App Engine use those credentials.
88 76
 	if appengineTokenFunc != nil && !appengineVM {
89
-		return AppEngineTokenSource(ctx, scope...), nil
77
+		return &DefaultCredentials{
78
+			ProjectID:   appengineAppIDFunc(ctx),
79
+			TokenSource: AppEngineTokenSource(ctx, scope...),
80
+		}, nil
90 81
 	}
91 82
 
92 83
 	// Fourth, if we're on Google Compute Engine use the metadata server.
93 84
 	if metadata.OnGCE() {
94
-		return ComputeTokenSource(""), nil
85
+		id, _ := metadata.ProjectID()
86
+		return &DefaultCredentials{
87
+			ProjectID:   id,
88
+			TokenSource: ComputeTokenSource(""),
89
+		}, nil
95 90
 	}
96 91
 
97 92
 	// None are found; return helpful error.
... ...
@@ -107,49 +110,21 @@ func wellKnownFile() string {
107 107
 	return filepath.Join(guessUnixHomeDir(), ".config", "gcloud", f)
108 108
 }
109 109
 
110
-func tokenSourceFromFile(ctx context.Context, filename string, scopes []string) (oauth2.TokenSource, error) {
110
+func readCredentialsFile(ctx context.Context, filename string, scopes []string) (*DefaultCredentials, error) {
111 111
 	b, err := ioutil.ReadFile(filename)
112 112
 	if err != nil {
113 113
 		return nil, err
114 114
 	}
115
-	var d struct {
116
-		// Common fields
117
-		Type     string
118
-		ClientID string `json:"client_id"`
119
-
120
-		// User Credential fields
121
-		ClientSecret string `json:"client_secret"`
122
-		RefreshToken string `json:"refresh_token"`
123
-
124
-		// Service Account fields
125
-		ClientEmail  string `json:"client_email"`
126
-		PrivateKeyID string `json:"private_key_id"`
127
-		PrivateKey   string `json:"private_key"`
128
-	}
129
-	if err := json.Unmarshal(b, &d); err != nil {
115
+	var f credentialsFile
116
+	if err := json.Unmarshal(b, &f); err != nil {
130 117
 		return nil, err
131 118
 	}
132
-	switch d.Type {
133
-	case "authorized_user":
134
-		cfg := &oauth2.Config{
135
-			ClientID:     d.ClientID,
136
-			ClientSecret: d.ClientSecret,
137
-			Scopes:       append([]string{}, scopes...), // copy
138
-			Endpoint:     Endpoint,
139
-		}
140
-		tok := &oauth2.Token{RefreshToken: d.RefreshToken}
141
-		return cfg.TokenSource(ctx, tok), nil
142
-	case "service_account":
143
-		cfg := &jwt.Config{
144
-			Email:      d.ClientEmail,
145
-			PrivateKey: []byte(d.PrivateKey),
146
-			Scopes:     append([]string{}, scopes...), // copy
147
-			TokenURL:   JWTTokenURL,
148
-		}
149
-		return cfg.TokenSource(ctx), nil
150
-	case "":
151
-		return nil, errors.New("missing 'type' field in credentials")
152
-	default:
153
-		return nil, fmt.Errorf("unknown credential type: %q", d.Type)
119
+	ts, err := f.tokenSource(ctx, append([]string(nil), scopes...))
120
+	if err != nil {
121
+		return nil, err
154 122
 	}
123
+	return &DefaultCredentials{
124
+		ProjectID:   f.ProjectID,
125
+		TokenSource: ts,
126
+	}, nil
155 127
 }
... ...
@@ -21,9 +21,10 @@ import (
21 21
 	"strings"
22 22
 	"time"
23 23
 
24
+	"cloud.google.com/go/compute/metadata"
25
+	"golang.org/x/net/context"
24 26
 	"golang.org/x/oauth2"
25 27
 	"golang.org/x/oauth2/jwt"
26
-	"google.golang.org/cloud/compute/metadata"
27 28
 )
28 29
 
29 30
 // Endpoint is Google's OAuth 2.0 endpoint.
... ...
@@ -37,9 +38,10 @@ const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
37 37
 
38 38
 // ConfigFromJSON uses a Google Developers Console client_credentials.json
39 39
 // file to construct a config.
40
-// client_credentials.json can be downloadable from https://console.developers.google.com,
41
-// under "APIs & Auth" > "Credentials". Download the Web application credentials in the
42
-// JSON format and provide the contents of the file as jsonKey.
40
+// client_credentials.json can be downloaded from
41
+// https://console.developers.google.com, under "Credentials". Download the Web
42
+// application credentials in the JSON format and provide the contents of the
43
+// file as jsonKey.
43 44
 func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
44 45
 	type cred struct {
45 46
 		ClientID     string   `json:"client_id"`
... ...
@@ -81,22 +83,77 @@ func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
81 81
 
82 82
 // JWTConfigFromJSON uses a Google Developers service account JSON key file to read
83 83
 // the credentials that authorize and authenticate the requests.
84
-// Create a service account on "Credentials" page under "APIs & Auth" for your
85
-// project at https://console.developers.google.com to download a JSON key file.
84
+// Create a service account on "Credentials" for your project at
85
+// https://console.developers.google.com to download a JSON key file.
86 86
 func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
87
-	var key struct {
88
-		Email      string `json:"client_email"`
89
-		PrivateKey string `json:"private_key"`
90
-	}
91
-	if err := json.Unmarshal(jsonKey, &key); err != nil {
87
+	var f credentialsFile
88
+	if err := json.Unmarshal(jsonKey, &f); err != nil {
92 89
 		return nil, err
93 90
 	}
94
-	return &jwt.Config{
95
-		Email:      key.Email,
96
-		PrivateKey: []byte(key.PrivateKey),
97
-		Scopes:     scope,
98
-		TokenURL:   JWTTokenURL,
99
-	}, nil
91
+	if f.Type != serviceAccountKey {
92
+		return nil, fmt.Errorf("google: read JWT from JSON credentials: 'type' field is %q (expected %q)", f.Type, serviceAccountKey)
93
+	}
94
+	scope = append([]string(nil), scope...) // copy
95
+	return f.jwtConfig(scope), nil
96
+}
97
+
98
+// JSON key file types.
99
+const (
100
+	serviceAccountKey  = "service_account"
101
+	userCredentialsKey = "authorized_user"
102
+)
103
+
104
+// credentialsFile is the unmarshalled representation of a credentials file.
105
+type credentialsFile struct {
106
+	Type string `json:"type"` // serviceAccountKey or userCredentialsKey
107
+
108
+	// Service Account fields
109
+	ClientEmail  string `json:"client_email"`
110
+	PrivateKeyID string `json:"private_key_id"`
111
+	PrivateKey   string `json:"private_key"`
112
+	TokenURL     string `json:"token_uri"`
113
+	ProjectID    string `json:"project_id"`
114
+
115
+	// User Credential fields
116
+	// (These typically come from gcloud auth.)
117
+	ClientSecret string `json:"client_secret"`
118
+	ClientID     string `json:"client_id"`
119
+	RefreshToken string `json:"refresh_token"`
120
+}
121
+
122
+func (f *credentialsFile) jwtConfig(scopes []string) *jwt.Config {
123
+	cfg := &jwt.Config{
124
+		Email:        f.ClientEmail,
125
+		PrivateKey:   []byte(f.PrivateKey),
126
+		PrivateKeyID: f.PrivateKeyID,
127
+		Scopes:       scopes,
128
+		TokenURL:     f.TokenURL,
129
+	}
130
+	if cfg.TokenURL == "" {
131
+		cfg.TokenURL = JWTTokenURL
132
+	}
133
+	return cfg
134
+}
135
+
136
+func (f *credentialsFile) tokenSource(ctx context.Context, scopes []string) (oauth2.TokenSource, error) {
137
+	switch f.Type {
138
+	case serviceAccountKey:
139
+		cfg := f.jwtConfig(scopes)
140
+		return cfg.TokenSource(ctx), nil
141
+	case userCredentialsKey:
142
+		cfg := &oauth2.Config{
143
+			ClientID:     f.ClientID,
144
+			ClientSecret: f.ClientSecret,
145
+			Scopes:       scopes,
146
+			Endpoint:     Endpoint,
147
+		}
148
+		tok := &oauth2.Token{RefreshToken: f.RefreshToken}
149
+		return cfg.TokenSource(ctx, tok), nil
150
+	case "":
151
+		return nil, errors.New("missing 'type' field in credentials")
152
+	default:
153
+		return nil, fmt.Errorf("unknown credential type: %q", f.Type)
154
+	}
100 155
 }
101 156
 
102 157
 // ComputeTokenSource returns a token source that fetches access tokens
... ...
@@ -36,6 +36,7 @@ func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.Token
36 36
 		email:    cfg.Email,
37 37
 		audience: audience,
38 38
 		pk:       pk,
39
+		pkID:     cfg.PrivateKeyID,
39 40
 	}
40 41
 	tok, err := ts.Token()
41 42
 	if err != nil {
... ...
@@ -47,6 +48,7 @@ func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.Token
47 47
 type jwtAccessTokenSource struct {
48 48
 	email, audience string
49 49
 	pk              *rsa.PrivateKey
50
+	pkID            string
50 51
 }
51 52
 
52 53
 func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
... ...
@@ -62,6 +64,7 @@ func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
62 62
 	hdr := &jws.Header{
63 63
 		Algorithm: "RS256",
64 64
 		Typ:       "JWT",
65
+		KeyID:     string(ts.pkID),
65 66
 	}
66 67
 	msg, err := jws.Encode(hdr, cs, ts.pk)
67 68
 	if err != nil {
... ...
@@ -160,9 +160,13 @@ var sdkConfigPath = func() (string, error) {
160 160
 }
161 161
 
162 162
 func guessUnixHomeDir() string {
163
-	usr, err := user.Current()
164
-	if err == nil {
165
-		return usr.HomeDir
163
+	// Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470
164
+	if v := os.Getenv("HOME"); v != "" {
165
+		return v
166 166
 	}
167
-	return os.Getenv("HOME")
167
+	// Else, fall back to user.Current:
168
+	if u, err := user.Current(); err == nil {
169
+		return u.HomeDir
170
+	}
171
+	return ""
168 172
 }
... ...
@@ -92,6 +92,7 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
92 92
 var brokenAuthHeaderProviders = []string{
93 93
 	"https://accounts.google.com/",
94 94
 	"https://api.dropbox.com/",
95
+	"https://api.dropboxapi.com/",
95 96
 	"https://api.instagram.com/",
96 97
 	"https://api.netatmo.net/",
97 98
 	"https://api.odnoklassniki.ru/",
... ...
@@ -105,6 +106,7 @@ var brokenAuthHeaderProviders = []string{
105 105
 	"https://oauth.sandbox.trainingpeaks.com/",
106 106
 	"https://oauth.trainingpeaks.com/",
107 107
 	"https://oauth.vk.com/",
108
+	"https://openapi.baidu.com/",
108 109
 	"https://slack.com/",
109 110
 	"https://test-sandbox.auth.corp.google.com",
110 111
 	"https://test.salesforce.com/",
... ...
@@ -113,6 +115,10 @@ var brokenAuthHeaderProviders = []string{
113 113
 	"https://www.googleapis.com/",
114 114
 	"https://www.linkedin.com/",
115 115
 	"https://www.strava.com/oauth/",
116
+	"https://www.wunderlist.com/oauth/",
117
+	"https://api.patreon.com/",
118
+	"https://sandbox.codeswholesale.com/oauth/token",
119
+	"https://api.codeswholesale.com/oauth/token",
116 120
 }
117 121
 
118 122
 func RegisterBrokenAuthHeaderProvider(tokenURL string) {
... ...
@@ -142,23 +148,23 @@ func providerAuthHeaderWorks(tokenURL string) bool {
142 142
 	return true
143 143
 }
144 144
 
145
-func RetrieveToken(ctx context.Context, ClientID, ClientSecret, TokenURL string, v url.Values) (*Token, error) {
145
+func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
146 146
 	hc, err := ContextClient(ctx)
147 147
 	if err != nil {
148 148
 		return nil, err
149 149
 	}
150
-	v.Set("client_id", ClientID)
151
-	bustedAuth := !providerAuthHeaderWorks(TokenURL)
152
-	if bustedAuth && ClientSecret != "" {
153
-		v.Set("client_secret", ClientSecret)
150
+	v.Set("client_id", clientID)
151
+	bustedAuth := !providerAuthHeaderWorks(tokenURL)
152
+	if bustedAuth && clientSecret != "" {
153
+		v.Set("client_secret", clientSecret)
154 154
 	}
155
-	req, err := http.NewRequest("POST", TokenURL, strings.NewReader(v.Encode()))
155
+	req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
156 156
 	if err != nil {
157 157
 		return nil, err
158 158
 	}
159 159
 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
160 160
 	if !bustedAuth {
161
-		req.SetBasicAuth(ClientID, ClientSecret)
161
+		req.SetBasicAuth(clientID, clientSecret)
162 162
 	}
163 163
 	r, err := hc.Do(req)
164 164
 	if err != nil {
... ...
@@ -2,8 +2,16 @@
2 2
 // Use of this source code is governed by a BSD-style
3 3
 // license that can be found in the LICENSE file.
4 4
 
5
-// Package jws provides encoding and decoding utilities for
6
-// signed JWS messages.
5
+// Package jws provides a partial implementation
6
+// of JSON Web Signature encoding and decoding.
7
+// It exists to support the golang.org/x/oauth2 package.
8
+//
9
+// See RFC 7515.
10
+//
11
+// Deprecated: this package is not intended for public use and might be
12
+// removed in the future. It exists for internal use only.
13
+// Please switch to another JWS package or copy this package into your own
14
+// source tree.
7 15
 package jws // import "golang.org/x/oauth2/jws"
8 16
 
9 17
 import (
... ...
@@ -64,7 +72,7 @@ func (c *ClaimSet) encode() (string, error) {
64 64
 	}
65 65
 
66 66
 	if len(c.PrivateClaims) == 0 {
67
-		return base64Encode(b), nil
67
+		return base64.RawURLEncoding.EncodeToString(b), nil
68 68
 	}
69 69
 
70 70
 	// Marshal private claim set and then append it to b.
... ...
@@ -82,7 +90,7 @@ func (c *ClaimSet) encode() (string, error) {
82 82
 	}
83 83
 	b[len(b)-1] = ','         // Replace closing curly brace with a comma.
84 84
 	b = append(b, prv[1:]...) // Append private claims.
85
-	return base64Encode(b), nil
85
+	return base64.RawURLEncoding.EncodeToString(b), nil
86 86
 }
87 87
 
88 88
 // Header represents the header for the signed JWS payloads.
... ...
@@ -92,6 +100,9 @@ type Header struct {
92 92
 
93 93
 	// Represents the token type.
94 94
 	Typ string `json:"typ"`
95
+
96
+	// The optional hint of which key is being used.
97
+	KeyID string `json:"kid,omitempty"`
95 98
 }
96 99
 
97 100
 func (h *Header) encode() (string, error) {
... ...
@@ -99,7 +110,7 @@ func (h *Header) encode() (string, error) {
99 99
 	if err != nil {
100 100
 		return "", err
101 101
 	}
102
-	return base64Encode(b), nil
102
+	return base64.RawURLEncoding.EncodeToString(b), nil
103 103
 }
104 104
 
105 105
 // Decode decodes a claim set from a JWS payload.
... ...
@@ -110,7 +121,7 @@ func Decode(payload string) (*ClaimSet, error) {
110 110
 		// TODO(jbd): Provide more context about the error.
111 111
 		return nil, errors.New("jws: invalid token received")
112 112
 	}
113
-	decoded, err := base64Decode(s[1])
113
+	decoded, err := base64.RawURLEncoding.DecodeString(s[1])
114 114
 	if err != nil {
115 115
 		return nil, err
116 116
 	}
... ...
@@ -137,7 +148,7 @@ func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
137 137
 	if err != nil {
138 138
 		return "", err
139 139
 	}
140
-	return fmt.Sprintf("%s.%s", ss, base64Encode(sig)), nil
140
+	return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
141 141
 }
142 142
 
143 143
 // Encode encodes a signed JWS with provided header and claim set.
... ...
@@ -145,28 +156,27 @@ func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
145 145
 func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
146 146
 	sg := func(data []byte) (sig []byte, err error) {
147 147
 		h := sha256.New()
148
-		h.Write([]byte(data))
148
+		h.Write(data)
149 149
 		return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
150 150
 	}
151 151
 	return EncodeWithSigner(header, c, sg)
152 152
 }
153 153
 
154
-// base64Encode returns and Base64url encoded version of the input string with any
155
-// trailing "=" stripped.
156
-func base64Encode(b []byte) string {
157
-	return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=")
158
-}
154
+// Verify tests whether the provided JWT token's signature was produced by the private key
155
+// associated with the supplied public key.
156
+func Verify(token string, key *rsa.PublicKey) error {
157
+	parts := strings.Split(token, ".")
158
+	if len(parts) != 3 {
159
+		return errors.New("jws: invalid token received, token must have 3 parts")
160
+	}
161
+
162
+	signedContent := parts[0] + "." + parts[1]
163
+	signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
164
+	if err != nil {
165
+		return err
166
+	}
159 167
 
160
-// base64Decode decodes the Base64url encoded string
161
-func base64Decode(s string) ([]byte, error) {
162
-	// add back missing padding
163
-	switch len(s) % 4 {
164
-	case 1:
165
-		s += "==="
166
-	case 2:
167
-		s += "=="
168
-	case 3:
169
-		s += "="
170
-	}
171
-	return base64.URLEncoding.DecodeString(s)
168
+	h := sha256.New()
169
+	h.Write([]byte(signedContent))
170
+	return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
172 171
 }
... ...
@@ -46,6 +46,10 @@ type Config struct {
46 46
 	//
47 47
 	PrivateKey []byte
48 48
 
49
+	// PrivateKeyID contains an optional hint indicating which key is being
50
+	// used.
51
+	PrivateKeyID string
52
+
49 53
 	// Subject is the optional user to impersonate.
50 54
 	Subject string
51 55
 
... ...
@@ -21,6 +21,8 @@ import (
21 21
 
22 22
 // NoContext is the default context you should supply if not using
23 23
 // your own context.Context (see https://golang.org/x/net/context).
24
+//
25
+// Deprecated: Use context.Background() or context.TODO() instead.
24 26
 var NoContext = context.TODO()
25 27
 
26 28
 // RegisterBrokenAuthHeaderProvider registers an OAuth2 server
... ...
@@ -37,6 +39,8 @@ func RegisterBrokenAuthHeaderProvider(tokenURL string) {
37 37
 
38 38
 // Config describes a typical 3-legged OAuth2 flow, with both the
39 39
 // client application information and the server's endpoint URLs.
40
+// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
41
+// package (https://golang.org/x/oauth2/clientcredentials).
40 42
 type Config struct {
41 43
 	// ClientID is the application's ID.
42 44
 	ClientID string
... ...
@@ -295,7 +299,7 @@ func NewClient(ctx context.Context, src TokenSource) *http.Client {
295 295
 	if src == nil {
296 296
 		c, err := internal.ContextClient(ctx)
297 297
 		if err != nil {
298
-			return &http.Client{Transport: internal.ErrorTransport{err}}
298
+			return &http.Client{Transport: internal.ErrorTransport{Err: err}}
299 299
 		}
300 300
 		return c
301 301
 	}