mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-11-04 01:53:42 +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
 | 
						|
}
 |