mirror of
https://github.com/optim-enterprises-bv/vault.git
synced 2025-11-01 19:17:58 +00:00
Port some replication bits to OSS (#2386)
This commit is contained in:
111
logical/response_util.go
Normal file
111
logical/response_util.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package logical
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/hashicorp/errwrap"
|
||||
multierror "github.com/hashicorp/go-multierror"
|
||||
"github.com/hashicorp/vault/helper/consts"
|
||||
)
|
||||
|
||||
// RespondErrorCommon pulls most of the functionality from http's
|
||||
// respondErrorCommon and some of http's handleLogical and makes it available
|
||||
// to both the http package and elsewhere.
|
||||
func RespondErrorCommon(req *Request, resp *Response, err error) (int, error) {
|
||||
if err == nil && (resp == nil || !resp.IsError()) {
|
||||
switch {
|
||||
case req.Operation == ReadOperation:
|
||||
if resp == nil {
|
||||
return http.StatusNotFound, nil
|
||||
}
|
||||
|
||||
// Basically: if we have empty "keys" or no keys at all, 404. This
|
||||
// provides consistency with GET.
|
||||
case req.Operation == ListOperation && resp.WrapInfo == nil:
|
||||
if resp == nil || len(resp.Data) == 0 {
|
||||
return http.StatusNotFound, nil
|
||||
}
|
||||
keysRaw, ok := resp.Data["keys"]
|
||||
if !ok || keysRaw == nil {
|
||||
return http.StatusNotFound, nil
|
||||
}
|
||||
keys, ok := keysRaw.([]string)
|
||||
if !ok {
|
||||
return http.StatusInternalServerError, nil
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
return http.StatusNotFound, nil
|
||||
}
|
||||
}
|
||||
|
||||
return 0, nil
|
||||
}
|
||||
|
||||
if errwrap.ContainsType(err, new(ReplicationCodedError)) {
|
||||
var allErrors error
|
||||
codedErr := errwrap.GetType(err, new(ReplicationCodedError)).(*ReplicationCodedError)
|
||||
errwrap.Walk(err, func(inErr error) {
|
||||
newErr, ok := inErr.(*ReplicationCodedError)
|
||||
if !ok {
|
||||
allErrors = multierror.Append(allErrors, newErr)
|
||||
}
|
||||
})
|
||||
if allErrors != nil {
|
||||
return codedErr.Code, multierror.Append(errors.New(fmt.Sprintf("errors from both primary and secondary; primary error was %v; secondary errors follow", codedErr.Msg)), allErrors)
|
||||
}
|
||||
return codedErr.Code, errors.New(codedErr.Msg)
|
||||
}
|
||||
|
||||
// Start out with internal server error since in most of these cases there
|
||||
// won't be a response so this won't be overridden
|
||||
statusCode := http.StatusInternalServerError
|
||||
// If we actually have a response, start out with bad request
|
||||
if resp != nil {
|
||||
statusCode = http.StatusBadRequest
|
||||
}
|
||||
|
||||
// Now, check the error itself; if it has a specific logical error, set the
|
||||
// appropriate code
|
||||
if err != nil {
|
||||
switch {
|
||||
case errwrap.ContainsType(err, new(StatusBadRequest)):
|
||||
statusCode = http.StatusBadRequest
|
||||
case errwrap.Contains(err, ErrPermissionDenied.Error()):
|
||||
statusCode = http.StatusForbidden
|
||||
case errwrap.Contains(err, ErrUnsupportedOperation.Error()):
|
||||
statusCode = http.StatusMethodNotAllowed
|
||||
case errwrap.Contains(err, ErrUnsupportedPath.Error()):
|
||||
statusCode = http.StatusNotFound
|
||||
case errwrap.Contains(err, ErrInvalidRequest.Error()):
|
||||
statusCode = http.StatusBadRequest
|
||||
}
|
||||
}
|
||||
|
||||
if resp != nil && resp.IsError() {
|
||||
err = fmt.Errorf("%s", resp.Data["error"].(string))
|
||||
}
|
||||
|
||||
return statusCode, err
|
||||
}
|
||||
|
||||
// AdjustErrorStatusCode adjusts the status that will be sent in error
|
||||
// conditions in a way that can be shared across http's respondError and other
|
||||
// locations.
|
||||
func AdjustErrorStatusCode(status *int, err error) {
|
||||
// Adjust status code when sealed
|
||||
if errwrap.Contains(err, consts.ErrSealed.Error()) {
|
||||
*status = http.StatusServiceUnavailable
|
||||
}
|
||||
|
||||
// Adjust status code on
|
||||
if errwrap.Contains(err, "http: request body too large") {
|
||||
*status = http.StatusRequestEntityTooLarge
|
||||
}
|
||||
|
||||
// Allow HTTPCoded error passthrough to specify a code
|
||||
if t, ok := err.(HTTPCodedError); ok {
|
||||
*status = t.Code()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user