in lib/handlerfactory/request_handler.go [82:169]
func Process(s storage.Store, opts *Options, r *http.Request) (_ proto.Message, ferr error) {
defer func() {
if c := recover(); c != nil {
glog.Errorf("CRASH %s %s: %v\n%s", r.Method, r.URL.Path, c, string(debug.Stack()))
if ferr == nil {
ferr = status.Errorf(codes.Internal, "internal error")
}
}
}()
hi := opts.Service()
var op func(*http.Request, string) (proto.Message, error)
switch r.Method {
case http.MethodGet:
op = hi.Get
case http.MethodPost:
op = hi.Post
case http.MethodPut:
op = hi.Put
case http.MethodPatch:
op = hi.Patch
case http.MethodDelete:
op = hi.Remove
default:
return nil, status.Errorf(codes.InvalidArgument, "request method not supported: %q", r.Method)
}
// TODO: move inside each service and don't pass NameChecker here.
name, vars, err := ValidateResourceName(r, opts.NameField, opts.NameChecker)
if err != nil {
return nil, status.Errorf(codes.InvalidArgument, "%v", err)
}
typ := opts.TypeName
desc := r.Method + " " + typ
tx, err := s.Tx(r.Method != http.MethodGet)
if err != nil {
return nil, status.Errorf(codes.Unavailable, "service dependencies not available; try again later")
}
defer func() {
err := tx.Finish()
if ferr == nil {
ferr = err
}
}()
// Get rid of Setup and move creation of transaction inside service methods.
//
if _, err = hi.Setup(r, tx); err != nil {
return nil, err
}
// TODO: Replace NormalizeInput with a ParseReq that returns a request proto message.
// TODO: Explicitly pass the message to the service methods.
if err := hi.NormalizeInput(r, name, vars); err != nil {
return nil, toStatusErr(codes.InvalidArgument, err, r)
}
// TODO: get rid of LookupItem and move this inside the service methods.
exists := hi.LookupItem(r, name, vars)
switch r.Method {
case http.MethodPost:
if exists {
return nil, status.Errorf(codes.AlreadyExists, "%s already exists: %q", typ, name)
}
case http.MethodGet, http.MethodPatch, http.MethodPut, http.MethodDelete:
if !exists {
if opts.HasNamedIdentifiers {
return nil, status.Errorf(codes.NotFound, "%s not found: %q", typ, name)
}
return nil, status.Errorf(codes.NotFound, "%s not found", typ)
}
}
if r.Method == http.MethodGet {
resp, err := op(r, name)
if err != nil {
return nil, toStatusErr(codes.InvalidArgument, err, r)
}
return resp, nil
}
resp, err := RunRMWTx(r, tx, op, hi.CheckIntegrity, hi.Save, name, vars, typ, desc)
if err != nil {
return nil, err
}
return resp, nil
}