cubefs

Форк
0
160 строк · 3.4 Кб
1
// Copyright 2022 The CubeFS Authors.
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//     http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
// implied. See the License for the specific language governing
13
// permissions and limitations under the License.
14

15
package rpc
16

17
import (
18
	"context"
19
	"encoding/json"
20
	"errors"
21
	"net/http"
22
	"strconv"
23
	"syscall"
24
)
25

26
type (
27
	// Error implements HTTPError
28
	Error struct {
29
		Status int    // http status code
30
		Code   string // error code
31
		Err    error  // error
32
	}
33

34
	// errorResponse response error with json
35
	// internal type between server and client
36
	errorResponse struct {
37
		Error string `json:"error"`
38
		Code  string `json:"code,omitempty"`
39
	}
40

41
	statusCoder interface {
42
		StatusCode() int
43
	}
44
	errorCoder interface {
45
		ErrorCode() string
46
	}
47
)
48

49
var _ HTTPError = &Error{}
50

51
// NewError new error with
52
func NewError(statusCode int, errCode string, err error) *Error {
53
	return &Error{
54
		Status: statusCode,
55
		Code:   errCode,
56
		Err:    err,
57
	}
58
}
59

60
// StatusCode returns http status code
61
func (e *Error) StatusCode() int {
62
	return e.Status
63
}
64

65
// ErrorCode returns special defined code
66
func (e *Error) ErrorCode() string {
67
	return e.Code
68
}
69

70
// Error implements error
71
func (e *Error) Error() string {
72
	if e.Err == nil {
73
		return ""
74
	}
75
	return e.Err.Error()
76
}
77

78
// Unwrap errors.Is(), errors.As() and errors.Unwrap()
79
func (e *Error) Unwrap() error {
80
	return e.Err
81
}
82

83
// DetectStatusCode returns http status code
84
func DetectStatusCode(err error) int {
85
	if err == nil {
86
		return http.StatusOK
87
	}
88

89
	var st statusCoder
90
	if errors.As(err, &st) {
91
		return st.StatusCode()
92
	}
93

94
	switch err {
95
	case syscall.EINVAL:
96
		return http.StatusBadRequest
97
	case context.Canceled:
98
		return 499
99
	default:
100
		return http.StatusInternalServerError
101
	}
102
}
103

104
// DetectErrorCode returns error code
105
func DetectErrorCode(err error) string {
106
	if err == nil {
107
		return ""
108
	}
109

110
	var ec errorCoder
111
	if errors.As(err, &ec) {
112
		return ec.ErrorCode()
113
	}
114

115
	switch err {
116
	case syscall.EINVAL:
117
		return "BadRequest"
118
	case context.Canceled:
119
		return "Canceled"
120
	default:
121
		return "InternalServerError"
122
	}
123
}
124

125
// DetectError returns status code, error code, error
126
func DetectError(err error) (int, string, error) {
127
	return DetectStatusCode(err), DetectErrorCode(err), errors.Unwrap(err)
128
}
129

130
// Error2HTTPError returns an interface HTTPError from an error
131
func Error2HTTPError(err error) HTTPError {
132
	if err == nil {
133
		return nil
134
	}
135
	if httpErr, ok := err.(HTTPError); ok {
136
		return httpErr
137
	}
138

139
	status, code, _ := DetectError(err)
140
	return NewError(status, code, err)
141
}
142

143
// ReplyErr directly reply error with response writer
144
func ReplyErr(w http.ResponseWriter, code int, err string) {
145
	msg, _ := json.Marshal(NewError(code, "", errors.New(err)))
146
	h := w.Header()
147
	h.Set("Content-Length", strconv.Itoa(len(msg)))
148
	h.Set("Content-Type", MIMEJSON)
149
	w.WriteHeader(code)
150
	w.Write(msg)
151
}
152

153
// ReplyWith directly reply body with response writer
154
func ReplyWith(w http.ResponseWriter, code int, bodyType string, msg []byte) {
155
	h := w.Header()
156
	h.Set("Content-Length", strconv.Itoa(len(msg)))
157
	h.Set("Content-Type", bodyType)
158
	w.WriteHeader(code)
159
	w.Write(msg)
160
}
161

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.