func (c *context) Call(service, method string, in, out ProtoMessage, opts *CallOptions) error { if service == "__go__" { if method == "GetNamespace" { out.(*basepb.StringProto).Value = proto.String(c.req.Header.Get("X-AppEngine-Current-Namespace")) return nil } if method == "GetDefaultNamespace" { out.(*basepb.StringProto).Value = proto.String(c.req.Header.Get("X-AppEngine-Default-Namespace")) return nil } } if f, ok := apiOverrides[struct{ service, method string }{service, method}]; ok { return f(in, out, opts) } data, err := proto.Marshal(in) if err != nil { return err } requestID := c.req.Header.Get("X-Appengine-Internal-Request-Id") res, err := call(service, method, data, requestID) if err != nil { return err } return proto.Unmarshal(res, out) }
// Encode returns an opaque representation of the key // suitable for use in HTML and URLs. // This is compatible with the Python and Java runtimes. func (k *Key) Encode() string { ref := keyToProto("", k) b, err := proto.Marshal(ref) if err != nil { panic(err) } // Trailing padding is stripped. return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") }
// Call is an implementation of appengine.Context's Call that delegates // to a child api_server.py instance. func (c *context) Call(service, method string, in, out appengine_internal.ProtoMessage, opts *appengine_internal.CallOptions) error { if service == "__go__" && (method == "GetNamespace" || method == "GetDefaultNamespace") { out.(*basepb.StringProto).Value = proto.String("") return nil } data, err := proto.Marshal(in) if err != nil { return err } req, err := proto.Marshal(&remoteapipb.Request{ ServiceName: proto.String(service), Method: proto.String(method), Request: data, RequestId: proto.String(c.session), }) if err != nil { return err } res, err := http.Post(c.apiURL, "application/octet-stream", bytes.NewReader(req)) if err != nil { return err } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if res.StatusCode != 200 { return fmt.Errorf("got status %d; body: %q", res.StatusCode, body) } if err != nil { return err } resp := &remoteapipb.Response{} err = proto.Unmarshal(body, resp) if err != nil { return err } if e := resp.GetApplicationError(); e != nil { return fmt.Errorf("remote_api error (%v): %v", *e.Code, *e.Detail) } return proto.Unmarshal(resp.Response, out) }
// String returns a base-64 string representation of a cursor. func (c Cursor) String() string { if c.cc == nil { return "" } b, err := proto.Marshal(c.cc) if err != nil { // The only way to construct a Cursor with a non-nil cc field is to // unmarshal from the byte representation. We panic if the unmarshal // succeeds but the marshaling of the unchanged protobuf value fails. panic(fmt.Sprintf("datastore: internal error: malformed cursor: %v", err)) } return strings.TrimRight(base64.URLEncoding.EncodeToString(b), "=") }
func call(service, method string, data []byte, requestID string) ([]byte, error) { req := &remote_api.Request{ ServiceName: &service, Method: &method, Request: data, RequestId: &requestID, } buf, err := proto.Marshal(req) if err != nil { return nil, err } resp, err := apiHTTPClient.Post(apiAddress, "application/octet-stream", bytes.NewReader(buf)) if err != nil { return nil, err } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return nil, err } res := &remote_api.Response{} err = proto.Unmarshal(body, res) if err != nil { return nil, err } if ae := res.ApplicationError; ae != nil { // All Remote API application errors are API-level failures. return nil, &APIError{Service: service, Detail: *ae.Detail, Code: *ae.Code} } return res.Response, nil }
// protoToRecord converts a RequestLog, the internal Protocol Buffer // representation of a single request-level log, to a Record, its // corresponding external representation. func protoToRecord(rl *pb.RequestLog) *Record { offset, err := proto.Marshal(rl.Offset) if err != nil { offset = nil } return &Record{ AppID: *rl.AppId, VersionID: *rl.VersionId, RequestID: rl.RequestId, Offset: offset, IP: *rl.Ip, Nickname: rl.GetNickname(), AppEngineRelease: string(rl.GetAppEngineRelease()), StartTime: time.Unix(0, *rl.StartTime*1e3), EndTime: time.Unix(0, *rl.EndTime*1e3), Latency: time.Duration(*rl.Latency) * time.Microsecond, MCycles: *rl.Mcycles, Method: *rl.Method, Resource: *rl.Resource, HTTPVersion: *rl.HttpVersion, Status: *rl.Status, ResponseSize: *rl.ResponseSize, Referrer: rl.GetReferrer(), UserAgent: rl.GetUserAgent(), URLMapEntry: *rl.UrlMapEntry, Combined: *rl.Combined, Host: rl.GetHost(), Cost: rl.GetCost(), TaskQueueName: rl.GetTaskQueueName(), TaskName: rl.GetTaskName(), WasLoadingRequest: rl.GetWasLoadingRequest(), PendingTime: time.Duration(rl.GetPendingTime()) * time.Microsecond, Finished: rl.GetFinished(), AppLogs: protoToAppLogs(rl.Line), } }
func handle(w http.ResponseWriter, req *http.Request) { c := appengine.NewContext(req) if !user.IsAdmin(c) { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusUnauthorized) io.WriteString(w, "You must be logged in as an administrator to access this.\n") return } if req.Header.Get("X-Appcfg-Api-Version") == "" { w.Header().Set("Content-Type", "text/plain; charset=utf-8") w.WriteHeader(http.StatusForbidden) io.WriteString(w, "This request did not contain a necessary header.\n") return } if req.Method != "POST" { // Response must be YAML. rtok := req.FormValue("rtok") if rtok == "" { rtok = "0" } w.Header().Set("Content-Type", "text/yaml; charset=utf-8") fmt.Fprintf(w, `{app_id: %q, rtok: %q}`, c.FullyQualifiedAppID(), rtok) return } defer req.Body.Close() body, err := ioutil.ReadAll(req.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) c.Errorf("Failed reading body: %v", err) return } remReq := &pb.Request{} if err := proto.Unmarshal(body, remReq); err != nil { w.WriteHeader(http.StatusBadRequest) c.Errorf("Bad body: %v", err) return } // Only allow datastore_v3 for now, or AllocateIds for datastore_v4. service, method := *remReq.ServiceName, *remReq.Method ok := service == "datastore_v3" || (service == "datastore_v4" && method == "AllocateIds") if !ok { w.WriteHeader(http.StatusBadRequest) c.Errorf("Unsupported RPC /%s.%s", service, method) return } rawReq := &rawMessage{remReq.Request} rawRes := &rawMessage{} err = c.Call(service, method, rawReq, rawRes, nil) remRes := &pb.Response{} if err == nil { remRes.Response = rawRes.buf } else if ae, ok := err.(*appengine_internal.APIError); ok { remRes.ApplicationError = &pb.ApplicationError{ Code: &ae.Code, Detail: &ae.Detail, } } else { // This shouldn't normally happen. c.Errorf("appengine/remote_api: Unexpected error of type %T: %v", err, err) remRes.ApplicationError = &pb.ApplicationError{ Code: proto.Int32(0), Detail: proto.String(err.Error()), } } out, err := proto.Marshal(remRes) if err != nil { // This should not be possible. w.WriteHeader(500) c.Errorf("proto.Marshal: %v", err) return } c.Infof("Spooling %d bytes of response to /%s.%s", len(out), service, method) w.Header().Set("Content-Type", "application/octet-stream") w.Header().Set("Content-Length", strconv.Itoa(len(out))) w.Write(out) }