func timeoutEncode(t time.Duration) string {
	if d := div(t, time.Nanosecond); d <= maxTimeoutValue {
		return strconv.FormatInt(d, 10) + "n"
	}
	if d := div(t, time.Microsecond); d <= maxTimeoutValue {
		return strconv.FormatInt(d, 10) + "u"
	}
	if d := div(t, time.Millisecond); d <= maxTimeoutValue {
		return strconv.FormatInt(d, 10) + "m"
	}
	if d := div(t, time.Second); d <= maxTimeoutValue {
		return strconv.FormatInt(d, 10) + "S"
	}
	if d := div(t, time.Minute); d <= maxTimeoutValue {
		return strconv.FormatInt(d, 10) + "M"
	}
	return strconv.FormatInt(div(t, time.Hour), 10) + "H"
}
TODO(zhaoq): It is the simplistic and not bandwidth efficient. Improve it.
package transport
import (
	"bufio"
	"fmt"
	"io"
	"net"
	"strconv"
	"strings"
	"sync/atomic"
	"time"
	"golang.org/x/net/http2"
	"golang.org/x/net/http2/hpack"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/grpclog"
	"google.golang.org/grpc/metadata"
)
const (
	primaryUA = "grpc-go/0.11"
	http2MaxFrameLen = 16384  
	http2InitHeaderTableSize = 4096
	http2IOBufSize = 32 * 1024
)
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.FailedPrecondition,
	}
	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,
	}
)
type decodeState struct {
	err error  
	encoding string
	statusCode codes.Code
	statusDesc string
	timeoutSet bool
	timeout    time.Duration
	method     string
	mdata map[string][]string
}
func isReservedHeader(hdr string) bool {
	if hdr != "" && hdr[0] == ':' {
		return true
	}
	switch hdr {
	case "content-type",
		"grpc-message-type",
		"grpc-encoding",
		"grpc-message",
		"grpc-status",
		"grpc-timeout",
		"te":
		return true
	default:
		return false
	}
}
func (d *decodeState) setErr(err error) {
	if d.err == nil {
		d.err = err
	}
}
func (d *decodeState) processHeaderField(f hpack.HeaderField) {
	switch f.Name {
	case "content-type":
		if !strings.Contains(f.Value, "application/grpc") {
			d.setErr(StreamErrorf(codes.FailedPrecondition, "transport: received the unexpected content-type %q", f.Value))
			return
		}
	case "grpc-encoding":
		d.encoding = f.Value
	case "grpc-status":
		code, err := strconv.Atoi(f.Value)
		if err != nil {
			d.setErr(StreamErrorf(codes.Internal, "transport: malformed grpc-status: %v", err))
			return
		}
		d.statusCode = codes.Code(code)
	case "grpc-message":
		d.statusDesc = f.Value
	case "grpc-timeout":
		d.timeoutSet = true
		var err error
		d.timeout, err = timeoutDecode(f.Value)
		if err != nil {
			d.setErr(StreamErrorf(codes.Internal, "transport: malformed time-out: %v", err))
			return
		}
	case ":path":
		d.method = f.Value
	default:
		if !isReservedHeader(f.Name) {
			if f.Name == "user-agent" {
				i := strings.LastIndex(f.Value, " ")
				if i == -1 {
					return
				}
				f.Value = f.Value[:i]
			}
			if d.mdata == nil {
				d.mdata = make(map[string][]string)
			}
			k, v, err := metadata.DecodeKeyValue(f.Name, f.Value)
			if err != nil {
				grpclog.Printf("Failed to decode (%q, %q): %v", f.Name, f.Value, err)
				return
			}
			d.mdata[k] = append(d.mdata[k], v)
		}
	}
}
type timeoutUnit uint8
const (
	hour        timeoutUnit = 'H'
	minute      timeoutUnit = 'M'
	second      timeoutUnit = 'S'
	millisecond timeoutUnit = 'm'
	microsecond timeoutUnit = 'u'
	nanosecond  timeoutUnit = 'n'
)
func timeoutUnitToDuration(u timeoutUnit) (d time.Duration, ok bool) {
	switch u {
	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
}
const maxTimeoutValue int64 = 100000000 - 1
func div(d, r time.Duration) int64 {
	if m := d % r; m > 0 {
		return int64(d/r + 1)
	}
	return int64(d / r)
}