-
Notifications
You must be signed in to change notification settings - Fork 4.6k
transport/grpcframer: create grpcframer package #7397
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
be858f0
a77e5d5
070d347
78c4957
cb35582
4a02377
10207e3
5990250
67e36ff
610bf63
4c20283
6a18aed
cc8bc6b
93fc866
e450516
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,70 @@ | ||
| /* | ||
| * | ||
| * Copyright 2024 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| package grpchttp2 | ||
|
|
||
| // ErrCode represents an HTTP/2 Error Code. Error codes are 32-bit fields | ||
| // that are used in [RST_STREAM] and [GOAWAY] frames to convey the reasons for | ||
| // the stream or connection error. See [HTTP/2 Error Code] for definitions of | ||
| // each of the following error codes. | ||
| // | ||
| // [HTTP/2 Error Code]: https://httpwg.org/specs/rfc7540.html#ErrorCodes | ||
| // [RST_STREAM]: https://httpwg.org/specs/rfc7540.html#RST_STREAM | ||
| // [GOAWAY]: https://httpwg.org/specs/rfc7540.html#GOAWAY | ||
| type ErrCode uint32 | ||
|
|
||
| const ( | ||
| ErrCodeNoError ErrCode = 0x0 | ||
| ErrCodeProtocol ErrCode = 0x1 | ||
| ErrCodeInternal ErrCode = 0x2 | ||
| ErrCodeFlowControl ErrCode = 0x3 | ||
| ErrCodeSettingsTimeout ErrCode = 0x4 | ||
| ErrCodeStreamClosed ErrCode = 0x5 | ||
| ErrCodeFrameSize ErrCode = 0x6 | ||
| ErrCodeRefusedStream ErrCode = 0x7 | ||
| ErrCodeCancel ErrCode = 0x8 | ||
| ErrCodeCompression ErrCode = 0x9 | ||
| ErrCodeConnect ErrCode = 0xa | ||
| ErrCodeEnhanceYourCalm ErrCode = 0xb | ||
| ErrCodeIndaequateSecurity ErrCode = 0xc | ||
| ErrCodeHTTP11Required ErrCode = 0xd | ||
| ) | ||
|
|
||
| var errorCodeNames = map[ErrCode]string{ | ||
| ErrCodeNoError: "NO_ERROR", | ||
| ErrCodeProtocol: "PROTOCOL_ERROR", | ||
| ErrCodeInternal: "INTERNAL_ERROR", | ||
| ErrCodeFlowControl: "FLOW_CONTROL_ERROR", | ||
| ErrCodeSettingsTimeout: "SETTINGS_TIMEOUT", | ||
| ErrCodeStreamClosed: "STREAM_CLOSED", | ||
| ErrCodeFrameSize: "FRAME_SIZE_ERROR", | ||
| ErrCodeRefusedStream: "REFUSED_STREAM", | ||
| ErrCodeCancel: "CANCEL", | ||
| ErrCodeCompression: "COMPRESSION_ERROR", | ||
| ErrCodeConnect: "CONNECT_ERROR", | ||
| ErrCodeEnhanceYourCalm: "ENHANCE_YOUR_CALM", | ||
| ErrCodeIndaequateSecurity: "INADEQUATE_SECURITY", | ||
| ErrCodeHTTP11Required: "HTTP_1_1_REQUIRED", | ||
| } | ||
|
|
||
| func (err ErrCode) String() string { | ||
| if v, ok := errorCodeNames[err]; ok { | ||
| return v | ||
| } | ||
| return "INTERNAL_ERROR" | ||
printchard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,246 @@ | ||
| /* | ||
| * | ||
| * Copyright 2024 gRPC authors. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| * | ||
| */ | ||
|
|
||
| // Package grpchttp2 defines HTTP/2 types and a framer API and implementation. | ||
| package grpchttp2 | ||
|
|
||
| import "golang.org/x/net/http2/hpack" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bummer. We cannot fully get rid of
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true. But Ricardo did mention this in his design, and also |
||
|
|
||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| // FrameType represents the type of an HTTP/2 Frame. | ||
| // See [Frame Type]. | ||
| // | ||
| // [Frame Type]: https://httpwg.org/specs/rfc7540.html#FrameType | ||
| type FrameType uint8 | ||
|
|
||
| const ( | ||
| FrameTypeData FrameType = 0x0 | ||
| FrameTypeHeaders FrameType = 0x1 | ||
| FrameTypePriority FrameType = 0x2 | ||
| FrameTypeRSTStream FrameType = 0x3 | ||
| FrameTypeSettings FrameType = 0x4 | ||
| FrameTypePushPromise FrameType = 0x5 | ||
| FrameTypePing FrameType = 0x6 | ||
| FrameTypeGoAway FrameType = 0x7 | ||
| FrameTypeWindowUpdate FrameType = 0x8 | ||
| FrameTypeContinuation FrameType = 0x9 | ||
printchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| ) | ||
|
|
||
| // Flags represents one or more flags set on an HTTP/2 Frame. | ||
| type Flags uint8 | ||
|
|
||
| const ( | ||
| FlagDataEndStream Flags = 0x1 | ||
| FlagDataPadded Flags = 0x8 | ||
| FlagHeadersEndStream Flags = 0x1 | ||
| FlagHeadersEndHeaders Flags = 0x4 | ||
| FlagHeadersPadded Flags = 0x8 | ||
| FlagHeadersPriority Flags = 0x20 | ||
| FlagSettingsAck Flags = 0x1 | ||
| FlagPingAck Flags = 0x1 | ||
| FlagContinuationEndHeaders Flags = 0x4 | ||
| ) | ||
|
|
||
| // Setting represents the id and value pair of an HTTP/2 setting. | ||
| // See [Setting Format]. | ||
| // | ||
| // [Setting Format]: https://httpwg.org/specs/rfc7540.html#SettingFormat | ||
| type Setting struct { | ||
| ID SettingID | ||
| Value uint32 | ||
| } | ||
|
|
||
| // SettingID represents the id of an HTTP/2 setting. | ||
| // See [Setting Values]. | ||
| // | ||
| // [Setting Values]: https://httpwg.org/specs/rfc7540.html#SettingValues | ||
| type SettingID uint16 | ||
|
|
||
| const ( | ||
| SettingsHeaderTableSize SettingID = 0x1 | ||
| SettingsEnablePush SettingID = 0x2 | ||
| SettingsMaxConcurrentStreams SettingID = 0x3 | ||
| SettingsInitialWindowSize SettingID = 0x4 | ||
| SettingsMaxFrameSize SettingID = 0x5 | ||
| SettingsMaxHeaderListSize SettingID = 0x6 | ||
| ) | ||
|
|
||
| // FrameHeader is the 9 byte header of any HTTP/2 Frame. | ||
| // See [Frame Header]. | ||
| // | ||
| // [Frame Header]: https://httpwg.org/specs/rfc7540.html#FrameHeader | ||
| type FrameHeader struct { | ||
| // Size is the size of the frame's payload without the 9 header bytes. | ||
| // As per the HTTP/2 spec, size can be up to 3 bytes, but only frames | ||
| // up to 16KB can be processed without agreement. | ||
| Size uint32 | ||
| // Type is a byte that represents the Frame Type. | ||
| Type FrameType | ||
| // Flags is a byte representing the flags set on this Frame. | ||
| Flags Flags | ||
| // StreamID is the ID for the stream which this frame is for. If the | ||
| // frame is connection specific instead of stream specific, the | ||
| // streamID is 0. | ||
| StreamID uint32 | ||
| } | ||
|
|
||
| // Frame represents an HTTP/2 Frame. | ||
| type Frame interface { | ||
| Header() *FrameHeader | ||
printchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| type DataFrame struct { | ||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| hdr *FrameHeader | ||
| free func() | ||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Data []byte | ||
printchard marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| func (f *DataFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| func (f *DataFrame) Free() { | ||
| if f.free != nil { | ||
| f.free() | ||
| } | ||
| } | ||
|
|
||
| type HeadersFrame struct { | ||
| hdr *FrameHeader | ||
| free func() | ||
| HdrBlock []byte | ||
| } | ||
|
|
||
| func (f *HeadersFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| func (f *HeadersFrame) Free() { | ||
| if f.free != nil { | ||
| f.free() | ||
| } | ||
| } | ||
|
|
||
| type RSTStreamFrame struct { | ||
| hdr *FrameHeader | ||
| Code ErrCode | ||
| } | ||
|
|
||
| func (f *RSTStreamFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| type SettingsFrame struct { | ||
| hdr *FrameHeader | ||
| free func() | ||
printchard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| settings []Setting | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| func (f *SettingsFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| type PingFrame struct { | ||
| hdr *FrameHeader | ||
| free func() | ||
| Data []byte | ||
| } | ||
|
|
||
| func (f *PingFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| func (f *PingFrame) Free() { | ||
| if f.free != nil { | ||
| f.free() | ||
| } | ||
| } | ||
|
|
||
| type GoAwayFrame struct { | ||
| hdr *FrameHeader | ||
| free func() | ||
| LastStreamID uint32 | ||
| Code ErrCode | ||
| DebugData []byte | ||
| } | ||
|
|
||
| func (f *GoAwayFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| func (f *GoAwayFrame) Free() { | ||
| if f.free != nil { | ||
| f.free() | ||
| } | ||
| } | ||
|
|
||
| type WindowUpdateFrame struct { | ||
| hdr *FrameHeader | ||
| Inc uint32 | ||
| } | ||
|
|
||
| func (f *WindowUpdateFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| type ContinuationFrame struct { | ||
| hdr *FrameHeader | ||
| free func() | ||
| HdrBlock []byte | ||
| } | ||
|
|
||
| func (f *ContinuationFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| func (f *ContinuationFrame) Free() { | ||
| if f.free != nil { | ||
| f.free() | ||
| } | ||
| } | ||
|
|
||
| // MetaHeadersFrame is not a Frame Type that appears on the HTTP/2 Spec. It is | ||
| // a representation of the merging and decoding of all the Headers and | ||
| // Continuation frames on a Stream. | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| type MetaHeadersFrame struct { | ||
| hdr *FrameHeader | ||
| Fields []hpack.HeaderField | ||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| func (f *MetaHeadersFrame) Header() *FrameHeader { | ||
| return f.hdr | ||
| } | ||
|
|
||
| // Framer represents a Framer used in gRPC-Go. | ||
printchard marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| type Framer interface { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I believe we need a We are missing coverage for all the methods on the structs introduced in the PR. Using this framer to test the different frame types might be ideal here imo.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes! A However, if you think it should be implemented here, it definitely is possible. |
||
| // SetMetaDecoder will set a decoder for the framer. When the decoder is | ||
| // set, ReadFrame will parse the header values, merging all Headers and | ||
| // Continuation frames. | ||
| SetMetaDecoder(d *hpack.Decoder) | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // ReadFrame returns an HTTP/2 Frame. It is the caller's responsibility to | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| // free the frame once it is done using it. | ||
| ReadFrame() (Frame, error) | ||
| WriteData(streamID uint32, endStream bool, data ...[]byte) error | ||
easwars marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| WriteHeaders(streamID uint32, endStream, endHeaders bool, headerBlock ...[]byte) error | ||
easwars marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| WriteRSTStream(streamID uint32, code ErrCode) error | ||
| WriteSettings(settings ...Setting) error | ||
| WriteSettingsAck() error | ||
| WritePing(ack bool, data [8]byte) error | ||
| WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error | ||
| WriteWindowUpdate(streamID, inc uint32) error | ||
| WriteContinuation(streamID uint32, endHeaders bool, headerBlock ...[]byte) error | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.