Source File
http_util.go
Belonging Package
google.golang.org/grpc/internal/transport
package transport
import (
spb
)
)
var (
clientPreface = []byte(http2.ClientPreface)
http2ErrConvTab = map[http2.ErrCode]codes.Code{
http2.ErrCodeNo: codes.Internal,
http2.ErrCodeProtocol: codes.Internal,
http2.ErrCodeInternal: codes.Internal,
http2.ErrCodeFlowControl: codes.ResourceExhausted,
http2.ErrCodeSettingsTimeout: codes.Internal,
http2.ErrCodeStreamClosed: codes.Internal,
http2.ErrCodeFrameSize: codes.Internal,
http2.ErrCodeRefusedStream: codes.Unavailable,
http2.ErrCodeCancel: codes.Canceled,
http2.ErrCodeCompression: codes.Internal,
http2.ErrCodeConnect: codes.Internal,
http2.ErrCodeEnhanceYourCalm: codes.ResourceExhausted,
http2.ErrCodeInadequateSecurity: codes.PermissionDenied,
http2.ErrCodeHTTP11Required: codes.Internal,
}
statusCodeConvTab = map[codes.Code]http2.ErrCode{
codes.Internal: http2.ErrCodeInternal,
codes.Canceled: http2.ErrCodeCancel,
codes.Unavailable: http2.ErrCodeRefusedStream,
codes.ResourceExhausted: http2.ErrCodeEnhanceYourCalm,
codes.PermissionDenied: http2.ErrCodeInadequateSecurity,
http.StatusGatewayTimeout: codes.Unavailable,
}
logger = grpclog.Component("transport")
)
type parsedHeaderData struct {
mdata map[string][]string
statsTags []byte
statsTrace []byte
contentSubtype string
.data.statusGen = status.New(codes.Code(int32(*(.data.rawStatusCode))), .data.rawStatusMsg)
}
return .data.statusGen
}
const binHdrSuffix = "-bin"
func ( []byte) string {
return base64.RawStdEncoding.EncodeToString()
}
func ( string) ([]byte, error) {
return base64.StdEncoding.DecodeString()
}
return base64.RawStdEncoding.DecodeString()
}
func (, string) string {
if strings.HasSuffix(, binHdrSuffix) {
return encodeBinHeader(([]byte)())
}
return
}
func (, string) (string, error) {
if strings.HasSuffix(, binHdrSuffix) {
, := decodeBinHeader()
return string(),
}
return , nil
}
if .data.httpErr != nil {
return .data.httpErr
}
var (
= codes.Internal // when header does not include HTTP status, return INTERNAL
bool
)
if .data.httpStatus != nil {
, = HTTPStatusConvTab[*(.data.httpStatus)]
if ! {
= codes.Unknown
}
}
return status.Error(, .constructHTTPErrMsg())
}
func ( *decodeState) () string {
var []string
if .data.httpStatus == nil {
= append(, "malformed header: missing HTTP status")
} else {
= append(, fmt.Sprintf("%s: HTTP status code %d", http.StatusText(*(.data.httpStatus)), *.data.httpStatus))
}
if .data.contentTypeErr == "" {
= append(, "transport: missing content-type field")
} else {
= append(, .data.contentTypeErr)
}
return strings.Join(, "; ")
}
func ( *decodeState) (, string) {
if .data.mdata == nil {
.data.mdata = make(map[string][]string)
}
.data.mdata[] = append(.data.mdata[], )
}
func ( *decodeState) ( hpack.HeaderField) {
switch .Name {
case "content-type":
, := grpcutil.ContentSubtype(.Value)
if ! {
.data.contentTypeErr = fmt.Sprintf("transport: received the unexpected content-type %q", .Value)
return
}
.addMetadata(.Name, .Value)
.data.isGRPC = true
case "grpc-encoding":
.data.encoding = .Value
case "grpc-status":
, := strconv.Atoi(.Value)
if != nil {
.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status: %v", )
return
}
.data.rawStatusCode = &
case "grpc-message":
.data.rawStatusMsg = decodeGrpcMessage(.Value)
case "grpc-status-details-bin":
, := decodeBinHeader(.Value)
if != nil {
.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", )
return
}
:= &spb.Status{}
if := proto.Unmarshal(, ); != nil {
.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-status-details-bin: %v", )
return
}
.data.statusGen = status.FromProto()
case "grpc-timeout":
.data.timeoutSet = true
var error
if .data.timeout, = decodeTimeout(.Value); != nil {
.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed time-out: %v", )
}
case ":path":
.data.method = .Value
case ":status":
, := strconv.Atoi(.Value)
if != nil {
.data.httpErr = status.Errorf(codes.Internal, "transport: malformed http-status: %v", )
return
}
.data.httpStatus = &
case "grpc-tags-bin":
, := decodeBinHeader(.Value)
if != nil {
.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-tags-bin: %v", )
return
}
.data.statsTags =
.addMetadata(.Name, string())
case "grpc-trace-bin":
, := decodeBinHeader(.Value)
if != nil {
.data.grpcErr = status.Errorf(codes.Internal, "transport: malformed grpc-trace-bin: %v", )
return
}
.data.statsTrace =
.addMetadata(.Name, string())
default:
if isReservedHeader(.Name) && !isWhitelistedHeader(.Name) {
break
}
, := decodeMetadataHeader(.Name, .Value)
if != nil {
if logger.V(logLevel) {
logger.Errorf("Failed to decode metadata header (%q, %q): %v", .Name, .Value, )
}
return
}
.addMetadata(.Name, )
}
}
type timeoutUnit uint8
const (
hour timeoutUnit = 'H'
minute timeoutUnit = 'M'
second timeoutUnit = 'S'
millisecond timeoutUnit = 'm'
microsecond timeoutUnit = 'u'
nanosecond timeoutUnit = 'n'
)
func ( timeoutUnit) ( time.Duration, bool) {
switch {
case hour:
return time.Hour, true
case minute:
return time.Minute, true
case second:
return time.Second, true
case millisecond:
return time.Millisecond, true
case microsecond:
return time.Microsecond, true
case nanosecond:
return time.Nanosecond, true
default:
}
return
}
func ( string) (time.Duration, error) {
:= len()
if < 2 {
return 0, fmt.Errorf("transport: timeout string is too short: %q", )
}
return 0, fmt.Errorf("transport: timeout string is too long: %q", )
}
:= timeoutUnit([-1])
, := timeoutUnitToDuration()
if ! {
return 0, fmt.Errorf("transport: timeout unit is not recognized: %q", )
}
, := strconv.ParseInt([:-1], 10, 64)
if != nil {
return 0,
}
const = math.MaxInt64 / int64(time.Hour)
func ( string) string {
if == "" {
return ""
}
:= len()
for := 0; < ; ++ {
:= []
if !( >= spaceByte && <= tildeByte && != percentByte) {
return encodeGrpcMessageUnchecked()
}
}
return
}
func ( string) string {
var bytes.Buffer
for len() > 0 {
, := utf8.DecodeRuneInString()
for , := range []byte(string()) {
.WriteString(fmt.Sprintf("%%%02X", ))
continue
}
if >= spaceByte && <= tildeByte && != percentByte {
.WriteByte()
} else {
.WriteString(fmt.Sprintf("%%%02X", ))
}
}
= [:]
}
return .String()
}
func ( string) string {
if == "" {
return ""
}
:= len()
for := 0; < ; ++ {
if [] == percentByte && +2 < {
return decodeGrpcMessageUnchecked()
}
}
return
}
func ( string) string {
var bytes.Buffer
:= len()
for := 0; < ; ++ {
:= []
if == percentByte && +2 < {
, := strconv.ParseUint([+1:+3], 16, 8)
if != nil {
.WriteByte()
} else {
.WriteByte(byte())
+= 2
}
} else {
.WriteByte()
}
}
return .String()
}
type bufWriter struct {
buf []byte
offset int
batchSize int
conn net.Conn
err error
onFlush func()
}
func ( net.Conn, int) *bufWriter {
return &bufWriter{
buf: make([]byte, *2),
batchSize: ,
conn: ,
}
}
func ( *bufWriter) ( []byte) ( int, error) {
if .err != nil {
return 0, .err
}
if .batchSize == 0 { // Buffer has been disabled.
return .conn.Write()
}
for len() > 0 {
:= copy(.buf[.offset:], )
= [:]
.offset +=
+=
if .offset >= .batchSize {
= .Flush()
}
}
return ,
}
func ( *bufWriter) () error {
if .err != nil {
return .err
}
if .offset == 0 {
return nil
}
if .onFlush != nil {
.onFlush()
}
_, .err = .conn.Write(.buf[:.offset])
.offset = 0
return .err
}
type framer struct {
writer *bufWriter
fr *http2.Framer
}
func ( net.Conn, , int, uint32) *framer {
if < 0 {
= 0
}
var io.Reader =
if > 0 {
= bufio.NewReaderSize(, )
}
:= newBufWriter(, )
:= &framer{
writer: ,
fr: http2.NewFramer(, ),
}
.fr.SetReuseFrames()
.fr.MaxHeaderListSize =
.fr.ReadMetaHeaders = hpack.NewDecoder(http2InitHeaderTableSize, nil)
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |