Update vendor directory

Re-added cobra patch 499475bb41
This commit is contained in:
Nick Craig-Wood 2017-02-17 16:49:51 +00:00
parent 3ef9f6f016
commit 8ec57d145e
267 changed files with 15430 additions and 10511 deletions

18
vendor/google.golang.org/appengine/.travis.yml generated vendored Normal file
View file

@ -0,0 +1,18 @@
language: go
go:
- 1.6.3
- 1.7.1
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 -q 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/...

90
vendor/google.golang.org/appengine/CONTRIBUTING.md generated vendored Normal file
View file

@ -0,0 +1,90 @@
# Contributing
1. Sign one of the contributor license agreements below.
1. Get the package:
`go get -d google.golang.org/appengine`
1. Change into the checked out source:
`cd $GOPATH/src/google.golang.org/appengine`
1. Fork the repo.
1. Set your fork as a remote:
`git remote add fork git@github.com:GITHUB_USERNAME/appengine.git`
1. Make changes, commit to your fork.
1. Send a pull request with your changes.
The first line of your commit message is conventionally a one-line summary of the change, prefixed by the primary affected package, and is used as the title of your pull request.
# Testing
## Running system tests
Download and install the [Go App Engine SDK](https://cloud.google.com/appengine/docs/go/download). Make sure the `go_appengine` dir is in your `PATH`.
Set the `APPENGINE_DEV_APPSERVER` environment variable to `/path/to/go_appengine/dev_appserver.py`.
Run tests with `goapp test`:
```
goapp test -v google.golang.org/appengine/...
```
## Contributor License Agreements
Before we can accept your pull requests you'll need to sign a Contributor
License Agreement (CLA):
- **If you are an individual writing original source code** and **you own the
intellectual property**, then you'll need to sign an [individual CLA][indvcla].
- **If you work for a company that wants to allow you to contribute your work**,
then you'll need to sign a [corporate CLA][corpcla].
You can sign these electronically (just scroll to the bottom). After that,
we'll be able to accept your pull requests.
## Contributor Code of Conduct
As contributors and maintainers of this project,
and in the interest of fostering an open and welcoming community,
we pledge to respect all people who contribute through reporting issues,
posting feature requests, updating documentation,
submitting pull requests or patches, and other activities.
We are committed to making participation in this project
a harassment-free experience for everyone,
regardless of level of experience, gender, gender identity and expression,
sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, religion, or nationality.
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery
* Personal attacks
* Trolling or insulting/derogatory comments
* Public or private harassment
* Publishing other's private information,
such as physical or electronic
addresses, without explicit permission
* Other unethical or unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions
that are not aligned to this Code of Conduct.
By adopting this Code of Conduct,
project maintainers commit themselves to fairly and consistently
applying these principles to every aspect of managing this project.
Project maintainers who do not follow or enforce the Code of Conduct
may be permanently removed from the project team.
This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior
may be reported by opening an issue
or contacting one or more of the project maintainers.
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0,
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/)
[indvcla]: https://developers.google.com/open-source/cla/individual
[corpcla]: https://developers.google.com/open-source/cla/corporate

View file

@ -1,16 +1,23 @@
# Go App Engine for Managed VMs
# Go App Engine packages
This repository supports the Go runtime for Managed VMs on App Engine.
[![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/managed-vms/
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 types (e.g. `appengine.Context`) that are used across APIs. Specific API
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,
@ -19,27 +26,24 @@ should not directly import any package under `internal`.
## Updating a Go App Engine app
This section describes how to update a traditional Go App Engine app to run on Managed VMs.
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
### 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
manual_scaling:
instances: 1
```
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 API packages need to be made relative to `google.golang.org/appengine`.
You can do that manually, or by running this command to recursively update all Go source files in the current directory:
(may require GNU sed)
```
sed -i '/"appengine/{s,"appengine,"google.golang.org/appengine,;s,appengine_,appengine/,}' \
$(find . -name '*.go')
```
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
@ -47,15 +51,23 @@ 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.Datacenter` now takes an `appengine.Context` argument.
* `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/aetest`, `appengine/blobstore`, `appengine/cloudsql`
and `appengine/runtime` have not been ported yet.
* `appengine.BackendHostname` and `appengine.BackendInstance` were for the deprecated backends feature.
Use `appengine.ModuleHostname`and `appengine.ModuleName` instead.
* `appengine.IsCapabilityDisabled` and `appengine/capability` are obsolete.
* Most of `appengine/file` is deprecated. Use [Google Cloud Storage](https://code.google.com/p/google-api-go-client/wiki/GettingStarted) instead.
* `appengine/socket` is deprecated. Use the standard `net` package instead.
* Most of `appengine/file` and parts of `appengine/blobstore` are deprecated.
Use [Google Cloud Storage](https://godoc.org/cloud.google.com/go/storage) if the
feature you require is not present in the new
[blobstore package](https://google.golang.org/appengine/blobstore).
* `appengine/socket` is not required on App Engine flexible environment / Managed VMs.
Use the standard `net` package instead.

View file

@ -12,53 +12,68 @@ 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.
//
// On App Engine Standard it ensures the server has started and is prepared to
// receive requests.
//
// 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 {
// TODO(dsymonds): Detect this.
return false
}
// Context represents the context of an in-flight HTTP request.
type Context interface {
// Debugf formats its arguments according to the format, analogous to fmt.Printf,
// and records the text as a log message at Debug level.
Debugf(format string, args ...interface{})
// Infof is like Debugf, but at Info level.
Infof(format string, args ...interface{})
// Warningf is like Debugf, but at Warning level.
Warningf(format string, args ...interface{})
// Errorf is like Debugf, but at Error level.
Errorf(format string, args ...interface{})
// Criticalf is like Debugf, but at Critical level.
Criticalf(format string, args ...interface{})
// The remaining methods are for internal use only.
// Developer-facing APIs wrap these methods to provide a more friendly API.
// Internal use only.
Call(service, method string, in, out proto.Message, opts *internal.CallOptions) error
// Internal use only. Use AppID instead.
FullyQualifiedAppID() string
// Internal use only.
Request() interface{}
return internal.IsDevAppServer()
}
// NewContext returns a context for an in-flight HTTP request.
// Repeated calls will return the same value.
func NewContext(req *http.Request) Context {
return internal.NewContext(req)
// This function is cheap.
func NewContext(req *http.Request) context.Context {
return WithContext(context.Background(), req)
}
// TODO(dsymonds): Add BackgroundContext function?
// 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.
//
@ -76,3 +91,23 @@ type GeoPoint struct {
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)
}

20
vendor/google.golang.org/appengine/appengine_vm.go generated vendored Normal file
View file

@ -0,0 +1,20 @@
// 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()
}

View file

@ -7,6 +7,8 @@ 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"
@ -15,18 +17,18 @@ import (
// 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) string { return internal.AppID(c.FullyQualifiedAppID()) }
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) string {
return internal.DefaultVersionHostname(c.Request())
func DefaultVersionHostname(c context.Context) string {
return internal.DefaultVersionHostname(c)
}
// ModuleName returns the module name of the current instance.
func ModuleName(c Context) string {
return internal.ModuleName()
func ModuleName(c context.Context) string {
return internal.ModuleName(c)
}
// ModuleHostname returns a hostname of a module instance.
@ -34,7 +36,7 @@ func ModuleName(c Context) string {
// 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, module, version, instance string) (string, error) {
func ModuleHostname(c context.Context, module, version, instance string) (string, error) {
req := &modpb.GetHostnameRequest{}
if module != "" {
req.Module = &module
@ -46,7 +48,7 @@ func ModuleHostname(c Context, module, version, instance string) (string, error)
req.Instance = &instance
}
res := &modpb.GetHostnameResponse{}
if err := c.Call("modules", "GetHostname", req, res, nil); err != nil {
if err := internal.Call(c, "modules", "GetHostname", req, res); err != nil {
return "", err
}
return *res.Hostname, nil
@ -56,13 +58,13 @@ func ModuleHostname(c Context, module, version, instance string) (string, error)
// 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) string { return internal.VersionID() }
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) string { return internal.Datacenter(c.Request()) }
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".
@ -70,16 +72,16 @@ func Datacenter(c Context) string { return internal.Datacenter(c.Request()) }
func ServerSoftware() string { return internal.ServerSoftware() }
// RequestID returns a string that uniquely identifies the request.
func RequestID(c Context) string { return internal.RequestID(c.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, scopes ...string) (token string, expiry time.Time, err error) {
func AccessToken(c context.Context, scopes ...string) (token string, expiry time.Time, err error) {
req := &pb.GetAccessTokenRequest{Scope: scopes}
res := &pb.GetAccessTokenResponse{}
err = c.Call("app_identity_service", "GetAccessToken", req, res, nil)
err = internal.Call(c, "app_identity_service", "GetAccessToken", req, res)
if err != nil {
return "", time.Time{}, err
}
@ -94,10 +96,10 @@ type Certificate struct {
// PublicCertificates retrieves the public certificates for the app.
// They can be used to verify a signature returned by SignBytes.
func PublicCertificates(c Context) ([]Certificate, error) {
func PublicCertificates(c context.Context) ([]Certificate, error) {
req := &pb.GetPublicCertificateForAppRequest{}
res := &pb.GetPublicCertificateForAppResponse{}
if err := c.Call("app_identity_service", "GetPublicCertificatesForApp", req, res, nil); err != nil {
if err := internal.Call(c, "app_identity_service", "GetPublicCertificatesForApp", req, res); err != nil {
return nil, err
}
var cs []Certificate
@ -112,11 +114,11 @@ func PublicCertificates(c Context) ([]Certificate, error) {
// 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) (string, error) {
func ServiceAccount(c context.Context) (string, error) {
req := &pb.GetServiceAccountNameRequest{}
res := &pb.GetServiceAccountNameResponse{}
err := c.Call("app_identity_service", "GetServiceAccountName", req, res, nil)
err := internal.Call(c, "app_identity_service", "GetServiceAccountName", req, res)
if err != nil {
return "", err
}
@ -124,15 +126,14 @@ func ServiceAccount(c Context) (string, error) {
}
// SignBytes signs bytes using a private key unique to your application.
func SignBytes(c Context, bytes []byte) (string, []byte, error) {
func SignBytes(c context.Context, bytes []byte) (keyName string, signature []byte, err error) {
req := &pb.SignForAppRequest{BytesToSign: bytes}
res := &pb.SignForAppResponse{}
err := c.Call("app_identity_service", "SignForApp", req, res, nil)
if err != nil {
if err := internal.Call(c, "app_identity_service", "SignForApp", req, res); err != nil {
return "", nil, err
}
return res.GetKeyName(), res.GetSignatureBytes(), err
return res.GetKeyName(), res.GetSignatureBytes(), nil
}
func init() {

View file

@ -2,10 +2,13 @@
// 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 (
"bytes"
"errors"
"fmt"
"io/ioutil"
"log"
@ -21,6 +24,7 @@ import (
"time"
"github.com/golang/protobuf/proto"
netcontext "golang.org/x/net/context"
basepb "google.golang.org/appengine/internal/base"
logpb "google.golang.org/appengine/internal/log"
@ -28,14 +32,15 @@ import (
)
const (
apiPath = "/rpc_http"
apiPath = "/rpc_http"
defaultTicketSuffix = "/default.20150612t184001.0"
)
var (
// Incoming headers.
ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket")
dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo")
defNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Default-Namespace")
traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context")
curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace")
userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP")
remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr")
@ -56,23 +61,31 @@ var (
Dial: limitDial,
},
}
defaultTicketOnce sync.Once
defaultTicket string
)
func apiHost() string {
host, port := "appengine.googleapis.com", "10001"
func apiURL() *url.URL {
host, port := "appengine.googleapis.internal", "10001"
if h := os.Getenv("API_HOST"); h != "" {
host = h
}
if p := os.Getenv("API_PORT"); p != "" {
port = p
}
return host + ":" + port
return &url.URL{
Scheme: "http",
Host: host + ":" + port,
Path: apiPath,
}
}
func handleHTTP(w http.ResponseWriter, r *http.Request) {
c := &context{
req: r,
outHeader: w.Header(),
apiURL: apiURL(),
}
stopFlushing := make(chan int)
@ -135,7 +148,8 @@ func handleHTTP(w http.ResponseWriter, r *http.Request) {
func executeRequestSafely(c *context, r *http.Request) {
defer func() {
if x := recover(); x != nil {
c.logf(4, "%s", renderPanic(x)) // 4 == critical
logf(c, 4, "%s", renderPanic(x)) // 4 == critical
c.outCode = 500
}
}()
@ -185,6 +199,10 @@ var ctxs = struct {
sync.Mutex
m map[*http.Request]*context
bg *context // background context, lazily initialized
// dec is used by tests to decorate the netcontext.Context returned
// for a given request. This allows tests to add overrides (such as
// WithAppIDOverride) to the context. The map is nil outside tests.
dec map[*http.Request]func(netcontext.Context) netcontext.Context
}{
m: make(map[*http.Request]*context),
}
@ -203,38 +221,83 @@ type context struct {
lines []*logpb.UserAppLogLine
flushes int
}
apiURL *url.URL
}
func NewContext(req *http.Request) *context {
var contextKey = "holds a *context"
func fromContext(ctx netcontext.Context) *context {
c, _ := ctx.Value(&contextKey).(*context)
return c
}
func withContext(parent netcontext.Context, c *context) netcontext.Context {
ctx := netcontext.WithValue(parent, &contextKey, c)
if ns := c.req.Header.Get(curNamespaceHeader); ns != "" {
ctx = withNamespace(ctx, ns)
}
return ctx
}
func toContext(c *context) netcontext.Context {
return withContext(netcontext.Background(), c)
}
func IncomingHeaders(ctx netcontext.Context) http.Header {
if c := fromContext(ctx); c != nil {
return c.req.Header
}
return nil
}
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
ctxs.Lock()
c := ctxs.m[req]
d := ctxs.dec[req]
ctxs.Unlock()
if d != nil {
parent = d(parent)
}
if c == nil {
// Someone passed in an http.Request that is not in-flight.
// We panic here rather than panicking at a later point
// so that stack traces will be more sensible.
log.Panic("appengine: NewContext passed an unknown http.Request")
}
return c
return withContext(parent, c)
}
func BackgroundContext() *context {
// DefaultTicket returns a ticket used for background context or dev_appserver.
func DefaultTicket() string {
defaultTicketOnce.Do(func() {
if IsDevAppServer() {
defaultTicket = "testapp" + defaultTicketSuffix
return
}
appID := partitionlessAppID()
escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
majVersion := VersionID(nil)
if i := strings.Index(majVersion, "."); i > 0 {
majVersion = majVersion[:i]
}
defaultTicket = fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID())
})
return defaultTicket
}
func BackgroundContext() netcontext.Context {
ctxs.Lock()
defer ctxs.Unlock()
if ctxs.bg != nil {
return ctxs.bg
return toContext(ctxs.bg)
}
// Compute background security ticket.
appID := partitionlessAppID()
escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
majVersion := VersionID()
if i := strings.Index(majVersion, "_"); i >= 0 {
majVersion = majVersion[:i]
}
ticket := fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(), majVersion, InstanceID())
ticket := DefaultTicket()
ctxs.bg = &context{
req: &http.Request{
@ -242,12 +305,44 @@ func BackgroundContext() *context {
ticketHeader: []string{ticket},
},
},
apiURL: apiURL(),
}
// TODO(dsymonds): Wire up the shutdown handler to do a final flush.
go ctxs.bg.logFlusher(make(chan int))
return ctxs.bg
return toContext(ctxs.bg)
}
// RegisterTestRequest registers the HTTP request req for testing, such that
// any API calls are sent to the provided URL. It returns a closure to delete
// the registration.
// It should only be used by aetest package.
func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) func() {
c := &context{
req: req,
apiURL: apiURL,
}
ctxs.Lock()
defer ctxs.Unlock()
if _, ok := ctxs.m[req]; ok {
log.Panic("req already associated with context")
}
if _, ok := ctxs.dec[req]; ok {
log.Panic("req already associated with context")
}
if ctxs.dec == nil {
ctxs.dec = make(map[*http.Request]func(netcontext.Context) netcontext.Context)
}
ctxs.m[req] = c
ctxs.dec[req] = decorate
return func() {
ctxs.Lock()
delete(ctxs.m, req)
delete(ctxs.dec, req)
ctxs.Unlock()
}
}
var errTimeout = &CallError{
@ -286,21 +381,16 @@ func (c *context) Write(b []byte) (int, error) {
func (c *context) WriteHeader(code int) {
if c.outCode != 0 {
c.Errorf("WriteHeader called multiple times on request.")
logf(c, 3, "WriteHeader called multiple times on request.") // error level
return
}
c.outCode = code
}
func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) {
dst := apiHost()
hreq := &http.Request{
Method: "POST",
URL: &url.URL{
Scheme: "http",
Host: dst,
Path: apiPath,
},
URL: c.apiURL,
Header: http.Header{
apiEndpointHeader: apiEndpointHeaderValue,
apiMethodHeader: apiMethodHeaderValue,
@ -309,11 +399,14 @@ func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error)
},
Body: ioutil.NopCloser(bytes.NewReader(body)),
ContentLength: int64(len(body)),
Host: dst,
Host: c.apiURL.Host,
}
if info := c.req.Header.Get(dapperHeader); info != "" {
hreq.Header.Set(dapperHeader, info)
}
if info := c.req.Header.Get(traceHeader); info != "" {
hreq.Header.Set(traceHeader, info)
}
tr := apiHTTPClient.Transport.(*http.Transport)
@ -354,30 +447,42 @@ func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error)
return hrespBody, nil
}
var virtualMethodHeaders = map[string]string{
"GetNamespace": curNamespaceHeader,
"GetDefaultNamespace": defNamespaceHeader,
"user:Email": http.CanonicalHeaderKey("X-AppEngine-User-Email"),
"user:AuthDomain": http.CanonicalHeaderKey("X-AppEngine-Auth-Domain"),
"user:ID": http.CanonicalHeaderKey("X-AppEngine-User-Id"),
"user:IsAdmin": http.CanonicalHeaderKey("X-AppEngine-User-Is-Admin"),
"user:FederatedIdentity": http.CanonicalHeaderKey("X-AppEngine-Federated-Identity"),
"user:FederatedProvider": http.CanonicalHeaderKey("X-AppEngine-Federated-Provider"),
}
func (c *context) Call(service, method string, in, out proto.Message, opts *CallOptions) error {
if service == "__go__" {
if hdr, ok := virtualMethodHeaders[method]; ok {
out.(*basepb.StringProto).Value = proto.String(c.req.Header.Get(hdr))
return nil
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)
}
}
// Default RPC timeout is 5s.
timeout := 5 * time.Second
if opts != nil && opts.Timeout > 0 {
timeout = opts.Timeout
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)
}
// Default RPC timeout is 60s.
timeout := 60 * time.Second
if deadline, ok := ctx.Deadline(); ok {
timeout = deadline.Sub(time.Now())
}
data, err := proto.Marshal(in)
@ -386,6 +491,16 @@ func (c *context) Call(service, method string, in, out proto.Message, opts *Call
}
ticket := c.req.Header.Get(ticketHeader)
// Use a test ticket under test environment.
if ticket == "" {
if appid := ctx.Value(&appIDOverrideKey); appid != nil {
ticket = appid.(string) + defaultTicketSuffix
}
}
// Fall back to use background ticket when the request ticket is not available in Flex or dev_appserver.
if ticket == "" {
ticket = DefaultTicket()
}
req := &remotepb.Request{
ServiceName: &service,
Method: &method,
@ -434,7 +549,7 @@ func (c *context) Call(service, method string, in, out proto.Message, opts *Call
return proto.Unmarshal(res.Response, out)
}
func (c *context) Request() interface{} {
func (c *context) Request() *http.Request {
return c.req
}
@ -460,7 +575,10 @@ var logLevelName = map[int64]string{
4: "CRITICAL",
}
func (c *context) logf(level int64, format string, args ...interface{}) {
func logf(c *context, level int64, format string, args ...interface{}) {
if c == nil {
panic("not an App Engine context")
}
s := fmt.Sprintf(format, args...)
s = strings.TrimRight(s, "\n") // Remove any trailing newline characters.
c.addLogLine(&logpb.UserAppLogLine{
@ -471,17 +589,6 @@ func (c *context) logf(level int64, format string, args ...interface{}) {
log.Print(logLevelName[level] + ": " + s)
}
func (c *context) Debugf(format string, args ...interface{}) { c.logf(0, format, args...) }
func (c *context) Infof(format string, args ...interface{}) { c.logf(1, format, args...) }
func (c *context) Warningf(format string, args ...interface{}) { c.logf(2, format, args...) }
func (c *context) Errorf(format string, args ...interface{}) { c.logf(3, format, args...) }
func (c *context) Criticalf(format string, args ...interface{}) { c.logf(4, format, args...) }
// 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 (c *context) FullyQualifiedAppID() string { return fullyQualifiedAppID() }
// flushLog attempts to flush any pending logs to the appserver.
// It should not be called concurrently.
func (c *context) flushLog(force bool) (flushed bool) {
@ -531,7 +638,7 @@ func (c *context) flushLog(force bool) (flushed bool) {
c.pendingLogs.Lock()
c.pendingLogs.flushes++
c.pendingLogs.Unlock()
if err := c.Call("logservice", "Flush", req, res, nil); err != nil {
if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil {
log.Printf("internal.flushLog: Flush RPC: %v", err)
rescueLogs = true
return false
@ -563,27 +670,6 @@ func (c *context) logFlusher(stop <-chan int) {
}
}
func ContextForTesting(req *http.Request) *context {
return &context{req: req}
}
// caller is a subset of appengine.Context.
type caller interface {
Call(service, method string, in, out proto.Message, opts *CallOptions) error
}
var virtualOpts = &CallOptions{
// Virtual API calls should happen nearly instantaneously.
Timeout: 1 * time.Millisecond,
}
// VirtAPI invokes a virtual API call for the __go__ service.
// It is for methods that accept a VoidProto and return a StringProto.
// It returns an empty string if the call fails.
func VirtAPI(c caller, method string) string {
s := &basepb.StringProto{}
if err := c.Call("__go__", method, &basepb.VoidProto{}, s, virtualOpts); err != nil {
log.Printf("/__go__.%s failed: %v", method, err)
}
return s.GetValue()
func ContextForTesting(req *http.Request) netcontext.Context {
return toContext(&context{req: req})
}

View file

@ -0,0 +1,159 @@
// 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...)
}

View file

@ -0,0 +1,116 @@
// 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 (
"os"
"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)
}
// SetTestEnv sets the env variables for testing background ticket in Flex.
func SetTestEnv() func() {
var environ = []struct {
key, value string
}{
{"GAE_LONG_APP_ID", "my-app-id"},
{"GAE_MINOR_VERSION", "067924799508853122"},
{"GAE_MODULE_INSTANCE", "0"},
{"GAE_MODULE_NAME", "default"},
{"GAE_MODULE_VERSION", "20150612t184001"},
}
for _, v := range environ {
old := os.Getenv(v.key)
os.Setenv(v.key, v.value)
v.value = old
}
return func() { // Restore old environment after the test completes.
for _, v := range environ {
if v.value == "" {
os.Unsetenv(v.key)
continue
}
os.Setenv(v.key, v.value)
}
}
}

View file

@ -25,10 +25,12 @@ It has these top-level messages:
package app_identity
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 AppIdentityServiceError_ErrorCode int32
@ -291,5 +293,4 @@ func (m *GetDefaultGcsBucketNameResponse) GetDefaultGcsBucketName() string {
}
func init() {
proto.RegisterEnum("appengine.AppIdentityServiceError_ErrorCode", AppIdentityServiceError_ErrorCode_name, AppIdentityServiceError_ErrorCode_value)
}

View file

@ -20,10 +20,12 @@ It has these top-level messages:
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 {
@ -129,6 +131,3 @@ type VoidProto struct {
func (m *VoidProto) Reset() { *m = VoidProto{} }
func (m *VoidProto) String() string { return proto.CompactTextString(m) }
func (*VoidProto) ProtoMessage() {}
func init() {
}

View file

@ -51,10 +51,12 @@ It has these top-level messages:
package datastore
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 Property_Meaning int32
@ -815,7 +817,7 @@ func (m *Property) GetLocale() string {
}
type Path struct {
Element []*Path_Element `protobuf:"group,1,rep" json:"element,omitempty"`
Element []*Path_Element `protobuf:"group,1,rep,name=Element" json:"element,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -1041,7 +1043,7 @@ func (m *CompositeProperty) GetValue() []string {
type Index struct {
EntityType *string `protobuf:"bytes,1,req,name=entity_type" json:"entity_type,omitempty"`
Ancestor *bool `protobuf:"varint,5,req,name=ancestor" json:"ancestor,omitempty"`
Property []*Index_Property `protobuf:"group,2,rep" json:"property,omitempty"`
Property []*Index_Property `protobuf:"group,2,rep,name=Property" json:"property,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -1310,9 +1312,9 @@ type Query struct {
NameSpace *string `protobuf:"bytes,29,opt,name=name_space" json:"name_space,omitempty"`
Kind *string `protobuf:"bytes,3,opt,name=kind" json:"kind,omitempty"`
Ancestor *Reference `protobuf:"bytes,17,opt,name=ancestor" json:"ancestor,omitempty"`
Filter []*Query_Filter `protobuf:"group,4,rep" json:"filter,omitempty"`
Filter []*Query_Filter `protobuf:"group,4,rep,name=Filter" json:"filter,omitempty"`
SearchQuery *string `protobuf:"bytes,8,opt,name=search_query" json:"search_query,omitempty"`
Order []*Query_Order `protobuf:"group,9,rep" json:"order,omitempty"`
Order []*Query_Order `protobuf:"group,9,rep,name=Order" json:"order,omitempty"`
Hint *Query_Hint `protobuf:"varint,18,opt,name=hint,enum=appengine.Query_Hint" json:"hint,omitempty"`
Count *int32 `protobuf:"varint,23,opt,name=count" json:"count,omitempty"`
Offset *int32 `protobuf:"varint,12,opt,name=offset,def=0" json:"offset,omitempty"`
@ -1807,7 +1809,7 @@ func (m *CompiledQuery_EntityFilter) GetAncestor() *Reference {
}
type CompiledCursor struct {
Position *CompiledCursor_Position `protobuf:"group,2,opt" json:"position,omitempty"`
Position *CompiledCursor_Position `protobuf:"group,2,opt,name=Position" json:"position,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -2067,7 +2069,7 @@ func (m *GetRequest) GetAllowDeferred() bool {
}
type GetResponse struct {
Entity []*GetResponse_Entity `protobuf:"group,1,rep" json:"entity,omitempty"`
Entity []*GetResponse_Entity `protobuf:"group,1,rep,name=Entity" json:"entity,omitempty"`
Deferred []*Reference `protobuf:"bytes,5,rep,name=deferred" json:"deferred,omitempty"`
InOrder *bool `protobuf:"varint,6,opt,name=in_order,def=1" json:"in_order,omitempty"`
XXX_unrecognized []byte `json:"-"`
@ -2726,7 +2728,7 @@ func (m *BeginTransactionRequest) GetAllowMultipleEg() bool {
type CommitResponse struct {
Cost *Cost `protobuf:"bytes,1,opt,name=cost" json:"cost,omitempty"`
Version []*CommitResponse_Version `protobuf:"group,3,rep" json:"version,omitempty"`
Version []*CommitResponse_Version `protobuf:"group,3,rep,name=Version" json:"version,omitempty"`
XXX_unrecognized []byte `json:"-"`
}
@ -2773,15 +2775,4 @@ func (m *CommitResponse_Version) GetVersion() int64 {
}
func init() {
proto.RegisterEnum("appengine.Property_Meaning", Property_Meaning_name, Property_Meaning_value)
proto.RegisterEnum("appengine.Property_FtsTokenizationOption", Property_FtsTokenizationOption_name, Property_FtsTokenizationOption_value)
proto.RegisterEnum("appengine.EntityProto_Kind", EntityProto_Kind_name, EntityProto_Kind_value)
proto.RegisterEnum("appengine.Index_Property_Direction", Index_Property_Direction_name, Index_Property_Direction_value)
proto.RegisterEnum("appengine.CompositeIndex_State", CompositeIndex_State_name, CompositeIndex_State_value)
proto.RegisterEnum("appengine.Snapshot_Status", Snapshot_Status_name, Snapshot_Status_value)
proto.RegisterEnum("appengine.Query_Hint", Query_Hint_name, Query_Hint_value)
proto.RegisterEnum("appengine.Query_Filter_Operator", Query_Filter_Operator_name, Query_Filter_Operator_value)
proto.RegisterEnum("appengine.Query_Order_Direction", Query_Order_Direction_name, Query_Order_Direction_value)
proto.RegisterEnum("appengine.Error_ErrorCode", Error_ErrorCode_name, Error_ErrorCode_value)
proto.RegisterEnum("appengine.PutRequest_AutoIdPolicy", PutRequest_AutoIdPolicy_name, PutRequest_AutoIdPolicy_value)
}

View file

@ -4,9 +4,11 @@
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(fqai string) string {
return appID(fqai)
func AppID(c netcontext.Context) string {
return appID(FullyQualifiedAppID(c))
}

View file

@ -0,0 +1,27 @@
// 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() }

View file

@ -2,11 +2,15 @@
// 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
@ -18,16 +22,20 @@ const (
hDatacenter = "X-AppEngine-Datacenter"
)
func DefaultVersionHostname(req interface{}) string {
return req.(*http.Request).Header.Get(hDefaultVersionHostname)
func ctxHeaders(ctx netcontext.Context) http.Header {
return fromContext(ctx).Request().Header
}
func RequestID(req interface{}) string {
return req.(*http.Request).Header.Get(hRequestLogId)
func DefaultVersionHostname(ctx netcontext.Context) string {
return ctxHeaders(ctx).Get(hDefaultVersionHostname)
}
func Datacenter(req interface{}) string {
return req.(*http.Request).Header.Get(hDatacenter)
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 {
@ -40,18 +48,18 @@ func ServerSoftware() string {
// TODO(dsymonds): Remove the metadata fetches.
func ModuleName() string {
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() string {
if s := os.Getenv("GAE_MODULE_VERSION"); s != "" {
return s
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"))
return string(mustGetMetadata("instance/attributes/gae_backend_version")) + "." + string(mustGetMetadata("instance/attributes/gae_backend_minor_version"))
}
func InstanceID() string {
@ -70,7 +78,7 @@ func partitionlessAppID() string {
return appID
}
func fullyQualifiedAppID() string {
func fullyQualifiedAppID(_ netcontext.Context) string {
appID := partitionlessAppID()
part := os.Getenv("GAE_PARTITION")
@ -83,3 +91,7 @@ func fullyQualifiedAppID() string {
}
return appID
}
func IsDevAppServer() bool {
return os.Getenv("RUN_WITH_DEVAPPSERVER") != ""
}

View file

@ -10,21 +10,12 @@ package internal
import (
"fmt"
"io"
"log"
"net/http"
"net/url"
"time"
"github.com/golang/protobuf/proto"
remotepb "google.golang.org/appengine/internal/remote_api"
)
type CallOptions struct {
Timeout time.Duration // if non-zero, overrides RPC default
}
// errorCodeMaps is a map of service name to the error code map for the service.
var errorCodeMaps = make(map[string]map[int32]string)
@ -113,52 +104,6 @@ func (e *CallError) IsTimeout() bool {
return e.Timeout
}
// The comment below must not be changed.
// It is used by go-app-builder to recognise that this package has
// the internal.Main function to use in the synthetic main.
// The gophers party all night; the rabbits provide the beats.
// Main is designed so that the complete generated main package is:
//
// package main
//
// import (
// "google.golang.org/appengine/internal"
//
// _ "myapp/package0"
// _ "myapp/package1"
// )
//
// func main() {
// internal.Main()
// }
//
// The "myapp/packageX" packages are expected to register HTTP handlers
// in their init functions.
func Main() {
installHealthChecker(http.DefaultServeMux)
if err := http.ListenAndServe(":8080", 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")
})
}
}
// 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.

View file

@ -27,10 +27,12 @@ It has these top-level messages:
package log
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 LogServiceError_ErrorCode int32
@ -894,5 +896,4 @@ func (m *LogUsageResponse) GetSummary() *LogUsageRecord {
}
func init() {
proto.RegisterEnum("appengine.LogServiceError_ErrorCode", LogServiceError_ErrorCode_name, LogServiceError_ErrorCode_value)
}

15
vendor/google.golang.org/appengine/internal/main.go generated vendored Normal file
View file

@ -0,0 +1,15 @@
// 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()
}

48
vendor/google.golang.org/appengine/internal/main_vm.go generated vendored Normal file
View file

@ -0,0 +1,48 @@
// 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
}
host := ""
if IsDevAppServer() {
host = "127.0.0.1"
}
if err := http.ListenAndServe(host+":"+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")
})
}
}

View file

@ -24,7 +24,7 @@ const (
var (
metadataRequestHeaders = http.Header{
"X-Google-Metadata-Request": []string{"True"},
"Metadata-Flavor": []string{"Google"},
}
)

View file

@ -30,10 +30,12 @@ It has these top-level messages:
package modules
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 ModulesServiceError_ErrorCode int32
@ -370,5 +372,4 @@ func (m *GetHostnameResponse) GetHostname() string {
}
func init() {
proto.RegisterEnum("appengine.ModulesServiceError_ErrorCode", ModulesServiceError_ErrorCode_name, ModulesServiceError_ErrorCode_value)
}

View file

@ -43,21 +43,14 @@ func limitDial(network, addr string) (net.Conn, error) {
}
type limitConn struct {
mu sync.Mutex // only for closing the net.Conn
close sync.Once
net.Conn
}
func (lc *limitConn) Close() error {
lc.mu.Lock()
defer lc.mu.Unlock()
if lc.Conn == nil {
// Silently ignore double close.
return nil
}
limitRelease()
err := lc.Conn.Close()
lc.Conn = nil
runtime.SetFinalizer(lc, nil)
return err
defer lc.close.Do(func() {
limitRelease()
runtime.SetFinalizer(lc, nil)
})
return lc.Conn.Close()
}

View file

@ -23,14 +23,18 @@ echo 1>&2 $pkgdir
base=$(echo $pkgdir | sed "s,/$PKG\$,,")
echo 1>&2 "base: $base"
cd $base
for f in $(find $PKG/internal -name '*.proto'); do
echo 1>&2 "* $f"
protoc --go_out=. $f
# 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
# Fix up import lines.
# This should be fixed upstream.
# https://code.google.com/p/goprotobuf/issues/detail?id=32
for f in $(find $PKG/internal -name '*.pb.go'); do
sed -i '/^import.*\.pb"$/s,/[^/]*\.pb"$,",' $f
# 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

View file

@ -17,10 +17,12 @@ It has these top-level messages:
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
@ -226,5 +228,4 @@ func (m *Response) GetRpcError() *RpcError {
}
func init() {
proto.RegisterEnum("remote_api.RpcError_ErrorCode", RpcError_ErrorCode_name, RpcError_ErrorCode_value)
}

View file

@ -1,12 +1,19 @@
// 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"
)
@ -20,11 +27,81 @@ func RegisterTransactionSetter(f interface{}) {
transactionSetters[v.Type().In(0)] = v
}
// ApplyTransaction applies the transaction t to message pb
// applyTransaction applies the transaction t to message pb
// by using the relevant setter passed to RegisterTransactionSetter.
func ApplyTransaction(pb proto.Message, t *pb.Transaction) {
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
}

View file

@ -8,41 +8,18 @@ import (
"fmt"
"regexp"
"github.com/golang/protobuf/proto"
"golang.org/x/net/context"
"google.golang.org/appengine/internal"
basepb "google.golang.org/appengine/internal/base"
)
// Namespace returns a replacement context that operates within the given namespace.
func Namespace(c Context, namespace string) (Context, error) {
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 &namespacedContext{
Context: c,
namespace: namespace,
}, nil
return internal.NamespacedContext(c, namespace), nil
}
// validNamespace matches valid namespace names.
var validNamespace = regexp.MustCompile(`^[0-9A-Za-z._-]{0,100}$`)
// namespacedContext wraps a Context to support namespaces.
type namespacedContext struct {
Context
namespace string
}
func (n *namespacedContext) Call(service, method string, in, out proto.Message, opts *internal.CallOptions) error {
// Apply any namespace mods.
if mod, ok := internal.NamespaceMods[service]; ok {
mod(in, n.namespace)
}
if service == "__go__" && method == "GetNamespace" {
out.(*basepb.StringProto).Value = proto.String(n.namespace)
return nil
}
return n.Context.Call(service, method, in, out, opts)
}

View file

@ -4,16 +4,13 @@
package appengine
import (
"time"
"github.com/golang/protobuf/proto"
"google.golang.org/appengine/internal"
)
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 {
@ -21,29 +18,3 @@ func IsTimeoutError(err error) bool {
}
return false
}
// Timeout returns a replacement context that uses d as the default API RPC timeout.
func Timeout(c Context, d time.Duration) Context {
return &timeoutContext{
Context: c,
d: d,
}
}
type timeoutContext struct {
Context
d time.Duration
}
func (t *timeoutContext) Call(service, method string, in, out proto.Message, opts *internal.CallOptions) error {
// Only affect calls that don't have a timeout.
if opts == nil || opts.Timeout == 0 {
newOpts := new(internal.CallOptions)
if opts != nil {
*newOpts = *opts
}
newOpts.Timeout = t.d
opts = newOpts
}
return t.Context.Call(service, method, in, out, opts)
}