Commit fc466743 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #32592 from dims/update-google-cloud-api-imports

Automatic merge from submit-queue Update Google Cloud API client import paths
parents 4387dcbd 64efc3a7
...@@ -20,12 +20,12 @@ package clouddns ...@@ -20,12 +20,12 @@ package clouddns
import ( import (
"io" "io"
"cloud.google.com/go/compute/metadata"
"github.com/golang/glog" "github.com/golang/glog"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
compute "google.golang.org/api/compute/v1" compute "google.golang.org/api/compute/v1"
dns "google.golang.org/api/dns/v1" dns "google.golang.org/api/dns/v1"
"google.golang.org/cloud/compute/metadata"
gcfg "gopkg.in/gcfg.v1" gcfg "gopkg.in/gcfg.v1"
"k8s.io/kubernetes/federation/pkg/dnsprovider" "k8s.io/kubernetes/federation/pkg/dnsprovider"
......
...@@ -41,13 +41,13 @@ import ( ...@@ -41,13 +41,13 @@ import (
"k8s.io/kubernetes/pkg/util/sets" "k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/util/wait" "k8s.io/kubernetes/pkg/util/wait"
"cloud.google.com/go/compute/metadata"
"github.com/golang/glog" "github.com/golang/glog"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
compute "google.golang.org/api/compute/v1" compute "google.golang.org/api/compute/v1"
container "google.golang.org/api/container/v1" container "google.golang.org/api/container/v1"
"google.golang.org/api/googleapi" "google.golang.org/api/googleapi"
"google.golang.org/cloud/compute/metadata"
) )
const ( const (
......
...@@ -23,10 +23,10 @@ import ( ...@@ -23,10 +23,10 @@ import (
"k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/api"
gce "cloud.google.com/go/compute/metadata"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/google" "golang.org/x/oauth2/google"
gcm "google.golang.org/api/cloudmonitoring/v2beta2" gcm "google.golang.org/api/cloudmonitoring/v2beta2"
gce "google.golang.org/cloud/compute/metadata"
) )
const ( const (
......
...@@ -229,6 +229,26 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo ...@@ -229,6 +229,26 @@ func NewPrometheusCollector(i infoProvider, f ContainerLabelsFunc) *PrometheusCo
} }
}, },
}, { }, {
name: "container_fs_inodes_free",
help: "Number of available Inodes",
valueType: prometheus.GaugeValue,
extraLabels: []string{"device"},
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.InodesFree)
})
},
}, {
name: "container_fs_inodes_total",
help: "Number of Inodes",
valueType: prometheus.GaugeValue,
extraLabels: []string{"device"},
getValues: func(s *info.ContainerStats) metricValues {
return fsValues(s.Filesystem, func(fs *info.FsStats) float64 {
return float64(fs.Inodes)
})
},
}, {
name: "container_fs_limit_bytes", name: "container_fs_limit_bytes",
help: "Number of bytes that can be consumed by the container on this filesystem.", help: "Number of bytes that can be consumed by the container on this filesystem.",
valueType: prometheus.GaugeValue, valueType: prometheus.GaugeValue,
......
language: go language: go
go: go:
- 1.3 - tip
- 1.4
install: install:
- export GOPATH="$HOME/gopath" - export GOPATH="$HOME/gopath"
......
# OAuth2 for Go # OAuth2 for Go
[![Build Status](https://travis-ci.org/golang/oauth2.svg?branch=master)](https://travis-ci.org/golang/oauth2) [![Build Status](https://travis-ci.org/golang/oauth2.svg?branch=master)](https://travis-ci.org/golang/oauth2)
[![GoDoc](https://godoc.org/golang.org/x/oauth2?status.svg)](https://godoc.org/golang.org/x/oauth2)
oauth2 package contains a client implementation for OAuth 2.0 spec. oauth2 package contains a client implementation for OAuth 2.0 spec.
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build appengine appenginevm // +build appengine
// App Engine hooks. // App Engine hooks.
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -14,6 +14,9 @@ import ( ...@@ -14,6 +14,9 @@ import (
"golang.org/x/oauth2" "golang.org/x/oauth2"
) )
// Set at init time by appenginevm_hook.go. If true, we are on App Engine Managed VMs.
var appengineVM bool
// Set at init time by appengine_hook.go. If nil, we're not on App Engine. // Set at init time by appengine_hook.go. If nil, we're not on App Engine.
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error) var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
......
// Copyright 2015 The oauth2 Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// +build appengine appenginevm // +build appengine
package google package google
......
// Copyright 2015 The oauth2 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 appenginevm
package google
import "google.golang.org/appengine"
func init() {
appengineVM = true
appengineTokenFunc = appengine.AccessToken
}
// Copyright 2015 The oauth2 Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -14,10 +14,10 @@ import ( ...@@ -14,10 +14,10 @@ import (
"path/filepath" "path/filepath"
"runtime" "runtime"
"cloud.google.com/go/compute/metadata"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/jwt" "golang.org/x/oauth2/jwt"
"google.golang.org/cloud/compute/metadata"
) )
// DefaultClient returns an HTTP Client that uses the // DefaultClient returns an HTTP Client that uses the
...@@ -50,7 +50,8 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) { ...@@ -50,7 +50,8 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json. // On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
// On other systems, $HOME/.config/gcloud/application_default_credentials.json. // On other systems, $HOME/.config/gcloud/application_default_credentials.json.
// 3. On Google App Engine it uses the appengine.AccessToken function. // 3. On Google App Engine it uses the appengine.AccessToken function.
// 4. On Google Compute Engine, it fetches credentials from the metadata server. // 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
// credentials from the metadata server.
// (In this final case any provided scopes are ignored.) // (In this final case any provided scopes are ignored.)
// //
// For more details, see: // For more details, see:
...@@ -84,7 +85,7 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc ...@@ -84,7 +85,7 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
} }
// Third, if we're on Google App Engine use those credentials. // Third, if we're on Google App Engine use those credentials.
if appengineTokenFunc != nil { if appengineTokenFunc != nil && !appengineVM {
return AppEngineTokenSource(ctx, scope...), nil return AppEngineTokenSource(ctx, scope...), nil
} }
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -21,9 +21,9 @@ import ( ...@@ -21,9 +21,9 @@ import (
"strings" "strings"
"time" "time"
"cloud.google.com/go/compute/metadata"
"golang.org/x/oauth2" "golang.org/x/oauth2"
"golang.org/x/oauth2/jwt" "golang.org/x/oauth2/jwt"
"google.golang.org/cloud/compute/metadata"
) )
// Endpoint is Google's OAuth 2.0 endpoint. // Endpoint is Google's OAuth 2.0 endpoint.
...@@ -37,9 +37,10 @@ const JWTTokenURL = "https://accounts.google.com/o/oauth2/token" ...@@ -37,9 +37,10 @@ const JWTTokenURL = "https://accounts.google.com/o/oauth2/token"
// ConfigFromJSON uses a Google Developers Console client_credentials.json // ConfigFromJSON uses a Google Developers Console client_credentials.json
// file to construct a config. // file to construct a config.
// client_credentials.json can be downloadable from https://console.developers.google.com, // client_credentials.json can be downloaded from
// under "APIs & Auth" > "Credentials". Download the Web application credentials in the // https://console.developers.google.com, under "Credentials". Download the Web
// JSON format and provide the contents of the file as jsonKey. // application credentials in the JSON format and provide the contents of the
// file as jsonKey.
func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) { func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
type cred struct { type cred struct {
ClientID string `json:"client_id"` ClientID string `json:"client_id"`
...@@ -81,22 +82,29 @@ func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) { ...@@ -81,22 +82,29 @@ func ConfigFromJSON(jsonKey []byte, scope ...string) (*oauth2.Config, error) {
// JWTConfigFromJSON uses a Google Developers service account JSON key file to read // JWTConfigFromJSON uses a Google Developers service account JSON key file to read
// the credentials that authorize and authenticate the requests. // the credentials that authorize and authenticate the requests.
// Create a service account on "Credentials" page under "APIs & Auth" for your // Create a service account on "Credentials" for your project at
// project at https://console.developers.google.com to download a JSON key file. // https://console.developers.google.com to download a JSON key file.
func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) { func JWTConfigFromJSON(jsonKey []byte, scope ...string) (*jwt.Config, error) {
var key struct { var key struct {
Email string `json:"client_email"` Email string `json:"client_email"`
PrivateKey string `json:"private_key"` PrivateKey string `json:"private_key"`
PrivateKeyID string `json:"private_key_id"`
TokenURL string `json:"token_uri"`
} }
if err := json.Unmarshal(jsonKey, &key); err != nil { if err := json.Unmarshal(jsonKey, &key); err != nil {
return nil, err return nil, err
} }
return &jwt.Config{ config := &jwt.Config{
Email: key.Email, Email: key.Email,
PrivateKey: []byte(key.PrivateKey), PrivateKey: []byte(key.PrivateKey),
Scopes: scope, PrivateKeyID: key.PrivateKeyID,
TokenURL: JWTTokenURL, Scopes: scope,
}, nil TokenURL: key.TokenURL,
}
if config.TokenURL == "" {
config.TokenURL = JWTTokenURL
}
return config, nil
} }
// ComputeTokenSource returns a token source that fetches access tokens // ComputeTokenSource returns a token source that fetches access tokens
......
// Copyright 2015 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.
package google
import (
"crypto/rsa"
"fmt"
"time"
"golang.org/x/oauth2"
"golang.org/x/oauth2/internal"
"golang.org/x/oauth2/jws"
)
// JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
// key file to read the credentials that authorize and authenticate the
// requests, and returns a TokenSource that does not use any OAuth2 flow but
// instead creates a JWT and sends that as the access token.
// The audience is typically a URL that specifies the scope of the credentials.
//
// Note that this is not a standard OAuth flow, but rather an
// optimization supported by a few Google services.
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
cfg, err := JWTConfigFromJSON(jsonKey)
if err != nil {
return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
}
pk, err := internal.ParseKey(cfg.PrivateKey)
if err != nil {
return nil, fmt.Errorf("google: could not parse key: %v", err)
}
ts := &jwtAccessTokenSource{
email: cfg.Email,
audience: audience,
pk: pk,
pkID: cfg.PrivateKeyID,
}
tok, err := ts.Token()
if err != nil {
return nil, err
}
return oauth2.ReuseTokenSource(tok, ts), nil
}
type jwtAccessTokenSource struct {
email, audience string
pk *rsa.PrivateKey
pkID string
}
func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
iat := time.Now()
exp := iat.Add(time.Hour)
cs := &jws.ClaimSet{
Iss: ts.email,
Sub: ts.email,
Aud: ts.audience,
Iat: iat.Unix(),
Exp: exp.Unix(),
}
hdr := &jws.Header{
Algorithm: "RS256",
Typ: "JWT",
KeyID: string(ts.pkID),
}
msg, err := jws.Encode(hdr, cs, ts.pk)
if err != nil {
return nil, fmt.Errorf("google: could not encode JWT: %v", err)
}
return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
}
// Copyright 2015 The oauth2 Authors. All rights reserved. // Copyright 2015 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -91,24 +91,36 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error { ...@@ -91,24 +91,36 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
var brokenAuthHeaderProviders = []string{ var brokenAuthHeaderProviders = []string{
"https://accounts.google.com/", "https://accounts.google.com/",
"https://www.googleapis.com/",
"https://github.com/",
"https://api.instagram.com/",
"https://www.douban.com/",
"https://api.dropbox.com/", "https://api.dropbox.com/",
"https://api.dropboxapi.com/",
"https://api.instagram.com/",
"https://api.netatmo.net/",
"https://api.odnoklassniki.ru/",
"https://api.pushbullet.com/",
"https://api.soundcloud.com/", "https://api.soundcloud.com/",
"https://www.linkedin.com/",
"https://api.twitch.tv/", "https://api.twitch.tv/",
"https://oauth.vk.com/", "https://app.box.com/",
"https://api.odnoklassniki.ru/",
"https://connect.stripe.com/", "https://connect.stripe.com/",
"https://api.pushbullet.com/", "https://login.microsoftonline.com/",
"https://login.salesforce.com/",
"https://oauth.sandbox.trainingpeaks.com/", "https://oauth.sandbox.trainingpeaks.com/",
"https://oauth.trainingpeaks.com/", "https://oauth.trainingpeaks.com/",
"https://www.strava.com/oauth/", "https://oauth.vk.com/",
"https://app.box.com/", "https://openapi.baidu.com/",
"https://slack.com/",
"https://test-sandbox.auth.corp.google.com", "https://test-sandbox.auth.corp.google.com",
"https://test.salesforce.com/",
"https://user.gini.net/", "https://user.gini.net/",
"https://www.douban.com/",
"https://www.googleapis.com/",
"https://www.linkedin.com/",
"https://www.strava.com/oauth/",
"https://www.wunderlist.com/oauth/",
"https://api.patreon.com/",
}
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
} }
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL // providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
...@@ -134,23 +146,23 @@ func providerAuthHeaderWorks(tokenURL string) bool { ...@@ -134,23 +146,23 @@ func providerAuthHeaderWorks(tokenURL string) bool {
return true return true
} }
func RetrieveToken(ctx context.Context, ClientID, ClientSecret, TokenURL string, v url.Values) (*Token, error) { func RetrieveToken(ctx context.Context, clientID, clientSecret, tokenURL string, v url.Values) (*Token, error) {
hc, err := ContextClient(ctx) hc, err := ContextClient(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
v.Set("client_id", ClientID) v.Set("client_id", clientID)
bustedAuth := !providerAuthHeaderWorks(TokenURL) bustedAuth := !providerAuthHeaderWorks(tokenURL)
if bustedAuth && ClientSecret != "" { if bustedAuth && clientSecret != "" {
v.Set("client_secret", ClientSecret) v.Set("client_secret", clientSecret)
} }
req, err := http.NewRequest("POST", TokenURL, strings.NewReader(v.Encode())) req, err := http.NewRequest("POST", tokenURL, strings.NewReader(v.Encode()))
if err != nil { if err != nil {
return nil, err return nil, err
} }
req.Header.Set("Content-Type", "application/x-www-form-urlencoded") req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
if !bustedAuth { if !bustedAuth {
req.SetBasicAuth(ClientID, ClientSecret) req.SetBasicAuth(clientID, clientSecret)
} }
r, err := hc.Do(req) r, err := hc.Do(req)
if err != nil { if err != nil {
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -33,6 +33,11 @@ func RegisterContextClientFunc(fn ContextClientFunc) { ...@@ -33,6 +33,11 @@ func RegisterContextClientFunc(fn ContextClientFunc) {
} }
func ContextClient(ctx context.Context) (*http.Client, error) { func ContextClient(ctx context.Context) (*http.Client, error) {
if ctx != nil {
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
return hc, nil
}
}
for _, fn := range contextClientFuncs { for _, fn := range contextClientFuncs {
c, err := fn(ctx) c, err := fn(ctx)
if err != nil { if err != nil {
...@@ -42,9 +47,6 @@ func ContextClient(ctx context.Context) (*http.Client, error) { ...@@ -42,9 +47,6 @@ func ContextClient(ctx context.Context) (*http.Client, error) {
return c, nil return c, nil
} }
} }
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
return hc, nil
}
return http.DefaultClient, nil return http.DefaultClient, nil
} }
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
// Package jws provides encoding and decoding utilities for // Package jws provides a partial implementation
// signed JWS messages. // of JSON Web Signature encoding and decoding.
// It exists to support the golang.org/x/oauth2 package.
//
// See RFC 7515.
//
// Deprecated: this package is not intended for public use and might be
// removed in the future. It exists for internal use only.
// Please switch to another JWS package or copy this package into your own
// source tree.
package jws package jws
import ( import (
...@@ -27,8 +35,8 @@ type ClaimSet struct { ...@@ -27,8 +35,8 @@ type ClaimSet struct {
Iss string `json:"iss"` // email address of the client_id of the application making the access token request Iss string `json:"iss"` // email address of the client_id of the application making the access token request
Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional). Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional).
Exp int64 `json:"exp"` // the expiration time of the assertion Exp int64 `json:"exp"` // the expiration time of the assertion (seconds since Unix epoch)
Iat int64 `json:"iat"` // the time the assertion was issued. Iat int64 `json:"iat"` // the time the assertion was issued (seconds since Unix epoch)
Typ string `json:"typ,omitempty"` // token type (Optional). Typ string `json:"typ,omitempty"` // token type (Optional).
// Email for which the application is requesting delegated access (Optional). // Email for which the application is requesting delegated access (Optional).
...@@ -41,23 +49,22 @@ type ClaimSet struct { ...@@ -41,23 +49,22 @@ type ClaimSet struct {
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3 // See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
// This array is marshalled using custom code (see (c *ClaimSet) encode()). // This array is marshalled using custom code (see (c *ClaimSet) encode()).
PrivateClaims map[string]interface{} `json:"-"` PrivateClaims map[string]interface{} `json:"-"`
exp time.Time
iat time.Time
} }
func (c *ClaimSet) encode() (string, error) { func (c *ClaimSet) encode() (string, error) {
if c.exp.IsZero() || c.iat.IsZero() { // Reverting time back for machines whose time is not perfectly in sync.
// Reverting time back for machines whose time is not perfectly in sync. // If client machine's time is in the future according
// If client machine's time is in the future according // to Google servers, an access token will not be issued.
// to Google servers, an access token will not be issued. now := time.Now().Add(-10 * time.Second)
now := time.Now().Add(-10 * time.Second) if c.Iat == 0 {
c.iat = now c.Iat = now.Unix()
c.exp = now.Add(time.Hour) }
if c.Exp == 0 {
c.Exp = now.Add(time.Hour).Unix()
}
if c.Exp < c.Iat {
return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
} }
c.Exp = c.exp.Unix()
c.Iat = c.iat.Unix()
b, err := json.Marshal(c) b, err := json.Marshal(c)
if err != nil { if err != nil {
...@@ -65,7 +72,7 @@ func (c *ClaimSet) encode() (string, error) { ...@@ -65,7 +72,7 @@ func (c *ClaimSet) encode() (string, error) {
} }
if len(c.PrivateClaims) == 0 { if len(c.PrivateClaims) == 0 {
return base64Encode(b), nil return base64.RawURLEncoding.EncodeToString(b), nil
} }
// Marshal private claim set and then append it to b. // Marshal private claim set and then append it to b.
...@@ -83,7 +90,7 @@ func (c *ClaimSet) encode() (string, error) { ...@@ -83,7 +90,7 @@ func (c *ClaimSet) encode() (string, error) {
} }
b[len(b)-1] = ',' // Replace closing curly brace with a comma. b[len(b)-1] = ',' // Replace closing curly brace with a comma.
b = append(b, prv[1:]...) // Append private claims. b = append(b, prv[1:]...) // Append private claims.
return base64Encode(b), nil return base64.RawURLEncoding.EncodeToString(b), nil
} }
// Header represents the header for the signed JWS payloads. // Header represents the header for the signed JWS payloads.
...@@ -93,6 +100,9 @@ type Header struct { ...@@ -93,6 +100,9 @@ type Header struct {
// Represents the token type. // Represents the token type.
Typ string `json:"typ"` Typ string `json:"typ"`
// The optional hint of which key is being used.
KeyID string `json:"kid,omitempty"`
} }
func (h *Header) encode() (string, error) { func (h *Header) encode() (string, error) {
...@@ -100,7 +110,7 @@ func (h *Header) encode() (string, error) { ...@@ -100,7 +110,7 @@ func (h *Header) encode() (string, error) {
if err != nil { if err != nil {
return "", err return "", err
} }
return base64Encode(b), nil return base64.RawURLEncoding.EncodeToString(b), nil
} }
// Decode decodes a claim set from a JWS payload. // Decode decodes a claim set from a JWS payload.
...@@ -111,7 +121,7 @@ func Decode(payload string) (*ClaimSet, error) { ...@@ -111,7 +121,7 @@ func Decode(payload string) (*ClaimSet, error) {
// TODO(jbd): Provide more context about the error. // TODO(jbd): Provide more context about the error.
return nil, errors.New("jws: invalid token received") return nil, errors.New("jws: invalid token received")
} }
decoded, err := base64Decode(s[1]) decoded, err := base64.RawURLEncoding.DecodeString(s[1])
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -120,8 +130,11 @@ func Decode(payload string) (*ClaimSet, error) { ...@@ -120,8 +130,11 @@ func Decode(payload string) (*ClaimSet, error) {
return c, err return c, err
} }
// Encode encodes a signed JWS with provided header and claim set. // Signer returns a signature for the given data.
func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) { type Signer func(data []byte) (sig []byte, err error)
// EncodeWithSigner encodes a header and claim set with the provided signer.
func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
head, err := header.encode() head, err := header.encode()
if err != nil { if err != nil {
return "", err return "", err
...@@ -131,30 +144,39 @@ func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, err ...@@ -131,30 +144,39 @@ func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, err
return "", err return "", err
} }
ss := fmt.Sprintf("%s.%s", head, cs) ss := fmt.Sprintf("%s.%s", head, cs)
h := sha256.New() sig, err := sg([]byte(ss))
h.Write([]byte(ss))
b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil))
if err != nil { if err != nil {
return "", err return "", err
} }
sig := base64Encode(b) return fmt.Sprintf("%s.%s", ss, base64.RawURLEncoding.EncodeToString(sig)), nil
return fmt.Sprintf("%s.%s", ss, sig), nil
} }
// base64Encode returns and Base64url encoded version of the input string with any // Encode encodes a signed JWS with provided header and claim set.
// trailing "=" stripped. // This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
func base64Encode(b []byte) string { func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") sg := func(data []byte) (sig []byte, err error) {
h := sha256.New()
h.Write(data)
return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
}
return EncodeWithSigner(header, c, sg)
} }
// base64Decode decodes the Base64url encoded string // Verify tests whether the provided JWT token's signature was produced by the private key
func base64Decode(s string) ([]byte, error) { // associated with the supplied public key.
// add back missing padding func Verify(token string, key *rsa.PublicKey) error {
switch len(s) % 4 { parts := strings.Split(token, ".")
case 2: if len(parts) != 3 {
s += "==" return errors.New("jws: invalid token received, token must have 3 parts")
case 3:
s += "="
} }
return base64.URLEncoding.DecodeString(s)
signedContent := parts[0] + "." + parts[1]
signatureString, err := base64.RawURLEncoding.DecodeString(parts[2])
if err != nil {
return err
}
h := sha256.New()
h.Write([]byte(signedContent))
return rsa.VerifyPKCS1v15(key, crypto.SHA256, h.Sum(nil), []byte(signatureString))
} }
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -46,6 +46,10 @@ type Config struct { ...@@ -46,6 +46,10 @@ type Config struct {
// //
PrivateKey []byte PrivateKey []byte
// PrivateKeyID contains an optional hint indicating which key is being
// used.
PrivateKeyID string
// Subject is the optional user to impersonate. // Subject is the optional user to impersonate.
Subject string Subject string
...@@ -54,6 +58,9 @@ type Config struct { ...@@ -54,6 +58,9 @@ type Config struct {
// TokenURL is the endpoint required to complete the 2-legged JWT flow. // TokenURL is the endpoint required to complete the 2-legged JWT flow.
TokenURL string TokenURL string
// Expires optionally specifies how long the token is valid for.
Expires time.Duration
} }
// TokenSource returns a JWT TokenSource using the configuration // TokenSource returns a JWT TokenSource using the configuration
...@@ -95,6 +102,9 @@ func (js jwtSource) Token() (*oauth2.Token, error) { ...@@ -95,6 +102,9 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
// to be compatible with legacy OAuth 2.0 providers. // to be compatible with legacy OAuth 2.0 providers.
claimSet.Prn = subject claimSet.Prn = subject
} }
if t := js.conf.Expires; t > 0 {
claimSet.Exp = time.Now().Add(t).Unix()
}
payload, err := jws.Encode(defaultHeader, claimSet, pk) payload, err := jws.Encode(defaultHeader, claimSet, pk)
if err != nil { if err != nil {
return nil, err return nil, err
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -21,10 +21,26 @@ import ( ...@@ -21,10 +21,26 @@ import (
// NoContext is the default context you should supply if not using // NoContext is the default context you should supply if not using
// your own context.Context (see https://golang.org/x/net/context). // your own context.Context (see https://golang.org/x/net/context).
//
// Deprecated: Use context.Background() or context.TODO() instead.
var NoContext = context.TODO() var NoContext = context.TODO()
// RegisterBrokenAuthHeaderProvider registers an OAuth2 server
// identified by the tokenURL prefix as an OAuth2 implementation
// which doesn't support the HTTP Basic authentication
// scheme to authenticate with the authorization server.
// Once a server is registered, credentials (client_id and client_secret)
// will be passed as query parameters rather than being present
// in the Authorization header.
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
internal.RegisterBrokenAuthHeaderProvider(tokenURL)
}
// Config describes a typical 3-legged OAuth2 flow, with both the // Config describes a typical 3-legged OAuth2 flow, with both the
// client application information and the server's endpoint URLs. // client application information and the server's endpoint URLs.
// For the client credentials 2-legged OAuth2 flow, see the clientcredentials
// package (https://golang.org/x/oauth2/clientcredentials).
type Config struct { type Config struct {
// ClientID is the application's ID. // ClientID is the application's ID.
ClientID string ClientID string
...@@ -283,7 +299,7 @@ func NewClient(ctx context.Context, src TokenSource) *http.Client { ...@@ -283,7 +299,7 @@ func NewClient(ctx context.Context, src TokenSource) *http.Client {
if src == nil { if src == nil {
c, err := internal.ContextClient(ctx) c, err := internal.ContextClient(ctx)
if err != nil { if err != nil {
return &http.Client{Transport: internal.ErrorTransport{err}} return &http.Client{Transport: internal.ErrorTransport{Err: err}}
} }
return c return c
} }
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
...@@ -7,6 +7,7 @@ package oauth2 ...@@ -7,6 +7,7 @@ package oauth2
import ( import (
"net/http" "net/http"
"net/url" "net/url"
"strconv"
"strings" "strings"
"time" "time"
...@@ -92,14 +93,28 @@ func (t *Token) WithExtra(extra interface{}) *Token { ...@@ -92,14 +93,28 @@ func (t *Token) WithExtra(extra interface{}) *Token {
// Extra fields are key-value pairs returned by the server as a // Extra fields are key-value pairs returned by the server as a
// part of the token retrieval response. // part of the token retrieval response.
func (t *Token) Extra(key string) interface{} { func (t *Token) Extra(key string) interface{} {
if vals, ok := t.raw.(url.Values); ok {
// TODO(jbd): Cast numeric values to int64 or float64.
return vals.Get(key)
}
if raw, ok := t.raw.(map[string]interface{}); ok { if raw, ok := t.raw.(map[string]interface{}); ok {
return raw[key] return raw[key]
} }
return nil
vals, ok := t.raw.(url.Values)
if !ok {
return nil
}
v := vals.Get(key)
switch s := strings.TrimSpace(v); strings.Count(s, ".") {
case 0: // Contains no "."; try to parse as int
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
return i
}
case 1: // Contains a single "."; try to parse as float
if f, err := strconv.ParseFloat(s, 64); err == nil {
return f
}
}
return v
} }
// expired reports whether the token is expired. // expired reports whether the token is expired.
......
// Copyright 2014 The oauth2 Authors. All rights reserved. // Copyright 2014 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
......
...@@ -771,25 +771,23 @@ func (c *MetricDescriptorsCreateCall) Context(ctx context.Context) *MetricDescri ...@@ -771,25 +771,23 @@ func (c *MetricDescriptorsCreateCall) Context(ctx context.Context) *MetricDescri
} }
func (c *MetricDescriptorsCreateCall) doRequest(alt string) (*http.Response, error) { func (c *MetricDescriptorsCreateCall) doRequest(alt string) (*http.Response, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", c.s.userAgent())
var body io.Reader = nil var body io.Reader = nil
body, err := googleapi.WithoutDataWrapper.JSONReader(c.metricdescriptor) body, err := googleapi.WithoutDataWrapper.JSONReader(c.metricdescriptor)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctype := "application/json" reqHeaders.Set("Content-Type", "application/json")
c.urlParams_.Set("alt", alt) c.urlParams_.Set("alt", alt)
urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/metricDescriptors") urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/metricDescriptors")
urls += "?" + c.urlParams_.Encode() urls += "?" + c.urlParams_.Encode()
req, _ := http.NewRequest("POST", urls, body) req, _ := http.NewRequest("POST", urls, body)
req.Header = reqHeaders
googleapi.Expand(req.URL, map[string]string{ googleapi.Expand(req.URL, map[string]string{
"project": c.project, "project": c.project,
}) })
req.Header.Set("Content-Type", ctype) return gensupport.SendRequest(c.ctx_, c.s.client, req)
req.Header.Set("User-Agent", c.s.userAgent())
if c.ctx_ != nil {
return ctxhttp.Do(c.ctx_, c.s.client, req)
}
return c.s.client.Do(req)
} }
// Do executes the "cloudmonitoring.metricDescriptors.create" call. // Do executes the "cloudmonitoring.metricDescriptors.create" call.
...@@ -824,7 +822,8 @@ func (c *MetricDescriptorsCreateCall) Do(opts ...googleapi.CallOption) (*MetricD ...@@ -824,7 +822,8 @@ func (c *MetricDescriptorsCreateCall) Do(opts ...googleapi.CallOption) (*MetricD
HTTPStatusCode: res.StatusCode, HTTPStatusCode: res.StatusCode,
}, },
} }
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { target := &ret
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
return nil, err return nil, err
} }
return ret, nil return ret, nil
...@@ -893,20 +892,19 @@ func (c *MetricDescriptorsDeleteCall) Context(ctx context.Context) *MetricDescri ...@@ -893,20 +892,19 @@ func (c *MetricDescriptorsDeleteCall) Context(ctx context.Context) *MetricDescri
} }
func (c *MetricDescriptorsDeleteCall) doRequest(alt string) (*http.Response, error) { func (c *MetricDescriptorsDeleteCall) doRequest(alt string) (*http.Response, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", c.s.userAgent())
var body io.Reader = nil var body io.Reader = nil
c.urlParams_.Set("alt", alt) c.urlParams_.Set("alt", alt)
urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/metricDescriptors/{metric}") urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/metricDescriptors/{metric}")
urls += "?" + c.urlParams_.Encode() urls += "?" + c.urlParams_.Encode()
req, _ := http.NewRequest("DELETE", urls, body) req, _ := http.NewRequest("DELETE", urls, body)
req.Header = reqHeaders
googleapi.Expand(req.URL, map[string]string{ googleapi.Expand(req.URL, map[string]string{
"project": c.project, "project": c.project,
"metric": c.metric, "metric": c.metric,
}) })
req.Header.Set("User-Agent", c.s.userAgent()) return gensupport.SendRequest(c.ctx_, c.s.client, req)
if c.ctx_ != nil {
return ctxhttp.Do(c.ctx_, c.s.client, req)
}
return c.s.client.Do(req)
} }
// Do executes the "cloudmonitoring.metricDescriptors.delete" call. // Do executes the "cloudmonitoring.metricDescriptors.delete" call.
...@@ -941,7 +939,8 @@ func (c *MetricDescriptorsDeleteCall) Do(opts ...googleapi.CallOption) (*DeleteM ...@@ -941,7 +939,8 @@ func (c *MetricDescriptorsDeleteCall) Do(opts ...googleapi.CallOption) (*DeleteM
HTTPStatusCode: res.StatusCode, HTTPStatusCode: res.StatusCode,
}, },
} }
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { target := &ret
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
return nil, err return nil, err
} }
return ret, nil return ret, nil
...@@ -1057,22 +1056,21 @@ func (c *MetricDescriptorsListCall) Context(ctx context.Context) *MetricDescript ...@@ -1057,22 +1056,21 @@ func (c *MetricDescriptorsListCall) Context(ctx context.Context) *MetricDescript
} }
func (c *MetricDescriptorsListCall) doRequest(alt string) (*http.Response, error) { func (c *MetricDescriptorsListCall) doRequest(alt string) (*http.Response, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", c.s.userAgent())
if c.ifNoneMatch_ != "" {
reqHeaders.Set("If-None-Match", c.ifNoneMatch_)
}
var body io.Reader = nil var body io.Reader = nil
c.urlParams_.Set("alt", alt) c.urlParams_.Set("alt", alt)
urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/metricDescriptors") urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/metricDescriptors")
urls += "?" + c.urlParams_.Encode() urls += "?" + c.urlParams_.Encode()
req, _ := http.NewRequest("GET", urls, body) req, _ := http.NewRequest("GET", urls, body)
req.Header = reqHeaders
googleapi.Expand(req.URL, map[string]string{ googleapi.Expand(req.URL, map[string]string{
"project": c.project, "project": c.project,
}) })
req.Header.Set("User-Agent", c.s.userAgent()) return gensupport.SendRequest(c.ctx_, c.s.client, req)
if c.ifNoneMatch_ != "" {
req.Header.Set("If-None-Match", c.ifNoneMatch_)
}
if c.ctx_ != nil {
return ctxhttp.Do(c.ctx_, c.s.client, req)
}
return c.s.client.Do(req)
} }
// Do executes the "cloudmonitoring.metricDescriptors.list" call. // Do executes the "cloudmonitoring.metricDescriptors.list" call.
...@@ -1107,7 +1105,8 @@ func (c *MetricDescriptorsListCall) Do(opts ...googleapi.CallOption) (*ListMetri ...@@ -1107,7 +1105,8 @@ func (c *MetricDescriptorsListCall) Do(opts ...googleapi.CallOption) (*ListMetri
HTTPStatusCode: res.StatusCode, HTTPStatusCode: res.StatusCode,
}, },
} }
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { target := &ret
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
return nil, err return nil, err
} }
return ret, nil return ret, nil
...@@ -1321,23 +1320,22 @@ func (c *TimeseriesListCall) Context(ctx context.Context) *TimeseriesListCall { ...@@ -1321,23 +1320,22 @@ func (c *TimeseriesListCall) Context(ctx context.Context) *TimeseriesListCall {
} }
func (c *TimeseriesListCall) doRequest(alt string) (*http.Response, error) { func (c *TimeseriesListCall) doRequest(alt string) (*http.Response, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", c.s.userAgent())
if c.ifNoneMatch_ != "" {
reqHeaders.Set("If-None-Match", c.ifNoneMatch_)
}
var body io.Reader = nil var body io.Reader = nil
c.urlParams_.Set("alt", alt) c.urlParams_.Set("alt", alt)
urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/timeseries/{metric}") urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/timeseries/{metric}")
urls += "?" + c.urlParams_.Encode() urls += "?" + c.urlParams_.Encode()
req, _ := http.NewRequest("GET", urls, body) req, _ := http.NewRequest("GET", urls, body)
req.Header = reqHeaders
googleapi.Expand(req.URL, map[string]string{ googleapi.Expand(req.URL, map[string]string{
"project": c.project, "project": c.project,
"metric": c.metric, "metric": c.metric,
}) })
req.Header.Set("User-Agent", c.s.userAgent()) return gensupport.SendRequest(c.ctx_, c.s.client, req)
if c.ifNoneMatch_ != "" {
req.Header.Set("If-None-Match", c.ifNoneMatch_)
}
if c.ctx_ != nil {
return ctxhttp.Do(c.ctx_, c.s.client, req)
}
return c.s.client.Do(req)
} }
// Do executes the "cloudmonitoring.timeseries.list" call. // Do executes the "cloudmonitoring.timeseries.list" call.
...@@ -1372,7 +1370,8 @@ func (c *TimeseriesListCall) Do(opts ...googleapi.CallOption) (*ListTimeseriesRe ...@@ -1372,7 +1370,8 @@ func (c *TimeseriesListCall) Do(opts ...googleapi.CallOption) (*ListTimeseriesRe
HTTPStatusCode: res.StatusCode, HTTPStatusCode: res.StatusCode,
}, },
} }
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { target := &ret
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
return nil, err return nil, err
} }
return ret, nil return ret, nil
...@@ -1538,25 +1537,23 @@ func (c *TimeseriesWriteCall) Context(ctx context.Context) *TimeseriesWriteCall ...@@ -1538,25 +1537,23 @@ func (c *TimeseriesWriteCall) Context(ctx context.Context) *TimeseriesWriteCall
} }
func (c *TimeseriesWriteCall) doRequest(alt string) (*http.Response, error) { func (c *TimeseriesWriteCall) doRequest(alt string) (*http.Response, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", c.s.userAgent())
var body io.Reader = nil var body io.Reader = nil
body, err := googleapi.WithoutDataWrapper.JSONReader(c.writetimeseriesrequest) body, err := googleapi.WithoutDataWrapper.JSONReader(c.writetimeseriesrequest)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ctype := "application/json" reqHeaders.Set("Content-Type", "application/json")
c.urlParams_.Set("alt", alt) c.urlParams_.Set("alt", alt)
urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/timeseries:write") urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/timeseries:write")
urls += "?" + c.urlParams_.Encode() urls += "?" + c.urlParams_.Encode()
req, _ := http.NewRequest("POST", urls, body) req, _ := http.NewRequest("POST", urls, body)
req.Header = reqHeaders
googleapi.Expand(req.URL, map[string]string{ googleapi.Expand(req.URL, map[string]string{
"project": c.project, "project": c.project,
}) })
req.Header.Set("Content-Type", ctype) return gensupport.SendRequest(c.ctx_, c.s.client, req)
req.Header.Set("User-Agent", c.s.userAgent())
if c.ctx_ != nil {
return ctxhttp.Do(c.ctx_, c.s.client, req)
}
return c.s.client.Do(req)
} }
// Do executes the "cloudmonitoring.timeseries.write" call. // Do executes the "cloudmonitoring.timeseries.write" call.
...@@ -1591,7 +1588,8 @@ func (c *TimeseriesWriteCall) Do(opts ...googleapi.CallOption) (*WriteTimeseries ...@@ -1591,7 +1588,8 @@ func (c *TimeseriesWriteCall) Do(opts ...googleapi.CallOption) (*WriteTimeseries
HTTPStatusCode: res.StatusCode, HTTPStatusCode: res.StatusCode,
}, },
} }
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { target := &ret
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
return nil, err return nil, err
} }
return ret, nil return ret, nil
...@@ -1766,23 +1764,22 @@ func (c *TimeseriesDescriptorsListCall) Context(ctx context.Context) *Timeseries ...@@ -1766,23 +1764,22 @@ func (c *TimeseriesDescriptorsListCall) Context(ctx context.Context) *Timeseries
} }
func (c *TimeseriesDescriptorsListCall) doRequest(alt string) (*http.Response, error) { func (c *TimeseriesDescriptorsListCall) doRequest(alt string) (*http.Response, error) {
reqHeaders := make(http.Header)
reqHeaders.Set("User-Agent", c.s.userAgent())
if c.ifNoneMatch_ != "" {
reqHeaders.Set("If-None-Match", c.ifNoneMatch_)
}
var body io.Reader = nil var body io.Reader = nil
c.urlParams_.Set("alt", alt) c.urlParams_.Set("alt", alt)
urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/timeseriesDescriptors/{metric}") urls := googleapi.ResolveRelative(c.s.BasePath, "{project}/timeseriesDescriptors/{metric}")
urls += "?" + c.urlParams_.Encode() urls += "?" + c.urlParams_.Encode()
req, _ := http.NewRequest("GET", urls, body) req, _ := http.NewRequest("GET", urls, body)
req.Header = reqHeaders
googleapi.Expand(req.URL, map[string]string{ googleapi.Expand(req.URL, map[string]string{
"project": c.project, "project": c.project,
"metric": c.metric, "metric": c.metric,
}) })
req.Header.Set("User-Agent", c.s.userAgent()) return gensupport.SendRequest(c.ctx_, c.s.client, req)
if c.ifNoneMatch_ != "" {
req.Header.Set("If-None-Match", c.ifNoneMatch_)
}
if c.ctx_ != nil {
return ctxhttp.Do(c.ctx_, c.s.client, req)
}
return c.s.client.Do(req)
} }
// Do executes the "cloudmonitoring.timeseriesDescriptors.list" call. // Do executes the "cloudmonitoring.timeseriesDescriptors.list" call.
...@@ -1818,7 +1815,8 @@ func (c *TimeseriesDescriptorsListCall) Do(opts ...googleapi.CallOption) (*ListT ...@@ -1818,7 +1815,8 @@ func (c *TimeseriesDescriptorsListCall) Do(opts ...googleapi.CallOption) (*ListT
HTTPStatusCode: res.StatusCode, HTTPStatusCode: res.StatusCode,
}, },
} }
if err := json.NewDecoder(res.Body).Decode(&ret); err != nil { target := &ret
if err := json.NewDecoder(res.Body).Decode(target); err != nil {
return nil, err return nil, err
} }
return ret, nil return ret, nil
......
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -12,7 +12,6 @@ import ( ...@@ -12,7 +12,6 @@ import (
"time" "time"
"golang.org/x/net/context" "golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
) )
const ( const (
...@@ -80,7 +79,7 @@ func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader, ...@@ -80,7 +79,7 @@ func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader,
req.Header.Set("Content-Range", contentRange) req.Header.Set("Content-Range", contentRange)
req.Header.Set("Content-Type", rx.MediaType) req.Header.Set("Content-Type", rx.MediaType)
req.Header.Set("User-Agent", rx.UserAgent) req.Header.Set("User-Agent", rx.UserAgent)
return ctxhttp.Do(ctx, rx.Client, req) return SendRequest(ctx, rx.Client, req)
} }
...@@ -135,6 +134,8 @@ func contextDone(ctx context.Context) bool { ...@@ -135,6 +134,8 @@ func contextDone(ctx context.Context) bool {
// It retries using the provided back off strategy until cancelled or the // It retries using the provided back off strategy until cancelled or the
// strategy indicates to stop retrying. // strategy indicates to stop retrying.
// It is called from the auto-generated API code and is not visible to the user. // It is called from the auto-generated API code and is not visible to the user.
// Before sending an HTTP request, Upload calls any registered hook functions,
// and calls the returned functions after the request returns (see send.go).
// rx is private to the auto-generated API code. // rx is private to the auto-generated API code.
// Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close. // Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close.
func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) { func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) {
......
// Copyright 2016 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.
package gensupport
import (
"net/http"
"golang.org/x/net/context"
"golang.org/x/net/context/ctxhttp"
)
// Hook is the type of a function that is called once before each HTTP request
// that is sent by a generated API. It returns a function that is called after
// the request returns.
// Hooks are not called if the context is nil.
type Hook func(ctx context.Context, req *http.Request) func(resp *http.Response)
var hooks []Hook
// RegisterHook registers a Hook to be called before each HTTP request by a
// generated API. Hooks are called in the order they are registered. Each
// hook can return a function; if it is non-nil, it is called after the HTTP
// request returns. These functions are called in the reverse order.
// RegisterHook should not be called concurrently with itself or SendRequest.
func RegisterHook(h Hook) {
hooks = append(hooks, h)
}
// SendRequest sends a single HTTP request using the given client.
// If ctx is non-nil, it calls all hooks, then sends the request with
// ctxhttp.Do, then calls any functions returned by the hooks in reverse order.
func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
if ctx == nil {
return client.Do(req)
}
// Call hooks in order of registration, store returned funcs.
post := make([]func(resp *http.Response), len(hooks))
for i, h := range hooks {
fn := h(ctx, req)
post[i] = fn
}
// Send request.
resp, err := ctxhttp.Do(ctx, client, req)
// Call returned funcs in reverse order.
for i := len(post) - 1; i >= 0; i-- {
if fn := post[i]; fn != nil {
fn(resp)
}
}
return resp, err
}
...@@ -149,12 +149,12 @@ func IsNotModified(err error) bool { ...@@ -149,12 +149,12 @@ func IsNotModified(err error) bool {
// CheckMediaResponse returns an error (of type *Error) if the response // CheckMediaResponse returns an error (of type *Error) if the response
// status code is not 2xx. Unlike CheckResponse it does not assume the // status code is not 2xx. Unlike CheckResponse it does not assume the
// body is a JSON error document. // body is a JSON error document.
// It is the caller's responsibility to close res.Body.
func CheckMediaResponse(res *http.Response) error { func CheckMediaResponse(res *http.Response) error {
if res.StatusCode >= 200 && res.StatusCode <= 299 { if res.StatusCode >= 200 && res.StatusCode <= 299 {
return nil return nil
} }
slurp, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20)) slurp, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20))
res.Body.Close()
return &Error{ return &Error{
Code: res.StatusCode, Code: res.StatusCode,
Body: string(slurp), Body: string(slurp),
...@@ -278,41 +278,15 @@ func ResolveRelative(basestr, relstr string) string { ...@@ -278,41 +278,15 @@ func ResolveRelative(basestr, relstr string) string {
return us return us
} }
// has4860Fix is whether this Go environment contains the fix for
// http://golang.org/issue/4860
var has4860Fix bool
// init initializes has4860Fix by checking the behavior of the net/http package.
func init() {
r := http.Request{
URL: &url.URL{
Scheme: "http",
Opaque: "//opaque",
},
}
b := &bytes.Buffer{}
r.Write(b)
has4860Fix = bytes.HasPrefix(b.Bytes(), []byte("GET http"))
}
// SetOpaque sets u.Opaque from u.Path such that HTTP requests to it
// don't alter any hex-escaped characters in u.Path.
func SetOpaque(u *url.URL) {
u.Opaque = "//" + u.Host + u.Path
if !has4860Fix {
u.Opaque = u.Scheme + ":" + u.Opaque
}
}
// Expand subsitutes any {encoded} strings in the URL passed in using // Expand subsitutes any {encoded} strings in the URL passed in using
// the map supplied. // the map supplied.
// //
// This calls SetOpaque to avoid encoding of the parameters in the URL path. // This calls SetOpaque to avoid encoding of the parameters in the URL path.
func Expand(u *url.URL, expansions map[string]string) { func Expand(u *url.URL, expansions map[string]string) {
expanded, err := uritemplates.Expand(u.Path, expansions) escaped, unescaped, err := uritemplates.Expand(u.Path, expansions)
if err == nil { if err == nil {
u.Path = expanded u.Path = unescaped
SetOpaque(u) u.RawPath = escaped
} }
} }
......
...@@ -34,11 +34,37 @@ func pctEncode(src []byte) []byte { ...@@ -34,11 +34,37 @@ func pctEncode(src []byte) []byte {
return dst return dst
} }
func escape(s string, allowReserved bool) string { // pairWriter is a convenience struct which allows escaped and unescaped
// versions of the template to be written in parallel.
type pairWriter struct {
escaped, unescaped bytes.Buffer
}
// Write writes the provided string directly without any escaping.
func (w *pairWriter) Write(s string) {
w.escaped.WriteString(s)
w.unescaped.WriteString(s)
}
// Escape writes the provided string, escaping the string for the
// escaped output.
func (w *pairWriter) Escape(s string, allowReserved bool) {
w.unescaped.WriteString(s)
if allowReserved { if allowReserved {
return string(reserved.ReplaceAllFunc([]byte(s), pctEncode)) w.escaped.Write(reserved.ReplaceAllFunc([]byte(s), pctEncode))
} else {
w.escaped.Write(unreserved.ReplaceAllFunc([]byte(s), pctEncode))
} }
return string(unreserved.ReplaceAllFunc([]byte(s), pctEncode)) }
// Escaped returns the escaped string.
func (w *pairWriter) Escaped() string {
return w.escaped.String()
}
// Unescaped returns the unescaped string.
func (w *pairWriter) Unescaped() string {
return w.unescaped.String()
} }
// A uriTemplate is a parsed representation of a URI template. // A uriTemplate is a parsed representation of a URI template.
...@@ -170,18 +196,20 @@ func parseTerm(term string) (result templateTerm, err error) { ...@@ -170,18 +196,20 @@ func parseTerm(term string) (result templateTerm, err error) {
return result, err return result, err
} }
// Expand expands a URI template with a set of values to produce a string. // Expand expands a URI template with a set of values to produce the
func (t *uriTemplate) Expand(values map[string]string) string { // resultant URI. Two forms of the result are returned: one with all the
var buf bytes.Buffer // elements escaped, and one with the elements unescaped.
func (t *uriTemplate) Expand(values map[string]string) (escaped, unescaped string) {
var w pairWriter
for _, p := range t.parts { for _, p := range t.parts {
p.expand(&buf, values) p.expand(&w, values)
} }
return buf.String() return w.Escaped(), w.Unescaped()
} }
func (tp *templatePart) expand(buf *bytes.Buffer, values map[string]string) { func (tp *templatePart) expand(w *pairWriter, values map[string]string) {
if len(tp.raw) > 0 { if len(tp.raw) > 0 {
buf.WriteString(tp.raw) w.Write(tp.raw)
return return
} }
var first = true var first = true
...@@ -191,30 +219,30 @@ func (tp *templatePart) expand(buf *bytes.Buffer, values map[string]string) { ...@@ -191,30 +219,30 @@ func (tp *templatePart) expand(buf *bytes.Buffer, values map[string]string) {
continue continue
} }
if first { if first {
buf.WriteString(tp.first) w.Write(tp.first)
first = false first = false
} else { } else {
buf.WriteString(tp.sep) w.Write(tp.sep)
} }
tp.expandString(buf, term, value) tp.expandString(w, term, value)
} }
} }
func (tp *templatePart) expandName(buf *bytes.Buffer, name string, empty bool) { func (tp *templatePart) expandName(w *pairWriter, name string, empty bool) {
if tp.named { if tp.named {
buf.WriteString(name) w.Write(name)
if empty { if empty {
buf.WriteString(tp.ifemp) w.Write(tp.ifemp)
} else { } else {
buf.WriteString("=") w.Write("=")
} }
} }
} }
func (tp *templatePart) expandString(buf *bytes.Buffer, t templateTerm, s string) { func (tp *templatePart) expandString(w *pairWriter, t templateTerm, s string) {
if len(s) > t.truncate && t.truncate > 0 { if len(s) > t.truncate && t.truncate > 0 {
s = s[:t.truncate] s = s[:t.truncate]
} }
tp.expandName(buf, t.name, len(s) == 0) tp.expandName(w, t.name, len(s) == 0)
buf.WriteString(escape(s, tp.allowReserved)) w.Escape(s, tp.allowReserved)
} }
...@@ -4,10 +4,14 @@ ...@@ -4,10 +4,14 @@
package uritemplates package uritemplates
func Expand(path string, values map[string]string) (string, error) { // Expand parses then expands a URI template with a set of values to produce
// the resultant URI. Two forms of the result are returned: one with all the
// elements escaped, and one with the elements unescaped.
func Expand(path string, values map[string]string) (escaped, unescaped string, err error) {
template, err := parse(path) template, err := parse(path)
if err != nil { if err != nil {
return "", err return "", "", err
} }
return template.Expand(values), nil escaped, unescaped = template.Expand(values)
return escaped, unescaped, nil
} }
language: go
go:
- 1.6.3
- 1.7rc6
install:
- go get -v -t -d google.golang.org/appengine/...
- mkdir sdk
- curl -o sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.40.zip"
- unzip sdk.zip -d sdk
- export APPENGINE_DEV_APPSERVER=$(pwd)/sdk/go_appengine/dev_appserver.py
script:
- go version
- go test -v google.golang.org/appengine/...
- go test -v -race google.golang.org/appengine/...
- sdk/go_appengine/goapp test -v google.golang.org/appengine/...
...@@ -187,7 +187,7 @@ ...@@ -187,7 +187,7 @@
same "printed page" as the copyright notice for easier same "printed page" as the copyright notice for easier
identification within third-party archives. identification within third-party archives.
Copyright 2014 Google Inc. Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.
......
# Go App Engine packages
[![Build Status](https://travis-ci.org/golang/appengine.svg)](https://travis-ci.org/golang/appengine)
This repository supports the Go runtime on App Engine,
including both the standard App Engine and the
"App Engine flexible environment" (formerly known as "Managed VMs").
It provides APIs for interacting with App Engine services.
Its canonical import path is `google.golang.org/appengine`.
See https://cloud.google.com/appengine/docs/go/
for more information.
File issue reports and feature requests on the [Google App Engine issue
tracker](https://code.google.com/p/googleappengine/issues/entry?template=Go%20defect).
## Directory structure
The top level directory of this repository is the `appengine` package. It
contains the
basic APIs (e.g. `appengine.NewContext`) that apply across APIs. Specific API
packages are in subdirectories (e.g. `datastore`).
There is an `internal` subdirectory that contains service protocol buffers,
plus packages required for connectivity to make API calls. App Engine apps
should not directly import any package under `internal`.
## Updating a Go App Engine app
This section describes how to update an older Go App Engine app to use
these packages. A provided tool, `aefix`, can help automate steps 2 and 3
(run `go get google.golang.org/appengine/cmd/aefix` to install it), but
read the details below since `aefix` can't perform all the changes.
### 1. Update YAML files (App Engine flexible environment / Managed VMs only)
The `app.yaml` file (and YAML files for modules) should have these new lines added:
```
vm: true
```
See https://cloud.google.com/appengine/docs/go/modules/#Go_Instance_scaling_and_class for details.
### 2. Update import paths
The import paths for App Engine packages are now fully qualified, based at `google.golang.org/appengine`.
You will need to update your code to use import paths starting with that; for instance,
code importing `appengine/datastore` will now need to import `google.golang.org/appengine/datastore`.
### 3. Update code using deprecated, removed or modified APIs
Most App Engine services are available with exactly the same API.
A few APIs were cleaned up, and some are not available yet.
This list summarises the differences:
* `appengine.Context` has been replaced with the `Context` type from `golang.org/x/net/context`.
* Logging methods that were on `appengine.Context` are now functions in `google.golang.org/appengine/log`.
* `appengine.Timeout` has been removed. Use `context.WithTimeout` instead.
* `appengine.Datacenter` now takes a `context.Context` argument.
* `datastore.PropertyLoadSaver` has been simplified to use slices in place of channels.
* `delay.Call` now returns an error.
* `search.FieldLoadSaver` now handles document metadata.
* `urlfetch.Transport` no longer has a Deadline field; set a deadline on the
`context.Context` instead.
* `aetest` no longer declares its own Context type, and uses the standard one instead.
* `taskqueue.QueueStats` no longer takes a maxTasks argument. That argument has been
deprecated and unused for a long time.
* `appengine.BackendHostname` and `appengine.BackendInstance` were for the deprecated backends feature.
Use `appengine.ModuleHostname`and `appengine.ModuleName` instead.
* Most of `appengine/file` and parts of `appengine/blobstore` are deprecated.
Use [Google Cloud Storage](https://godoc.org/google.golang.org/cloud/storage) instead.
* `appengine/socket` is not required on App Engine flexible environment / Managed VMs.
Use the standard `net` package instead.
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// Package appengine provides basic functionality for Google App Engine.
//
// For more information on how to write Go apps for Google App Engine, see:
// https://cloud.google.com/appengine/docs/go/
package appengine
import (
"net/http"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"google.golang.org/appengine/internal"
)
// The gophers party all night; the rabbits provide the beats.
// Main is the principal entry point for an app running in App Engine.
//
// On App Engine Flexible it installs a trivial health checker if one isn't
// already registered, and starts listening on port 8080 (overridden by the
// $PORT environment variable).
//
// See https://cloud.google.com/appengine/docs/flexible/custom-runtimes#health_check_requests
// for details on how to do your own health checking.
//
// Main is not yet supported on App Engine Standard.
//
// Main never returns.
//
// Main is designed so that the app's main package looks like this:
//
// package main
//
// import (
// "google.golang.org/appengine"
//
// _ "myapp/package0"
// _ "myapp/package1"
// )
//
// func main() {
// appengine.Main()
// }
//
// The "myapp/packageX" packages are expected to register HTTP handlers
// in their init functions.
func Main() {
internal.Main()
}
// IsDevAppServer reports whether the App Engine app is running in the
// development App Server.
func IsDevAppServer() bool {
return internal.IsDevAppServer()
}
// NewContext returns a context for an in-flight HTTP request.
// This function is cheap.
func NewContext(req *http.Request) context.Context {
return WithContext(context.Background(), req)
}
// WithContext returns a copy of the parent context
// and associates it with an in-flight HTTP request.
// This function is cheap.
func WithContext(parent context.Context, req *http.Request) context.Context {
return internal.WithContext(parent, req)
}
// TODO(dsymonds): Add a Call function here? Otherwise other packages can't access internal.Call.
// BlobKey is a key for a blobstore blob.
//
// Conceptually, this type belongs in the blobstore package, but it lives in
// the appengine package to avoid a circular dependency: blobstore depends on
// datastore, and datastore needs to refer to the BlobKey type.
type BlobKey string
// GeoPoint represents a location as latitude/longitude in degrees.
type GeoPoint struct {
Lat, Lng float64
}
// Valid returns whether a GeoPoint is within [-90, 90] latitude and [-180, 180] longitude.
func (g GeoPoint) Valid() bool {
return -90 <= g.Lat && g.Lat <= 90 && -180 <= g.Lng && g.Lng <= 180
}
// APICallFunc defines a function type for handling an API call.
// See WithCallOverride.
type APICallFunc func(ctx context.Context, service, method string, in, out proto.Message) error
// WithAPICallFunc returns a copy of the parent context
// that will cause API calls to invoke f instead of their normal operation.
//
// This is intended for advanced users only.
func WithAPICallFunc(ctx context.Context, f APICallFunc) context.Context {
return internal.WithCallOverride(ctx, internal.CallOverrideFunc(f))
}
// APICall performs an API call.
//
// This is not intended for general use; it is exported for use in conjunction
// with WithAPICallFunc.
func APICall(ctx context.Context, service, method string, in, out proto.Message) error {
return internal.Call(ctx, service, method, in, out)
}
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package appengine
import (
"golang.org/x/net/context"
"google.golang.org/appengine/internal"
)
// BackgroundContext returns a context not associated with a request.
// This should only be used when not servicing a request.
// This only works in App Engine "flexible environment".
func BackgroundContext() context.Context {
return internal.BackgroundContext()
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// This file provides error functions for common API failure modes.
package appengine
import (
"fmt"
"google.golang.org/appengine/internal"
)
// IsOverQuota reports whether err represents an API call failure
// due to insufficient available quota.
func IsOverQuota(err error) bool {
callErr, ok := err.(*internal.CallError)
return ok && callErr.Code == 4
}
// MultiError is returned by batch operations when there are errors with
// particular elements. Errors will be in a one-to-one correspondence with
// the input elements; successful elements will have a nil entry.
type MultiError []error
func (m MultiError) Error() string {
s, n := "", 0
for _, e := range m {
if e != nil {
if n == 0 {
s = e.Error()
}
n++
}
}
switch n {
case 0:
return "(0 errors)"
case 1:
return s
case 2:
return s + " (and 1 other error)"
}
return fmt.Sprintf("%s (and %d other errors)", s, n-1)
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package appengine
import (
"time"
"golang.org/x/net/context"
"google.golang.org/appengine/internal"
pb "google.golang.org/appengine/internal/app_identity"
modpb "google.golang.org/appengine/internal/modules"
)
// AppID returns the application ID for the current application.
// The string will be a plain application ID (e.g. "appid"), with a
// domain prefix for custom domain deployments (e.g. "example.com:appid").
func AppID(c context.Context) string { return internal.AppID(c) }
// DefaultVersionHostname returns the standard hostname of the default version
// of the current application (e.g. "my-app.appspot.com"). This is suitable for
// use in constructing URLs.
func DefaultVersionHostname(c context.Context) string {
return internal.DefaultVersionHostname(c)
}
// ModuleName returns the module name of the current instance.
func ModuleName(c context.Context) string {
return internal.ModuleName(c)
}
// ModuleHostname returns a hostname of a module instance.
// If module is the empty string, it refers to the module of the current instance.
// If version is empty, it refers to the version of the current instance if valid,
// or the default version of the module of the current instance.
// If instance is empty, ModuleHostname returns the load-balancing hostname.
func ModuleHostname(c context.Context, module, version, instance string) (string, error) {
req := &modpb.GetHostnameRequest{}
if module != "" {
req.Module = &module
}
if version != "" {
req.Version = &version
}
if instance != "" {
req.Instance = &instance
}
res := &modpb.GetHostnameResponse{}
if err := internal.Call(c, "modules", "GetHostname", req, res); err != nil {
return "", err
}
return *res.Hostname, nil
}
// VersionID returns the version ID for the current application.
// It will be of the form "X.Y", where X is specified in app.yaml,
// and Y is a number generated when each version of the app is uploaded.
// It does not include a module name.
func VersionID(c context.Context) string { return internal.VersionID(c) }
// InstanceID returns a mostly-unique identifier for this instance.
func InstanceID() string { return internal.InstanceID() }
// Datacenter returns an identifier for the datacenter that the instance is running in.
func Datacenter(c context.Context) string { return internal.Datacenter(c) }
// ServerSoftware returns the App Engine release version.
// In production, it looks like "Google App Engine/X.Y.Z".
// In the development appserver, it looks like "Development/X.Y".
func ServerSoftware() string { return internal.ServerSoftware() }
// RequestID returns a string that uniquely identifies the request.
func RequestID(c context.Context) string { return internal.RequestID(c) }
// AccessToken generates an OAuth2 access token for the specified scopes on
// behalf of service account of this application. This token will expire after
// the returned time.
func AccessToken(c context.Context, scopes ...string) (token string, expiry time.Time, err error) {
req := &pb.GetAccessTokenRequest{Scope: scopes}
res := &pb.GetAccessTokenResponse{}
err = internal.Call(c, "app_identity_service", "GetAccessToken", req, res)
if err != nil {
return "", time.Time{}, err
}
return res.GetAccessToken(), time.Unix(res.GetExpirationTime(), 0), nil
}
// Certificate represents a public certificate for the app.
type Certificate struct {
KeyName string
Data []byte // PEM-encoded X.509 certificate
}
// PublicCertificates retrieves the public certificates for the app.
// They can be used to verify a signature returned by SignBytes.
func PublicCertificates(c context.Context) ([]Certificate, error) {
req := &pb.GetPublicCertificateForAppRequest{}
res := &pb.GetPublicCertificateForAppResponse{}
if err := internal.Call(c, "app_identity_service", "GetPublicCertificatesForApp", req, res); err != nil {
return nil, err
}
var cs []Certificate
for _, pc := range res.PublicCertificateList {
cs = append(cs, Certificate{
KeyName: pc.GetKeyName(),
Data: []byte(pc.GetX509CertificatePem()),
})
}
return cs, nil
}
// ServiceAccount returns a string representing the service account name, in
// the form of an email address (typically app_id@appspot.gserviceaccount.com).
func ServiceAccount(c context.Context) (string, error) {
req := &pb.GetServiceAccountNameRequest{}
res := &pb.GetServiceAccountNameResponse{}
err := internal.Call(c, "app_identity_service", "GetServiceAccountName", req, res)
if err != nil {
return "", err
}
return res.GetServiceAccountName(), err
}
// SignBytes signs bytes using a private key unique to your application.
func SignBytes(c context.Context, bytes []byte) (keyName string, signature []byte, err error) {
req := &pb.SignForAppRequest{BytesToSign: bytes}
res := &pb.SignForAppResponse{}
if err := internal.Call(c, "app_identity_service", "SignForApp", req, res); err != nil {
return "", nil, err
}
return res.GetKeyName(), res.GetSignatureBytes(), nil
}
func init() {
internal.RegisterErrorCodeMap("app_identity_service", pb.AppIdentityServiceError_ErrorCode_name)
internal.RegisterErrorCodeMap("modules", modpb.ModulesServiceError_ErrorCode_name)
}
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appengine
package internal
import (
"errors"
"fmt"
"net/http"
"time"
"appengine"
"appengine_internal"
basepb "appengine_internal/base"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
)
var contextKey = "holds an appengine.Context"
func fromContext(ctx netcontext.Context) appengine.Context {
c, _ := ctx.Value(&contextKey).(appengine.Context)
return c
}
// This is only for classic App Engine adapters.
func ClassicContextFromContext(ctx netcontext.Context) appengine.Context {
return fromContext(ctx)
}
func withContext(parent netcontext.Context, c appengine.Context) netcontext.Context {
ctx := netcontext.WithValue(parent, &contextKey, c)
s := &basepb.StringProto{}
c.Call("__go__", "GetNamespace", &basepb.VoidProto{}, s, nil)
if ns := s.GetValue(); ns != "" {
ctx = NamespacedContext(ctx, ns)
}
return ctx
}
func IncomingHeaders(ctx netcontext.Context) http.Header {
if c := fromContext(ctx); c != nil {
if req, ok := c.Request().(*http.Request); ok {
return req.Header
}
}
return nil
}
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
c := appengine.NewContext(req)
return withContext(parent, c)
}
type testingContext struct {
appengine.Context
req *http.Request
}
func (t *testingContext) FullyQualifiedAppID() string { return "dev~testcontext" }
func (t *testingContext) Call(service, method string, _, _ appengine_internal.ProtoMessage, _ *appengine_internal.CallOptions) error {
if service == "__go__" && method == "GetNamespace" {
return nil
}
return fmt.Errorf("testingContext: unsupported Call")
}
func (t *testingContext) Request() interface{} { return t.req }
func ContextForTesting(req *http.Request) netcontext.Context {
return withContext(netcontext.Background(), &testingContext{req: req})
}
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
if ns := NamespaceFromContext(ctx); ns != "" {
if fn, ok := NamespaceMods[service]; ok {
fn(in, ns)
}
}
if f, ctx, ok := callOverrideFromContext(ctx); ok {
return f(ctx, service, method, in, out)
}
// Handle already-done contexts quickly.
select {
case <-ctx.Done():
return ctx.Err()
default:
}
c := fromContext(ctx)
if c == nil {
// Give a good error message rather than a panic lower down.
return errors.New("not an App Engine context")
}
// Apply transaction modifications if we're in a transaction.
if t := transactionFromContext(ctx); t != nil {
if t.finished {
return errors.New("transaction context has expired")
}
applyTransaction(in, &t.transaction)
}
var opts *appengine_internal.CallOptions
if d, ok := ctx.Deadline(); ok {
opts = &appengine_internal.CallOptions{
Timeout: d.Sub(time.Now()),
}
}
err := c.Call(service, method, in, out, opts)
switch v := err.(type) {
case *appengine_internal.APIError:
return &APIError{
Service: v.Service,
Detail: v.Detail,
Code: v.Code,
}
case *appengine_internal.CallError:
return &CallError{
Detail: v.Detail,
Code: v.Code,
Timeout: v.Timeout,
}
}
return err
}
func handleHTTP(w http.ResponseWriter, r *http.Request) {
panic("handleHTTP called; this should be impossible")
}
func logf(c appengine.Context, level int64, format string, args ...interface{}) {
var fn func(format string, args ...interface{})
switch level {
case 0:
fn = c.Debugf
case 1:
fn = c.Infof
case 2:
fn = c.Warningf
case 3:
fn = c.Errorf
case 4:
fn = c.Criticalf
default:
// This shouldn't happen.
fn = c.Criticalf
}
fn(format, args...)
}
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
)
type CallOverrideFunc func(ctx netcontext.Context, service, method string, in, out proto.Message) error
var callOverrideKey = "holds []CallOverrideFunc"
func WithCallOverride(ctx netcontext.Context, f CallOverrideFunc) netcontext.Context {
// We avoid appending to any existing call override
// so we don't risk overwriting a popped stack below.
var cofs []CallOverrideFunc
if uf, ok := ctx.Value(&callOverrideKey).([]CallOverrideFunc); ok {
cofs = append(cofs, uf...)
}
cofs = append(cofs, f)
return netcontext.WithValue(ctx, &callOverrideKey, cofs)
}
func callOverrideFromContext(ctx netcontext.Context) (CallOverrideFunc, netcontext.Context, bool) {
cofs, _ := ctx.Value(&callOverrideKey).([]CallOverrideFunc)
if len(cofs) == 0 {
return nil, nil, false
}
// We found a list of overrides; grab the last, and reconstitute a
// context that will hide it.
f := cofs[len(cofs)-1]
ctx = netcontext.WithValue(ctx, &callOverrideKey, cofs[:len(cofs)-1])
return f, ctx, true
}
type logOverrideFunc func(level int64, format string, args ...interface{})
var logOverrideKey = "holds a logOverrideFunc"
func WithLogOverride(ctx netcontext.Context, f logOverrideFunc) netcontext.Context {
return netcontext.WithValue(ctx, &logOverrideKey, f)
}
var appIDOverrideKey = "holds a string, being the full app ID"
func WithAppIDOverride(ctx netcontext.Context, appID string) netcontext.Context {
return netcontext.WithValue(ctx, &appIDOverrideKey, appID)
}
var namespaceKey = "holds the namespace string"
func withNamespace(ctx netcontext.Context, ns string) netcontext.Context {
return netcontext.WithValue(ctx, &namespaceKey, ns)
}
func NamespaceFromContext(ctx netcontext.Context) string {
// If there's no namespace, return the empty string.
ns, _ := ctx.Value(&namespaceKey).(string)
return ns
}
// FullyQualifiedAppID returns the fully-qualified application ID.
// This may contain a partition prefix (e.g. "s~" for High Replication apps),
// or a domain prefix (e.g. "example.com:").
func FullyQualifiedAppID(ctx netcontext.Context) string {
if id, ok := ctx.Value(&appIDOverrideKey).(string); ok {
return id
}
return fullyQualifiedAppID(ctx)
}
func Logf(ctx netcontext.Context, level int64, format string, args ...interface{}) {
if f, ok := ctx.Value(&logOverrideKey).(logOverrideFunc); ok {
f(level, format, args...)
return
}
logf(fromContext(ctx), level, format, args...)
}
// NamespacedContext wraps a Context to support namespaces.
func NamespacedContext(ctx netcontext.Context, namespace string) netcontext.Context {
return withNamespace(ctx, namespace)
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import (
"strings"
)
func parseFullAppID(appid string) (partition, domain, displayID string) {
if i := strings.Index(appid, "~"); i != -1 {
partition, appid = appid[:i], appid[i+1:]
}
if i := strings.Index(appid, ":"); i != -1 {
domain, appid = appid[:i], appid[i+1:]
}
return partition, domain, appid
}
// appID returns "appid" or "domain.com:appid".
func appID(fullAppID string) string {
_, dom, dis := parseFullAppID(fullAppID)
if dom != "" {
return dom + ":" + dis
}
return dis
}
syntax = "proto2";
option go_package = "app_identity";
package appengine;
message AppIdentityServiceError {
enum ErrorCode {
SUCCESS = 0;
UNKNOWN_SCOPE = 9;
BLOB_TOO_LARGE = 1000;
DEADLINE_EXCEEDED = 1001;
NOT_A_VALID_APP = 1002;
UNKNOWN_ERROR = 1003;
NOT_ALLOWED = 1005;
NOT_IMPLEMENTED = 1006;
}
}
message SignForAppRequest {
optional bytes bytes_to_sign = 1;
}
message SignForAppResponse {
optional string key_name = 1;
optional bytes signature_bytes = 2;
}
message GetPublicCertificateForAppRequest {
}
message PublicCertificate {
optional string key_name = 1;
optional string x509_certificate_pem = 2;
}
message GetPublicCertificateForAppResponse {
repeated PublicCertificate public_certificate_list = 1;
optional int64 max_client_cache_time_in_second = 2;
}
message GetServiceAccountNameRequest {
}
message GetServiceAccountNameResponse {
optional string service_account_name = 1;
}
message GetAccessTokenRequest {
repeated string scope = 1;
optional int64 service_account_id = 2;
optional string service_account_name = 3;
}
message GetAccessTokenResponse {
optional string access_token = 1;
optional int64 expiration_time = 2;
}
message GetDefaultGcsBucketNameRequest {
}
message GetDefaultGcsBucketNameResponse {
optional string default_gcs_bucket_name = 1;
}
// Code generated by protoc-gen-go.
// source: google.golang.org/appengine/internal/base/api_base.proto
// DO NOT EDIT!
/*
Package base is a generated protocol buffer package.
It is generated from these files:
google.golang.org/appengine/internal/base/api_base.proto
It has these top-level messages:
StringProto
Integer32Proto
Integer64Proto
BoolProto
DoubleProto
BytesProto
VoidProto
*/
package base
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type StringProto struct {
Value *string `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *StringProto) Reset() { *m = StringProto{} }
func (m *StringProto) String() string { return proto.CompactTextString(m) }
func (*StringProto) ProtoMessage() {}
func (m *StringProto) GetValue() string {
if m != nil && m.Value != nil {
return *m.Value
}
return ""
}
type Integer32Proto struct {
Value *int32 `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Integer32Proto) Reset() { *m = Integer32Proto{} }
func (m *Integer32Proto) String() string { return proto.CompactTextString(m) }
func (*Integer32Proto) ProtoMessage() {}
func (m *Integer32Proto) GetValue() int32 {
if m != nil && m.Value != nil {
return *m.Value
}
return 0
}
type Integer64Proto struct {
Value *int64 `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Integer64Proto) Reset() { *m = Integer64Proto{} }
func (m *Integer64Proto) String() string { return proto.CompactTextString(m) }
func (*Integer64Proto) ProtoMessage() {}
func (m *Integer64Proto) GetValue() int64 {
if m != nil && m.Value != nil {
return *m.Value
}
return 0
}
type BoolProto struct {
Value *bool `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *BoolProto) Reset() { *m = BoolProto{} }
func (m *BoolProto) String() string { return proto.CompactTextString(m) }
func (*BoolProto) ProtoMessage() {}
func (m *BoolProto) GetValue() bool {
if m != nil && m.Value != nil {
return *m.Value
}
return false
}
type DoubleProto struct {
Value *float64 `protobuf:"fixed64,1,req,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *DoubleProto) Reset() { *m = DoubleProto{} }
func (m *DoubleProto) String() string { return proto.CompactTextString(m) }
func (*DoubleProto) ProtoMessage() {}
func (m *DoubleProto) GetValue() float64 {
if m != nil && m.Value != nil {
return *m.Value
}
return 0
}
type BytesProto struct {
Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *BytesProto) Reset() { *m = BytesProto{} }
func (m *BytesProto) String() string { return proto.CompactTextString(m) }
func (*BytesProto) ProtoMessage() {}
func (m *BytesProto) GetValue() []byte {
if m != nil {
return m.Value
}
return nil
}
type VoidProto struct {
XXX_unrecognized []byte `json:"-"`
}
func (m *VoidProto) Reset() { *m = VoidProto{} }
func (m *VoidProto) String() string { return proto.CompactTextString(m) }
func (*VoidProto) ProtoMessage() {}
// Built-in base types for API calls. Primarily useful as return types.
syntax = "proto2";
option go_package = "base";
package appengine.base;
message StringProto {
required string value = 1;
}
message Integer32Proto {
required int32 value = 1;
}
message Integer64Proto {
required int64 value = 1;
}
message BoolProto {
required bool value = 1;
}
message DoubleProto {
required double value = 1;
}
message BytesProto {
required bytes value = 1 [ctype=CORD];
}
message VoidProto {
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
import netcontext "golang.org/x/net/context"
// These functions are implementations of the wrapper functions
// in ../appengine/identity.go. See that file for commentary.
func AppID(c netcontext.Context) string {
return appID(FullyQualifiedAppID(c))
}
// Copyright 2015 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appengine
package internal
import (
"appengine"
netcontext "golang.org/x/net/context"
)
func DefaultVersionHostname(ctx netcontext.Context) string {
return appengine.DefaultVersionHostname(fromContext(ctx))
}
func RequestID(ctx netcontext.Context) string { return appengine.RequestID(fromContext(ctx)) }
func Datacenter(_ netcontext.Context) string { return appengine.Datacenter() }
func ServerSoftware() string { return appengine.ServerSoftware() }
func ModuleName(ctx netcontext.Context) string { return appengine.ModuleName(fromContext(ctx)) }
func VersionID(ctx netcontext.Context) string { return appengine.VersionID(fromContext(ctx)) }
func InstanceID() string { return appengine.InstanceID() }
func IsDevAppServer() bool { return appengine.IsDevAppServer() }
func fullyQualifiedAppID(ctx netcontext.Context) string { return fromContext(ctx).FullyQualifiedAppID() }
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"net/http"
"os"
netcontext "golang.org/x/net/context"
)
// These functions are implementations of the wrapper functions
// in ../appengine/identity.go. See that file for commentary.
const (
hDefaultVersionHostname = "X-AppEngine-Default-Version-Hostname"
hRequestLogId = "X-AppEngine-Request-Log-Id"
hDatacenter = "X-AppEngine-Datacenter"
)
func ctxHeaders(ctx netcontext.Context) http.Header {
return fromContext(ctx).Request().Header
}
func DefaultVersionHostname(ctx netcontext.Context) string {
return ctxHeaders(ctx).Get(hDefaultVersionHostname)
}
func RequestID(ctx netcontext.Context) string {
return ctxHeaders(ctx).Get(hRequestLogId)
}
func Datacenter(ctx netcontext.Context) string {
return ctxHeaders(ctx).Get(hDatacenter)
}
func ServerSoftware() string {
// TODO(dsymonds): Remove fallback when we've verified this.
if s := os.Getenv("SERVER_SOFTWARE"); s != "" {
return s
}
return "Google App Engine/1.x.x"
}
// TODO(dsymonds): Remove the metadata fetches.
func ModuleName(_ netcontext.Context) string {
if s := os.Getenv("GAE_MODULE_NAME"); s != "" {
return s
}
return string(mustGetMetadata("instance/attributes/gae_backend_name"))
}
func VersionID(_ netcontext.Context) string {
if s1, s2 := os.Getenv("GAE_MODULE_VERSION"), os.Getenv("GAE_MINOR_VERSION"); s1 != "" && s2 != "" {
return s1 + "." + s2
}
return string(mustGetMetadata("instance/attributes/gae_backend_version")) + "." + string(mustGetMetadata("instance/attributes/gae_backend_minor_version"))
}
func InstanceID() string {
if s := os.Getenv("GAE_MODULE_INSTANCE"); s != "" {
return s
}
return string(mustGetMetadata("instance/attributes/gae_backend_instance"))
}
func partitionlessAppID() string {
// gae_project has everything except the partition prefix.
appID := os.Getenv("GAE_LONG_APP_ID")
if appID == "" {
appID = string(mustGetMetadata("instance/attributes/gae_project"))
}
return appID
}
func fullyQualifiedAppID(_ netcontext.Context) string {
appID := partitionlessAppID()
part := os.Getenv("GAE_PARTITION")
if part == "" {
part = string(mustGetMetadata("instance/attributes/gae_partition"))
}
if part != "" {
appID = part + "~" + appID
}
return appID
}
func IsDevAppServer() bool {
return os.Getenv("RUN_WITH_DEVAPPSERVER") != ""
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// Package internal provides support for package appengine.
//
// Programs should not use this package directly. Its API is not stable.
// Use packages appengine and appengine/* instead.
package internal
import (
"fmt"
"github.com/golang/protobuf/proto"
remotepb "google.golang.org/appengine/internal/remote_api"
)
// errorCodeMaps is a map of service name to the error code map for the service.
var errorCodeMaps = make(map[string]map[int32]string)
// RegisterErrorCodeMap is called from API implementations to register their
// error code map. This should only be called from init functions.
func RegisterErrorCodeMap(service string, m map[int32]string) {
errorCodeMaps[service] = m
}
type timeoutCodeKey struct {
service string
code int32
}
// timeoutCodes is the set of service+code pairs that represent timeouts.
var timeoutCodes = make(map[timeoutCodeKey]bool)
func RegisterTimeoutErrorCode(service string, code int32) {
timeoutCodes[timeoutCodeKey{service, code}] = true
}
// APIError is the type returned by appengine.Context's Call method
// when an API call fails in an API-specific way. This may be, for instance,
// a taskqueue API call failing with TaskQueueServiceError::UNKNOWN_QUEUE.
type APIError struct {
Service string
Detail string
Code int32 // API-specific error code
}
func (e *APIError) Error() string {
if e.Code == 0 {
if e.Detail == "" {
return "APIError <empty>"
}
return e.Detail
}
s := fmt.Sprintf("API error %d", e.Code)
if m, ok := errorCodeMaps[e.Service]; ok {
s += " (" + e.Service + ": " + m[e.Code] + ")"
} else {
// Shouldn't happen, but provide a bit more detail if it does.
s = e.Service + " " + s
}
if e.Detail != "" {
s += ": " + e.Detail
}
return s
}
func (e *APIError) IsTimeout() bool {
return timeoutCodes[timeoutCodeKey{e.Service, e.Code}]
}
// CallError is the type returned by appengine.Context's Call method when an
// API call fails in a generic way, such as RpcError::CAPABILITY_DISABLED.
type CallError struct {
Detail string
Code int32
// TODO: Remove this if we get a distinguishable error code.
Timeout bool
}
func (e *CallError) Error() string {
var msg string
switch remotepb.RpcError_ErrorCode(e.Code) {
case remotepb.RpcError_UNKNOWN:
return e.Detail
case remotepb.RpcError_OVER_QUOTA:
msg = "Over quota"
case remotepb.RpcError_CAPABILITY_DISABLED:
msg = "Capability disabled"
case remotepb.RpcError_CANCELLED:
msg = "Canceled"
default:
msg = fmt.Sprintf("Call error %d", e.Code)
}
s := msg + ": " + e.Detail
if e.Timeout {
s += " (timeout)"
}
return s
}
func (e *CallError) IsTimeout() bool {
return e.Timeout
}
// NamespaceMods is a map from API service to a function that will mutate an RPC request to attach a namespace.
// The function should be prepared to be called on the same message more than once; it should only modify the
// RPC request the first time.
var NamespaceMods = make(map[string]func(m proto.Message, namespace string))
syntax = "proto2";
option go_package = "log";
package appengine;
message LogServiceError {
enum ErrorCode {
OK = 0;
INVALID_REQUEST = 1;
STORAGE_ERROR = 2;
}
}
message UserAppLogLine {
required int64 timestamp_usec = 1;
required int64 level = 2;
required string message = 3;
}
message UserAppLogGroup {
repeated UserAppLogLine log_line = 2;
}
message FlushRequest {
optional bytes logs = 1;
}
message SetStatusRequest {
required string status = 1;
}
message LogOffset {
optional bytes request_id = 1;
}
message LogLine {
required int64 time = 1;
required int32 level = 2;
required string log_message = 3;
}
message RequestLog {
required string app_id = 1;
optional string module_id = 37 [default="default"];
required string version_id = 2;
required bytes request_id = 3;
optional LogOffset offset = 35;
required string ip = 4;
optional string nickname = 5;
required int64 start_time = 6;
required int64 end_time = 7;
required int64 latency = 8;
required int64 mcycles = 9;
required string method = 10;
required string resource = 11;
required string http_version = 12;
required int32 status = 13;
required int64 response_size = 14;
optional string referrer = 15;
optional string user_agent = 16;
required string url_map_entry = 17;
required string combined = 18;
optional int64 api_mcycles = 19;
optional string host = 20;
optional double cost = 21;
optional string task_queue_name = 22;
optional string task_name = 23;
optional bool was_loading_request = 24;
optional int64 pending_time = 25;
optional int32 replica_index = 26 [default = -1];
optional bool finished = 27 [default = true];
optional bytes clone_key = 28;
repeated LogLine line = 29;
optional bool lines_incomplete = 36;
optional bytes app_engine_release = 38;
optional int32 exit_reason = 30;
optional bool was_throttled_for_time = 31;
optional bool was_throttled_for_requests = 32;
optional int64 throttled_time = 33;
optional bytes server_name = 34;
}
message LogModuleVersion {
optional string module_id = 1 [default="default"];
optional string version_id = 2;
}
message LogReadRequest {
required string app_id = 1;
repeated string version_id = 2;
repeated LogModuleVersion module_version = 19;
optional int64 start_time = 3;
optional int64 end_time = 4;
optional LogOffset offset = 5;
repeated bytes request_id = 6;
optional int32 minimum_log_level = 7;
optional bool include_incomplete = 8;
optional int64 count = 9;
optional string combined_log_regex = 14;
optional string host_regex = 15;
optional int32 replica_index = 16;
optional bool include_app_logs = 10;
optional int32 app_logs_per_request = 17;
optional bool include_host = 11;
optional bool include_all = 12;
optional bool cache_iterator = 13;
optional int32 num_shards = 18;
}
message LogReadResponse {
repeated RequestLog log = 1;
optional LogOffset offset = 2;
optional int64 last_end_time = 3;
}
message LogUsageRecord {
optional string version_id = 1;
optional int32 start_time = 2;
optional int32 end_time = 3;
optional int64 count = 4;
optional int64 total_size = 5;
optional int32 records = 6;
}
message LogUsageRequest {
required string app_id = 1;
repeated string version_id = 2;
optional int32 start_time = 3;
optional int32 end_time = 4;
optional uint32 resolution_hours = 5 [default = 1];
optional bool combine_versions = 6;
optional int32 usage_version = 7;
optional bool versions_only = 8;
}
message LogUsageResponse {
repeated LogUsageRecord usage = 1;
optional LogUsageRecord summary = 2;
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build appengine
package internal
import (
"appengine_internal"
)
func Main() {
appengine_internal.Main()
}
// Copyright 2011 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
// +build !appengine
package internal
import (
"io"
"log"
"net/http"
"net/url"
"os"
)
func Main() {
installHealthChecker(http.DefaultServeMux)
port := "8080"
if s := os.Getenv("PORT"); s != "" {
port = s
}
if err := http.ListenAndServe(":"+port, http.HandlerFunc(handleHTTP)); err != nil {
log.Fatalf("http.ListenAndServe: %v", err)
}
}
func installHealthChecker(mux *http.ServeMux) {
// If no health check handler has been installed by this point, add a trivial one.
const healthPath = "/_ah/health"
hreq := &http.Request{
Method: "GET",
URL: &url.URL{
Path: healthPath,
},
}
if _, pat := mux.Handler(hreq); pat != healthPath {
mux.HandleFunc(healthPath, func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "ok")
})
}
}
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
// This file has code for accessing metadata.
//
// References:
// https://cloud.google.com/compute/docs/metadata
import (
"fmt"
"io/ioutil"
"log"
"net/http"
"net/url"
)
const (
metadataHost = "metadata"
metadataPath = "/computeMetadata/v1/"
)
var (
metadataRequestHeaders = http.Header{
"Metadata-Flavor": []string{"Google"},
}
)
// TODO(dsymonds): Do we need to support default values, like Python?
func mustGetMetadata(key string) []byte {
b, err := getMetadata(key)
if err != nil {
log.Fatalf("Metadata fetch failed: %v", err)
}
return b
}
func getMetadata(key string) ([]byte, error) {
// TODO(dsymonds): May need to use url.Parse to support keys with query args.
req := &http.Request{
Method: "GET",
URL: &url.URL{
Scheme: "http",
Host: metadataHost,
Path: metadataPath + key,
},
Header: metadataRequestHeaders,
Host: metadataHost,
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != 200 {
return nil, fmt.Errorf("metadata server returned HTTP %d", resp.StatusCode)
}
return ioutil.ReadAll(resp.Body)
}
syntax = "proto2";
option go_package = "modules";
package appengine;
message ModulesServiceError {
enum ErrorCode {
OK = 0;
INVALID_MODULE = 1;
INVALID_VERSION = 2;
INVALID_INSTANCES = 3;
TRANSIENT_ERROR = 4;
UNEXPECTED_STATE = 5;
}
}
message GetModulesRequest {
}
message GetModulesResponse {
repeated string module = 1;
}
message GetVersionsRequest {
optional string module = 1;
}
message GetVersionsResponse {
repeated string version = 1;
}
message GetDefaultVersionRequest {
optional string module = 1;
}
message GetDefaultVersionResponse {
required string version = 1;
}
message GetNumInstancesRequest {
optional string module = 1;
optional string version = 2;
}
message GetNumInstancesResponse {
required int64 instances = 1;
}
message SetNumInstancesRequest {
optional string module = 1;
optional string version = 2;
required int64 instances = 3;
}
message SetNumInstancesResponse {}
message StartModuleRequest {
required string module = 1;
required string version = 2;
}
message StartModuleResponse {}
message StopModuleRequest {
optional string module = 1;
optional string version = 2;
}
message StopModuleResponse {}
message GetHostnameRequest {
optional string module = 1;
optional string version = 2;
optional string instance = 3;
}
message GetHostnameResponse {
required string hostname = 1;
}
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
// This file implements a network dialer that limits the number of concurrent connections.
// It is only used for API calls.
import (
"log"
"net"
"runtime"
"sync"
"time"
)
var limitSem = make(chan int, 100) // TODO(dsymonds): Use environment variable.
func limitRelease() {
// non-blocking
select {
case <-limitSem:
default:
// This should not normally happen.
log.Print("appengine: unbalanced limitSem release!")
}
}
func limitDial(network, addr string) (net.Conn, error) {
limitSem <- 1
// Dial with a timeout in case the API host is MIA.
// The connection should normally be very fast.
conn, err := net.DialTimeout(network, addr, 500*time.Millisecond)
if err != nil {
limitRelease()
return nil, err
}
lc := &limitConn{Conn: conn}
runtime.SetFinalizer(lc, (*limitConn).Close) // shouldn't usually be required
return lc, nil
}
type limitConn struct {
close sync.Once
net.Conn
}
func (lc *limitConn) Close() error {
defer lc.close.Do(func() {
limitRelease()
runtime.SetFinalizer(lc, nil)
})
return lc.Conn.Close()
}
#!/bin/bash -e
#
# This script rebuilds the generated code for the protocol buffers.
# To run this you will need protoc and goprotobuf installed;
# see https://github.com/golang/protobuf for instructions.
PKG=google.golang.org/appengine
function die() {
echo 1>&2 $*
exit 1
}
# Sanity check that the right tools are accessible.
for tool in go protoc protoc-gen-go; do
q=$(which $tool) || die "didn't find $tool"
echo 1>&2 "$tool: $q"
done
echo -n 1>&2 "finding package dir... "
pkgdir=$(go list -f '{{.Dir}}' $PKG)
echo 1>&2 $pkgdir
base=$(echo $pkgdir | sed "s,/$PKG\$,,")
echo 1>&2 "base: $base"
cd $base
# Run protoc once per package.
for dir in $(find $PKG/internal -name '*.proto' | xargs dirname | sort | uniq); do
echo 1>&2 "* $dir"
protoc --go_out=. $dir/*.proto
done
for f in $(find $PKG/internal -name '*.pb.go'); do
# Remove proto.RegisterEnum calls.
# These cause duplicate registration panics when these packages
# are used on classic App Engine. proto.RegisterEnum only affects
# parsing the text format; we don't care about that.
# https://code.google.com/p/googleappengine/issues/detail?id=11670#c17
sed -i '/proto.RegisterEnum/d' $f
done
// Code generated by protoc-gen-go.
// source: google.golang.org/appengine/internal/remote_api/remote_api.proto
// DO NOT EDIT!
/*
Package remote_api is a generated protocol buffer package.
It is generated from these files:
google.golang.org/appengine/internal/remote_api/remote_api.proto
It has these top-level messages:
Request
ApplicationError
RpcError
Response
*/
package remote_api
import proto "github.com/golang/protobuf/proto"
import fmt "fmt"
import math "math"
// Reference imports to suppress errors if they are not otherwise used.
var _ = proto.Marshal
var _ = fmt.Errorf
var _ = math.Inf
type RpcError_ErrorCode int32
const (
RpcError_UNKNOWN RpcError_ErrorCode = 0
RpcError_CALL_NOT_FOUND RpcError_ErrorCode = 1
RpcError_PARSE_ERROR RpcError_ErrorCode = 2
RpcError_SECURITY_VIOLATION RpcError_ErrorCode = 3
RpcError_OVER_QUOTA RpcError_ErrorCode = 4
RpcError_REQUEST_TOO_LARGE RpcError_ErrorCode = 5
RpcError_CAPABILITY_DISABLED RpcError_ErrorCode = 6
RpcError_FEATURE_DISABLED RpcError_ErrorCode = 7
RpcError_BAD_REQUEST RpcError_ErrorCode = 8
RpcError_RESPONSE_TOO_LARGE RpcError_ErrorCode = 9
RpcError_CANCELLED RpcError_ErrorCode = 10
RpcError_REPLAY_ERROR RpcError_ErrorCode = 11
RpcError_DEADLINE_EXCEEDED RpcError_ErrorCode = 12
)
var RpcError_ErrorCode_name = map[int32]string{
0: "UNKNOWN",
1: "CALL_NOT_FOUND",
2: "PARSE_ERROR",
3: "SECURITY_VIOLATION",
4: "OVER_QUOTA",
5: "REQUEST_TOO_LARGE",
6: "CAPABILITY_DISABLED",
7: "FEATURE_DISABLED",
8: "BAD_REQUEST",
9: "RESPONSE_TOO_LARGE",
10: "CANCELLED",
11: "REPLAY_ERROR",
12: "DEADLINE_EXCEEDED",
}
var RpcError_ErrorCode_value = map[string]int32{
"UNKNOWN": 0,
"CALL_NOT_FOUND": 1,
"PARSE_ERROR": 2,
"SECURITY_VIOLATION": 3,
"OVER_QUOTA": 4,
"REQUEST_TOO_LARGE": 5,
"CAPABILITY_DISABLED": 6,
"FEATURE_DISABLED": 7,
"BAD_REQUEST": 8,
"RESPONSE_TOO_LARGE": 9,
"CANCELLED": 10,
"REPLAY_ERROR": 11,
"DEADLINE_EXCEEDED": 12,
}
func (x RpcError_ErrorCode) Enum() *RpcError_ErrorCode {
p := new(RpcError_ErrorCode)
*p = x
return p
}
func (x RpcError_ErrorCode) String() string {
return proto.EnumName(RpcError_ErrorCode_name, int32(x))
}
func (x *RpcError_ErrorCode) UnmarshalJSON(data []byte) error {
value, err := proto.UnmarshalJSONEnum(RpcError_ErrorCode_value, data, "RpcError_ErrorCode")
if err != nil {
return err
}
*x = RpcError_ErrorCode(value)
return nil
}
type Request struct {
ServiceName *string `protobuf:"bytes,2,req,name=service_name" json:"service_name,omitempty"`
Method *string `protobuf:"bytes,3,req,name=method" json:"method,omitempty"`
Request []byte `protobuf:"bytes,4,req,name=request" json:"request,omitempty"`
RequestId *string `protobuf:"bytes,5,opt,name=request_id" json:"request_id,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Request) Reset() { *m = Request{} }
func (m *Request) String() string { return proto.CompactTextString(m) }
func (*Request) ProtoMessage() {}
func (m *Request) GetServiceName() string {
if m != nil && m.ServiceName != nil {
return *m.ServiceName
}
return ""
}
func (m *Request) GetMethod() string {
if m != nil && m.Method != nil {
return *m.Method
}
return ""
}
func (m *Request) GetRequest() []byte {
if m != nil {
return m.Request
}
return nil
}
func (m *Request) GetRequestId() string {
if m != nil && m.RequestId != nil {
return *m.RequestId
}
return ""
}
type ApplicationError struct {
Code *int32 `protobuf:"varint,1,req,name=code" json:"code,omitempty"`
Detail *string `protobuf:"bytes,2,req,name=detail" json:"detail,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *ApplicationError) Reset() { *m = ApplicationError{} }
func (m *ApplicationError) String() string { return proto.CompactTextString(m) }
func (*ApplicationError) ProtoMessage() {}
func (m *ApplicationError) GetCode() int32 {
if m != nil && m.Code != nil {
return *m.Code
}
return 0
}
func (m *ApplicationError) GetDetail() string {
if m != nil && m.Detail != nil {
return *m.Detail
}
return ""
}
type RpcError struct {
Code *int32 `protobuf:"varint,1,req,name=code" json:"code,omitempty"`
Detail *string `protobuf:"bytes,2,opt,name=detail" json:"detail,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *RpcError) Reset() { *m = RpcError{} }
func (m *RpcError) String() string { return proto.CompactTextString(m) }
func (*RpcError) ProtoMessage() {}
func (m *RpcError) GetCode() int32 {
if m != nil && m.Code != nil {
return *m.Code
}
return 0
}
func (m *RpcError) GetDetail() string {
if m != nil && m.Detail != nil {
return *m.Detail
}
return ""
}
type Response struct {
Response []byte `protobuf:"bytes,1,opt,name=response" json:"response,omitempty"`
Exception []byte `protobuf:"bytes,2,opt,name=exception" json:"exception,omitempty"`
ApplicationError *ApplicationError `protobuf:"bytes,3,opt,name=application_error" json:"application_error,omitempty"`
JavaException []byte `protobuf:"bytes,4,opt,name=java_exception" json:"java_exception,omitempty"`
RpcError *RpcError `protobuf:"bytes,5,opt,name=rpc_error" json:"rpc_error,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
func (m *Response) Reset() { *m = Response{} }
func (m *Response) String() string { return proto.CompactTextString(m) }
func (*Response) ProtoMessage() {}
func (m *Response) GetResponse() []byte {
if m != nil {
return m.Response
}
return nil
}
func (m *Response) GetException() []byte {
if m != nil {
return m.Exception
}
return nil
}
func (m *Response) GetApplicationError() *ApplicationError {
if m != nil {
return m.ApplicationError
}
return nil
}
func (m *Response) GetJavaException() []byte {
if m != nil {
return m.JavaException
}
return nil
}
func (m *Response) GetRpcError() *RpcError {
if m != nil {
return m.RpcError
}
return nil
}
func init() {
}
syntax = "proto2";
option go_package = "remote_api";
package remote_api;
message Request {
required string service_name = 2;
required string method = 3;
required bytes request = 4;
optional string request_id = 5;
}
message ApplicationError {
required int32 code = 1;
required string detail = 2;
}
message RpcError {
enum ErrorCode {
UNKNOWN = 0;
CALL_NOT_FOUND = 1;
PARSE_ERROR = 2;
SECURITY_VIOLATION = 3;
OVER_QUOTA = 4;
REQUEST_TOO_LARGE = 5;
CAPABILITY_DISABLED = 6;
FEATURE_DISABLED = 7;
BAD_REQUEST = 8;
RESPONSE_TOO_LARGE = 9;
CANCELLED = 10;
REPLAY_ERROR = 11;
DEADLINE_EXCEEDED = 12;
}
required int32 code = 1;
optional string detail = 2;
}
message Response {
optional bytes response = 1;
optional bytes exception = 2;
optional ApplicationError application_error = 3;
optional bytes java_exception = 4;
optional RpcError rpc_error = 5;
}
// Copyright 2014 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package internal
// This file implements hooks for applying datastore transactions.
import (
"errors"
"reflect"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
pb "google.golang.org/appengine/internal/datastore"
)
var transactionSetters = make(map[reflect.Type]reflect.Value)
// RegisterTransactionSetter registers a function that sets transaction information
// in a protocol buffer message. f should be a function with two arguments,
// the first being a protocol buffer type, and the second being *datastore.Transaction.
func RegisterTransactionSetter(f interface{}) {
v := reflect.ValueOf(f)
transactionSetters[v.Type().In(0)] = v
}
// applyTransaction applies the transaction t to message pb
// by using the relevant setter passed to RegisterTransactionSetter.
func applyTransaction(pb proto.Message, t *pb.Transaction) {
v := reflect.ValueOf(pb)
if f, ok := transactionSetters[v.Type()]; ok {
f.Call([]reflect.Value{v, reflect.ValueOf(t)})
}
}
var transactionKey = "used for *Transaction"
func transactionFromContext(ctx netcontext.Context) *transaction {
t, _ := ctx.Value(&transactionKey).(*transaction)
return t
}
func withTransaction(ctx netcontext.Context, t *transaction) netcontext.Context {
return netcontext.WithValue(ctx, &transactionKey, t)
}
type transaction struct {
transaction pb.Transaction
finished bool
}
var ErrConcurrentTransaction = errors.New("internal: concurrent transaction")
func RunTransactionOnce(c netcontext.Context, f func(netcontext.Context) error, xg bool) error {
if transactionFromContext(c) != nil {
return errors.New("nested transactions are not supported")
}
// Begin the transaction.
t := &transaction{}
req := &pb.BeginTransactionRequest{
App: proto.String(FullyQualifiedAppID(c)),
}
if xg {
req.AllowMultipleEg = proto.Bool(true)
}
if err := Call(c, "datastore_v3", "BeginTransaction", req, &t.transaction); err != nil {
return err
}
// Call f, rolling back the transaction if f returns a non-nil error, or panics.
// The panic is not recovered.
defer func() {
if t.finished {
return
}
t.finished = true
// Ignore the error return value, since we are already returning a non-nil
// error (or we're panicking).
Call(c, "datastore_v3", "Rollback", &t.transaction, &basepb.VoidProto{})
}()
if err := f(withTransaction(c, t)); err != nil {
return err
}
t.finished = true
// Commit the transaction.
res := &pb.CommitResponse{}
err := Call(c, "datastore_v3", "Commit", &t.transaction, res)
if ae, ok := err.(*APIError); ok {
/* TODO: restore this conditional
if appengine.IsDevAppServer() {
*/
// The Python Dev AppServer raises an ApplicationError with error code 2 (which is
// Error.CONCURRENT_TRANSACTION) and message "Concurrency exception.".
if ae.Code == int32(pb.Error_BAD_REQUEST) && ae.Detail == "ApplicationError: 2 Concurrency exception." {
return ErrConcurrentTransaction
}
if ae.Code == int32(pb.Error_CONCURRENT_TRANSACTION) {
return ErrConcurrentTransaction
}
}
return err
}
// Copyright 2012 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package appengine
import (
"fmt"
"regexp"
"golang.org/x/net/context"
"google.golang.org/appengine/internal"
)
// Namespace returns a replacement context that operates within the given namespace.
func Namespace(c context.Context, namespace string) (context.Context, error) {
if !validNamespace.MatchString(namespace) {
return nil, fmt.Errorf("appengine: namespace %q does not match /%s/", namespace, validNamespace)
}
return internal.NamespacedContext(c, namespace), nil
}
// validNamespace matches valid namespace names.
var validNamespace = regexp.MustCompile(`^[0-9A-Za-z._-]{0,100}$`)
// Copyright 2013 Google Inc. All rights reserved.
// Use of this source code is governed by the Apache 2.0
// license that can be found in the LICENSE file.
package appengine
import "golang.org/x/net/context"
// IsTimeoutError reports whether err is a timeout error.
func IsTimeoutError(err error) bool {
if err == context.DeadlineExceeded {
return true
}
if t, ok := err.(interface {
IsTimeout() bool
}); ok {
return t.IsTimeout()
}
return false
}
// Copyright 2014 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// Package internal provides support for the cloud packages.
//
// Users should not import this package directly.
package internal
import (
"fmt"
"net/http"
"sync"
"golang.org/x/net/context"
)
type contextKey struct{}
func WithContext(parent context.Context, projID string, c *http.Client) context.Context {
if c == nil {
panic("nil *http.Client passed to WithContext")
}
if projID == "" {
panic("empty project ID passed to WithContext")
}
return context.WithValue(parent, contextKey{}, &cloudContext{
ProjectID: projID,
HTTPClient: c,
})
}
const userAgent = "gcloud-golang/0.1"
type cloudContext struct {
ProjectID string
HTTPClient *http.Client
mu sync.Mutex // guards svc
svc map[string]interface{} // e.g. "storage" => *rawStorage.Service
}
// Service returns the result of the fill function if it's never been
// called before for the given name (which is assumed to be an API
// service name, like "datastore"). If it has already been cached, the fill
// func is not run.
// It's safe for concurrent use by multiple goroutines.
func Service(ctx context.Context, name string, fill func(*http.Client) interface{}) interface{} {
return cc(ctx).service(name, fill)
}
func (c *cloudContext) service(name string, fill func(*http.Client) interface{}) interface{} {
c.mu.Lock()
defer c.mu.Unlock()
if c.svc == nil {
c.svc = make(map[string]interface{})
} else if v, ok := c.svc[name]; ok {
return v
}
v := fill(c.HTTPClient)
c.svc[name] = v
return v
}
// Transport is an http.RoundTripper that appends
// Google Cloud client's user-agent to the original
// request's user-agent header.
type Transport struct {
// Base is the actual http.RoundTripper
// requests will use. It must not be nil.
Base http.RoundTripper
}
// RoundTrip appends a user-agent to the existing user-agent
// header and delegates the request to the base http.RoundTripper.
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
req = cloneRequest(req)
ua := req.Header.Get("User-Agent")
if ua == "" {
ua = userAgent
} else {
ua = fmt.Sprintf("%s %s", ua, userAgent)
}
req.Header.Set("User-Agent", ua)
return t.Base.RoundTrip(req)
}
// cloneRequest returns a clone of the provided *http.Request.
// The clone is a shallow copy of the struct and its Header map.
func cloneRequest(r *http.Request) *http.Request {
// shallow copy of the struct
r2 := new(http.Request)
*r2 = *r
// deep copy of the Header
r2.Header = make(http.Header)
for k, s := range r.Header {
r2.Header[k] = s
}
return r2
}
func ProjID(ctx context.Context) string {
return cc(ctx).ProjectID
}
func HTTPClient(ctx context.Context) *http.Client {
return cc(ctx).HTTPClient
}
// cc returns the internal *cloudContext (cc) state for a context.Context.
// It panics if the user did it wrong.
func cc(ctx context.Context) *cloudContext {
if c, ok := ctx.Value(contextKey{}).(*cloudContext); ok {
return c
}
panic("invalid context.Context type; it should be created with cloud.NewContext")
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment