- 
                Notifications
    You must be signed in to change notification settings 
- Fork 4.6k
transport/grpchttp2: add http2.Framer bridge #7453
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
          
     Merged
      
      
    
      
        
          +911
        
        
          −0
        
        
          
        
      
    
  
  
     Merged
                    Changes from all commits
      Commits
    
    
            Show all changes
          
          
            22 commits
          
        
        Select commit
          Hold shift + click to select a range
      
      f43d3b9
              
                implement http2bridge
              
              
                printchard 3b2ddb7
              
                address comments and merge branches
              
              
                printchard 239a4dd
              
                Revert "address comments and merge branches"
              
              
                printchard e00de1e
              
                address comments
              
              
                printchard c91fc3b
              
                Merge branch 'master' into framer-adapter
              
              
                printchard e1dfe25
              
                remove unused method
              
              
                printchard 6490228
              
                remove duplciated comments
              
              
                printchard c9fa84d
              
                Rename structs and refactor tests
              
              
                printchard 6e784be
              
                fix vet
              
              
                printchard d71d065
              
                Merge branch 'master' into framer-adapter
              
              
                printchard 6883fff
              
                Rename tests
              
              
                printchard 7b02e5f
              
                Revert "transport/grpchttp2: change types to include `mem` package (#…
              
              
                printchard 37731a5
              
                Merge branch 'master' into framer-adapter
              
              
                printchard 529afa6
              
                Roll back the usage of mem.buffers
              
              
                printchard b64f976
              
                fix mem types on WriteData
              
              
                printchard d412a87
              
                Address more comments
              
              
                printchard 3447612
              
                Merge branch 'master' into framer-adapter
              
              
                printchard c716f26
              
                Remove connError
              
              
                printchard b04dd6d
              
                refactor tests
              
              
                printchard c9454c4
              
                Refactor returning frames and test helper functions
              
              
                printchard 0d5edcb
              
                Refactor write check
              
              
                printchard eafb63c
              
                Change doc
              
              
                printchard File filter
Filter by extension
Conversations
          Failed to load comments.   
        
        
          
      Loading
        
  Jump to
        
          Jump to file
        
      
      
          Failed to load files.   
        
        
          
      Loading
        
  Diff view
Diff view
There are no files selected for viewing
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              |         
                  easwars marked this conversation as resolved.
              Show resolved
            Hide resolved | 
  
    
      This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
      Learn more about bidirectional Unicode characters
    
  
  
    
              | Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,225 @@ | ||
| /* | ||
| * | ||
| * 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 | ||
|  | ||
| import ( | ||
| "io" | ||
|  | ||
| "golang.org/x/net/http2" | ||
| "golang.org/x/net/http2/hpack" | ||
| "google.golang.org/grpc/mem" | ||
| ) | ||
|  | ||
| // FramerBridge adapts the net/x/http2 Framer to satisfy the grpchttp2.Framer | ||
| // interface. | ||
| // | ||
| // Note: This allows temporary use of the older framer and will be removed in | ||
| // a future release after the new framer stabilizes. | ||
| type FramerBridge struct { | ||
| framer *http2.Framer // the underlying http2.Framer implementation to perform reads and writes. | ||
| pool mem.BufferPool // a pool to reuse buffers when reading. | ||
| } | ||
|  | ||
| // NewFramerBridge creates an adaptor that wraps a http2.Framer in a | ||
| // grpchttp2.Framer. | ||
| // | ||
| // Internally, it creates a http2.Framer that uses the provided io.Reader and | ||
| // io.Writer, and is configured with a maximum header list size of | ||
| // maxHeaderListSize. | ||
| // | ||
| // Frames returned by a call to the underlying http2.Framer's ReadFrame() method | ||
| // need to be consumed before the next call to it. To overcome this restriction, | ||
| // the data in a Frame returned by the http2.Framer's ReadFrame is copied into a | ||
| // buffer from the given pool. If no pool is provided, a default pool provided | ||
| // by the mem package is used. | ||
| func NewFramerBridge(w io.Writer, r io.Reader, maxHeaderListSize uint32, pool mem.BufferPool) *FramerBridge { | ||
| fr := http2.NewFramer(w, r) | ||
| fr.SetReuseFrames() | ||
| fr.MaxHeaderListSize = maxHeaderListSize | ||
| fr.ReadMetaHeaders = hpack.NewDecoder(initHeaderTableSize, nil) | ||
|  | ||
| if pool == nil { | ||
| pool = mem.DefaultBufferPool() | ||
|         
                  arvindbr8 marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| } | ||
|  | ||
| return &FramerBridge{ | ||
| framer: fr, | ||
| pool: pool, | ||
| } | ||
| } | ||
|  | ||
| // ReadFrame reads a frame from the underlying http2.Framer and returns a | ||
| // Frame defined in the grpchttp2 package. This operation copies the data to a | ||
| // buffer from the pool, making it safe to use even after another call to | ||
| // ReadFrame. | ||
| func (fr *FramerBridge) ReadFrame() (Frame, error) { | ||
| f, err := fr.framer.ReadFrame() | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|  | ||
| h := f.Header() | ||
|         
                  easwars marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| hdr := &FrameHeader{ | ||
| Size: h.Length, | ||
| Type: FrameType(h.Type), | ||
| Flags: Flag(h.Flags), | ||
| StreamID: h.StreamID, | ||
| } | ||
|  | ||
| switch f := f.(type) { | ||
| case *http2.DataFrame: | ||
| buf := fr.pool.Get(int(hdr.Size)) | ||
| copy(buf, f.Data()) | ||
| return &DataFrame{ | ||
| hdr: hdr, | ||
| Data: buf, | ||
| free: func() { fr.pool.Put(buf) }, | ||
| }, nil | ||
| case *http2.RSTStreamFrame: | ||
| return &RSTStreamFrame{ | ||
| hdr: hdr, | ||
| Code: ErrCode(f.ErrCode), | ||
| }, nil | ||
| case *http2.SettingsFrame: | ||
| buf := make([]Setting, 0, f.NumSettings()) | ||
| f.ForeachSetting(func(s http2.Setting) error { | ||
| buf = append(buf, Setting{ | ||
| ID: SettingID(s.ID), | ||
| Value: s.Val, | ||
| }) | ||
| return nil | ||
| }) | ||
| return &SettingsFrame{ | ||
| hdr: hdr, | ||
| Settings: buf, | ||
| }, nil | ||
| case *http2.PingFrame: | ||
| buf := fr.pool.Get(int(hdr.Size)) | ||
| copy(buf, f.Data[:]) | ||
| return &PingFrame{ | ||
| hdr: hdr, | ||
| Data: buf, | ||
| free: func() { fr.pool.Put(buf) }, | ||
| }, nil | ||
| case *http2.GoAwayFrame: | ||
| // Size of the frame minus the code and lastStreamID | ||
| buf := fr.pool.Get(int(hdr.Size) - 8) | ||
| copy(buf, f.DebugData()) | ||
| return &GoAwayFrame{ | ||
| hdr: hdr, | ||
| LastStreamID: f.LastStreamID, | ||
| Code: ErrCode(f.ErrCode), | ||
| DebugData: buf, | ||
| free: func() { fr.pool.Put(buf) }, | ||
| }, nil | ||
| case *http2.WindowUpdateFrame: | ||
| return &WindowUpdateFrame{ | ||
| hdr: hdr, | ||
| Inc: f.Increment, | ||
| }, nil | ||
| case *http2.MetaHeadersFrame: | ||
| return &MetaHeadersFrame{ | ||
| hdr: hdr, | ||
| Fields: f.Fields, | ||
| }, nil | ||
| default: | ||
| buf := fr.pool.Get(int(hdr.Size)) | ||
|         
                  arvindbr8 marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| uf := f.(*http2.UnknownFrame) | ||
| copy(buf, uf.Payload()) | ||
| return &UnknownFrame{ | ||
| hdr: hdr, | ||
| Payload: buf, | ||
| free: func() { fr.pool.Put(buf) }, | ||
| }, nil | ||
| } | ||
| } | ||
|  | ||
| // WriteData writes a DATA Frame into the underlying writer. | ||
| func (fr *FramerBridge) WriteData(streamID uint32, endStream bool, data ...[]byte) error { | ||
| if len(data) == 1 { | ||
|         
                  arvindbr8 marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| return fr.framer.WriteData(streamID, endStream, data[0]) | ||
| } | ||
|  | ||
| var buf []byte | ||
|         
                  arvindbr8 marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| tl := 0 | ||
| for _, s := range data { | ||
| tl += len(s) | ||
| } | ||
|  | ||
|         
                  easwars marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| buf = fr.pool.Get(tl)[:0] | ||
| defer fr.pool.Put(buf) | ||
| for _, s := range data { | ||
| buf = append(buf, s...) | ||
| } | ||
|  | ||
| return fr.framer.WriteData(streamID, endStream, buf) | ||
| } | ||
|  | ||
| // WriteHeaders writes a Headers Frame into the underlying writer. | ||
| func (fr *FramerBridge) WriteHeaders(streamID uint32, endStream, endHeaders bool, headerBlock []byte) error { | ||
| return fr.framer.WriteHeaders(http2.HeadersFrameParam{ | ||
| StreamID: streamID, | ||
| EndStream: endStream, | ||
| EndHeaders: endHeaders, | ||
| BlockFragment: headerBlock, | ||
| }) | ||
| } | ||
|  | ||
| // WriteRSTStream writes a RSTStream Frame into the underlying writer. | ||
| func (fr *FramerBridge) WriteRSTStream(streamID uint32, code ErrCode) error { | ||
| return fr.framer.WriteRSTStream(streamID, http2.ErrCode(code)) | ||
| } | ||
|  | ||
| // WriteSettings writes a Settings Frame into the underlying writer. | ||
| func (fr *FramerBridge) WriteSettings(settings ...Setting) error { | ||
| ss := make([]http2.Setting, 0, len(settings)) | ||
| for _, s := range settings { | ||
| ss = append(ss, http2.Setting{ | ||
| ID: http2.SettingID(s.ID), | ||
| Val: s.Value, | ||
| }) | ||
| } | ||
|  | ||
| return fr.framer.WriteSettings(ss...) | ||
| } | ||
|  | ||
| // WriteSettingsAck writes a Settings Frame with the Ack flag set. | ||
| func (fr *FramerBridge) WriteSettingsAck() error { | ||
| return fr.framer.WriteSettingsAck() | ||
| } | ||
|  | ||
| // WritePing writes a Ping frame to the underlying writer. | ||
| func (fr *FramerBridge) WritePing(ack bool, data [8]byte) error { | ||
|         
                  arvindbr8 marked this conversation as resolved.
              Show resolved
            Hide resolved | ||
| return fr.framer.WritePing(ack, data) | ||
| } | ||
|  | ||
| // WriteGoAway writes a GoAway Frame to the unerlying writer. | ||
| func (fr *FramerBridge) WriteGoAway(maxStreamID uint32, code ErrCode, debugData []byte) error { | ||
| return fr.framer.WriteGoAway(maxStreamID, http2.ErrCode(code), debugData) | ||
| } | ||
|  | ||
| // WriteWindowUpdate writes a WindowUpdate Frame into the underlying writer. | ||
| func (fr *FramerBridge) WriteWindowUpdate(streamID, inc uint32) error { | ||
| return fr.framer.WriteWindowUpdate(streamID, inc) | ||
| } | ||
|  | ||
| // WriteContinuation writes a Continuation Frame into the underlying writer. | ||
| func (fr *FramerBridge) WriteContinuation(streamID uint32, endHeaders bool, headerBlock []byte) error { | ||
| return fr.framer.WriteContinuation(streamID, endHeaders, headerBlock) | ||
| } | ||
      
      Oops, something went wrong.
        
    
  
  Add this suggestion to a batch that can be applied as a single commit.
  This suggestion is invalid because no changes were made to the code.
  Suggestions cannot be applied while the pull request is closed.
  Suggestions cannot be applied while viewing a subset of changes.
  Only one suggestion per line can be applied in a batch.
  Add this suggestion to a batch that can be applied as a single commit.
  Applying suggestions on deleted lines is not supported.
  You must change the existing code in this line in order to create a valid suggestion.
  Outdated suggestions cannot be applied.
  This suggestion has been applied or marked resolved.
  Suggestions cannot be applied from pending reviews.
  Suggestions cannot be applied on multi-line comments.
  Suggestions cannot be applied while the pull request is queued to merge.
  Suggestion cannot be applied right now. Please check back later.
  
    
  
    
Uh oh!
There was an error while loading. Please reload this page.