mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-30 23:53:48 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			121 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			4.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2015 The Kubernetes 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 spdy
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"net"
 | |
| 	"net/http"
 | |
| 	"strings"
 | |
| 	"sync/atomic"
 | |
| 	"time"
 | |
| 
 | |
| 	"k8s.io/apimachinery/pkg/util/httpstream"
 | |
| 	"k8s.io/apimachinery/pkg/util/runtime"
 | |
| )
 | |
| 
 | |
| const HeaderSpdy31 = "SPDY/3.1"
 | |
| 
 | |
| // responseUpgrader knows how to upgrade HTTP responses. It
 | |
| // implements the httpstream.ResponseUpgrader interface.
 | |
| type responseUpgrader struct {
 | |
| 	pingPeriod time.Duration
 | |
| }
 | |
| 
 | |
| // connWrapper is used to wrap a hijacked connection and its bufio.Reader. All
 | |
| // calls will be handled directly by the underlying net.Conn with the exception
 | |
| // of Read and Close calls, which will consider data in the bufio.Reader. This
 | |
| // ensures that data already inside the used bufio.Reader instance is also
 | |
| // read.
 | |
| type connWrapper struct {
 | |
| 	net.Conn
 | |
| 	closed    int32
 | |
| 	bufReader *bufio.Reader
 | |
| }
 | |
| 
 | |
| func (w *connWrapper) Read(b []byte) (n int, err error) {
 | |
| 	if atomic.LoadInt32(&w.closed) == 1 {
 | |
| 		return 0, io.EOF
 | |
| 	}
 | |
| 	return w.bufReader.Read(b)
 | |
| }
 | |
| 
 | |
| func (w *connWrapper) Close() error {
 | |
| 	err := w.Conn.Close()
 | |
| 	atomic.StoreInt32(&w.closed, 1)
 | |
| 	return err
 | |
| }
 | |
| 
 | |
| // NewResponseUpgrader returns a new httpstream.ResponseUpgrader that is
 | |
| // capable of upgrading HTTP responses using SPDY/3.1 via the
 | |
| // spdystream package.
 | |
| func NewResponseUpgrader() httpstream.ResponseUpgrader {
 | |
| 	return NewResponseUpgraderWithPings(0)
 | |
| }
 | |
| 
 | |
| // NewResponseUpgraderWithPings returns a new httpstream.ResponseUpgrader that
 | |
| // is capable of upgrading HTTP responses using SPDY/3.1 via the spdystream
 | |
| // package.
 | |
| //
 | |
| // If pingPeriod is non-zero, for each incoming connection a background
 | |
| // goroutine will send periodic Ping frames to the server. Use this to keep
 | |
| // idle connections through certain load balancers alive longer.
 | |
| func NewResponseUpgraderWithPings(pingPeriod time.Duration) httpstream.ResponseUpgrader {
 | |
| 	return responseUpgrader{pingPeriod: pingPeriod}
 | |
| }
 | |
| 
 | |
| // UpgradeResponse upgrades an HTTP response to one that supports multiplexed
 | |
| // streams. newStreamHandler will be called synchronously whenever the
 | |
| // other end of the upgraded connection creates a new stream.
 | |
| func (u responseUpgrader) UpgradeResponse(w http.ResponseWriter, req *http.Request, newStreamHandler httpstream.NewStreamHandler) httpstream.Connection {
 | |
| 	connectionHeader := strings.ToLower(req.Header.Get(httpstream.HeaderConnection))
 | |
| 	upgradeHeader := strings.ToLower(req.Header.Get(httpstream.HeaderUpgrade))
 | |
| 	if !strings.Contains(connectionHeader, strings.ToLower(httpstream.HeaderUpgrade)) || !strings.Contains(upgradeHeader, strings.ToLower(HeaderSpdy31)) {
 | |
| 		errorMsg := fmt.Sprintf("unable to upgrade: missing upgrade headers in request: %#v", req.Header)
 | |
| 		http.Error(w, errorMsg, http.StatusBadRequest)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	hijacker, ok := w.(http.Hijacker)
 | |
| 	if !ok {
 | |
| 		errorMsg := "unable to upgrade: unable to hijack response"
 | |
| 		http.Error(w, errorMsg, http.StatusInternalServerError)
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	w.Header().Add(httpstream.HeaderConnection, httpstream.HeaderUpgrade)
 | |
| 	w.Header().Add(httpstream.HeaderUpgrade, HeaderSpdy31)
 | |
| 	w.WriteHeader(http.StatusSwitchingProtocols)
 | |
| 
 | |
| 	conn, bufrw, err := hijacker.Hijack()
 | |
| 	if err != nil {
 | |
| 		runtime.HandleError(fmt.Errorf("unable to upgrade: error hijacking response: %v", err))
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	connWithBuf := &connWrapper{Conn: conn, bufReader: bufrw.Reader}
 | |
| 	spdyConn, err := NewServerConnectionWithPings(connWithBuf, newStreamHandler, u.pingPeriod)
 | |
| 	if err != nil {
 | |
| 		runtime.HandleError(fmt.Errorf("unable to upgrade: error creating SPDY server connection: %v", err))
 | |
| 		return nil
 | |
| 	}
 | |
| 
 | |
| 	return spdyConn
 | |
| }
 | 
