github.com/google/martian/v3@v3.3.3/h2/processor.go (about)

     1  // Copyright 2021 Google Inc. All rights reserved.
     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 implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package h2
    16  
    17  import (
    18  	"fmt"
    19  	"net/url"
    20  
    21  	"golang.org/x/net/http2"
    22  	"golang.org/x/net/http2/hpack"
    23  )
    24  
    25  // Direction indicates the direction of the traffic flow.
    26  type Direction uint8
    27  
    28  const (
    29  	// ClientToServer indicates traffic flowing from client-to-server.
    30  	ClientToServer Direction = iota
    31  	// ServerToClient indicates traffic flowing from server-to-client.
    32  	ServerToClient
    33  )
    34  
    35  // StreamProcessorFactory is implemented by clients that wish to observe or edit HTTP/2 frames
    36  // flowing through the proxy. It creates a pair of processors for the bidirectional stream. A
    37  // processor consumes frames then calls the corresponding sink methods to forward frames to the
    38  // destination, modifying the frame if needed.
    39  //
    40  // Returns the client-to-server and server-to-client processors. Nil values are safe to return and
    41  // no processing occurs in such cases. NOTE: an interface may have a non-nil type with a nil value.
    42  // Such values are treated as valid processors.
    43  //
    44  // Concurrency: there is a separate client-to-server and server-to-client thread. Calls against
    45  // the `ClientToServer` sink must be made on the client-to-server thread and calls against
    46  // the `ServerToClient` sink must be made on the server-to-client thread. Implementors should
    47  // guard interactions across threads.
    48  type StreamProcessorFactory func(url *url.URL, sinks *Processors) (Processor, Processor)
    49  
    50  // Processors encapsulates the two traffic receiving endpoints.
    51  type Processors struct {
    52  	cToS, sToC Processor
    53  }
    54  
    55  // ForDirection returns the processor receiving traffic in the given direction.
    56  func (s *Processors) ForDirection(dir Direction) Processor {
    57  	switch dir {
    58  	case ClientToServer:
    59  		return s.cToS
    60  	case ServerToClient:
    61  		return s.sToC
    62  	}
    63  	panic(fmt.Sprintf("invalid direction: %v", dir))
    64  }
    65  
    66  // Processor accepts the possible stream frames.
    67  //
    68  // This API abstracts away some of the lower level HTTP/2 mechanisms.
    69  // CONTINUATION frames are appropriately buffered and turned into Header calls and Header or
    70  // PushPromise calls are split into CONTINUATION frames when needed.
    71  //
    72  // The proxy handles WINDOW_UPDATE frames and flow control, managing it independently for both
    73  // endpoints.
    74  type Processor interface {
    75  	DataFrameProcessor
    76  	HeaderProcessor
    77  	PriorityFrameProcessor
    78  	RSTStreamProcessor
    79  	PushPromiseProcessor
    80  }
    81  
    82  // DataFrameProcessor processes data frames.
    83  type DataFrameProcessor interface {
    84  	Data(data []byte, streamEnded bool) error
    85  }
    86  
    87  // HeaderProcessor processes headers, abstracting out continuations.
    88  type HeaderProcessor interface {
    89  	Header(
    90  		headers []hpack.HeaderField,
    91  		streamEnded bool,
    92  		priority http2.PriorityParam,
    93  	) error
    94  }
    95  
    96  // PriorityFrameProcessor processes priority frames.
    97  type PriorityFrameProcessor interface {
    98  	Priority(http2.PriorityParam) error
    99  }
   100  
   101  // RSTStreamProcessor processes RSTStream frames.
   102  type RSTStreamProcessor interface {
   103  	RSTStream(http2.ErrCode) error
   104  }
   105  
   106  // PushPromiseProcessor processes push promises, abstracting out continuations.
   107  type PushPromiseProcessor interface {
   108  	PushPromise(promiseID uint32, headers []hpack.HeaderField) error
   109  }
   110  
   111  // relayAdapter implements the Processor interface by delegating to an underlying relay.
   112  type relayAdapter struct {
   113  	id    uint32
   114  	relay *relay
   115  }
   116  
   117  func (r *relayAdapter) Data(data []byte, streamEnded bool) error {
   118  	return r.relay.data(r.id, data, streamEnded)
   119  }
   120  
   121  func (r *relayAdapter) Header(
   122  	headers []hpack.HeaderField,
   123  	streamEnded bool,
   124  	priority http2.PriorityParam,
   125  ) error {
   126  	return r.relay.header(r.id, headers, streamEnded, priority)
   127  }
   128  
   129  func (r *relayAdapter) Priority(priority http2.PriorityParam) error {
   130  	r.relay.priority(r.id, priority)
   131  	return nil
   132  }
   133  
   134  func (r *relayAdapter) RSTStream(errCode http2.ErrCode) error {
   135  	r.relay.rstStream(r.id, errCode)
   136  	return nil
   137  }
   138  
   139  func (r *relayAdapter) PushPromise(promiseID uint32, headers []hpack.HeaderField) error {
   140  	return r.relay.pushPromise(r.id, promiseID, headers)
   141  }