| Index: impl/prod/context.go
|
| diff --git a/impl/prod/context.go b/impl/prod/context.go
|
| index 73fec355fd739518a432bc310b43ae6acb7344b6..bccbf7934cd648ad1cb748ec7fad3b0d3f46b38e 100644
|
| --- a/impl/prod/context.go
|
| +++ b/impl/prod/context.go
|
| @@ -5,9 +5,14 @@
|
| package prod
|
|
|
| import (
|
| + "fmt"
|
| "net/http"
|
| + "net/http/cookiejar"
|
| + "net/url"
|
| + "strings"
|
|
|
| "github.com/luci/gae/service/info"
|
| + "github.com/luci/gae/service/urlfetch"
|
| "golang.org/x/net/context"
|
| gOAuth "golang.org/x/oauth2/google"
|
| "google.golang.org/appengine"
|
| @@ -29,6 +34,9 @@ var (
|
| // anyway).
|
| func AEContext(c context.Context) context.Context {
|
| aeCtx, _ := c.Value(prodContextKey).(context.Context)
|
| + if aeCtx == nil {
|
| + return nil
|
| + }
|
| if deadline, ok := c.Deadline(); ok {
|
| aeCtx, _ = context.WithDeadline(aeCtx, deadline)
|
| }
|
| @@ -39,6 +47,9 @@ func AEContext(c context.Context) context.Context {
|
| // Context that's not part of a transaction.
|
| func AEContextNoTxn(c context.Context) context.Context {
|
| aeCtx, _ := c.Value(prodContextNoTxnKey).(context.Context)
|
| + if aeCtx == nil {
|
| + return nil
|
| + }
|
| aeCtx, err := appengine.Namespace(aeCtx, info.Get(c).GetNamespace())
|
| if err != nil {
|
| panic(err)
|
| @@ -81,27 +92,68 @@ func Use(c context.Context, r *http.Request) context.Context {
|
| //
|
| // docs: https://cloud.google.com/appengine/docs/go/tools/remoteapi
|
| //
|
| -// If client is nil, this will use a default Google OAuth2 client. Otherwise the
|
| -// client must be configured to have the following OAuth2 scopes:
|
| -// "https://www.googleapis.com/auth/appengine.apis"
|
| -// "https://www.googleapis.com/auth/userinfo.email"
|
| -// "https://www.googleapis.com/auth/cloud.platform"
|
| -func UseRemote(c context.Context, host string, client *http.Client) (context.Context, error) {
|
| - err := error(nil)
|
| +// inOutCtx will be replaced with the new, derived context, if err is nil,
|
| +// otherwise it's unchanged and continues to be safe-to-use.
|
| +//
|
| +// If client is nil, this will use create a new client, and will try to be
|
| +// clever about it:
|
| +// * If you're creating a remote context FROM AppEngine, this will use
|
| +// urlfetch.Transport. This can be used to allow app-to-app remote_api
|
| +// control.
|
| +//
|
| +// * If host starts with "localhost", this will create a regular http.Client
|
| +// with a cookiejar, and call the _ah/login API to log in as an admin with
|
| +// the user "admin@example.com".
|
| +//
|
| +// * Otherwise, it will create a Google OAuth2 client with the following scopes:
|
| +// - "https://www.googleapis.com/auth/appengine.apis"
|
| +// - "https://www.googleapis.com/auth/userinfo.email"
|
| +// - "https://www.googleapis.com/auth/cloud.platform"
|
| +func UseRemote(inOutCtx *context.Context, host string, client *http.Client) (err error) {
|
| if client == nil {
|
| - client, err = gOAuth.DefaultClient(context.Background(),
|
| - "https://www.googleapis.com/auth/appengine.apis",
|
| - "https://www.googleapis.com/auth/userinfo.email",
|
| - "https://www.googleapis.com/auth/cloud.platform",
|
| - )
|
| - if err != nil {
|
| - return nil, err
|
| + if strings.HasPrefix(host, "localhost") {
|
| + transp := http.DefaultTransport
|
| + if aeCtx := AEContextNoTxn(*inOutCtx); aeCtx != nil {
|
| + transp = urlfetch.Get(aeCtx)
|
| + }
|
| +
|
| + client = &http.Client{Transport: transp}
|
| + client.Jar, err = cookiejar.New(nil)
|
| + if err != nil {
|
| + return
|
| + }
|
| + u := fmt.Sprintf("http://%s/_ah/login?%s", host, url.Values{
|
| + "email": {"admin@example.com"},
|
| + "admin": {"True"},
|
| + "action": {"Login"},
|
| + }.Encode())
|
| +
|
| + var rsp *http.Response
|
| + rsp, err = client.Get(u)
|
| + if err != nil {
|
| + return
|
| + }
|
| + defer rsp.Body.Close()
|
| + } else {
|
| + aeCtx := AEContextNoTxn(*inOutCtx)
|
| + if aeCtx == nil {
|
| + aeCtx = context.Background()
|
| + }
|
| + client, err = gOAuth.DefaultClient(aeCtx,
|
| + "https://www.googleapis.com/auth/appengine.apis",
|
| + "https://www.googleapis.com/auth/userinfo.email",
|
| + "https://www.googleapis.com/auth/cloud.platform",
|
| + )
|
| + if err != nil {
|
| + return
|
| + }
|
| }
|
| }
|
|
|
| aeCtx, err := remote_api.NewRemoteContext(host, client)
|
| if err != nil {
|
| - return nil, err
|
| + return
|
| }
|
| - return setupAECtx(c, aeCtx), nil
|
| + *inOutCtx = setupAECtx(*inOutCtx, aeCtx)
|
| + return nil
|
| }
|
|
|