istio

Форк
0
/
util.go 
112 строк · 3.4 Кб
1
// Copyright Istio Authors
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 hbone
16

17
import (
18
	"io"
19
	"net"
20
	"net/http"
21
	"sync"
22
	"time"
23

24
	istiolog "istio.io/istio/pkg/log"
25
)
26

27
// createBuffer to get a buffer. io.Copy uses 32k.
28
// experimental use shows ~20k max read with Firefox.
29
var bufferPoolCopy = sync.Pool{New: func() any {
30
	return make([]byte, 0, 32*1024)
31
}}
32

33
func copyBuffered(dst io.Writer, src io.Reader, log *istiolog.Scope) {
34
	buf1 := bufferPoolCopy.Get().([]byte)
35
	// nolint: staticcheck
36
	defer bufferPoolCopy.Put(buf1)
37
	bufCap := cap(buf1)
38
	buf := buf1[0:bufCap:bufCap]
39

40
	// For netstack: src is a gonet.Conn, doesn't implement WriterTo. Dst is a net.TcpConn - and implements ReadFrom.
41
	// CopyBuffered is the actual implementation of Copy and CopyBuffer.
42
	// if buf is nil, one is allocated.
43
	// Duplicated from io
44

45
	// This will prevent stats from working.
46
	// If the reader has a WriteTo method, use it to do the copy.
47
	// Avoids an allocation and a copy.
48
	//if wt, ok := src.(io.WriterTo); ok {
49
	//	return wt.WriteTo(dst)
50
	//}
51
	// Similarly, if the writer has a ReadFrom method, use it to do the copy.
52
	//if rt, ok := dst.(io.ReaderFrom); ok {
53
	//	return rt.ReadFrom(src)
54
	//}
55
	for {
56
		if srcc, ok := src.(net.Conn); ok {
57
			// Best effort
58
			_ = srcc.SetReadDeadline(time.Now().Add(15 * time.Minute))
59
		}
60
		nr, err := src.Read(buf)
61
		log.Debugf("read %v/%v", nr, err)
62
		if nr > 0 { // before dealing with the read error
63
			nw, ew := dst.Write(buf[0:nr])
64
			log.Debugf("write %v/%v", nw, ew)
65
			if f, ok := dst.(http.Flusher); ok {
66
				f.Flush()
67
			}
68
			if nr != nw { // Should not happen
69
				ew = io.ErrShortWrite
70
			}
71
			if ew != nil {
72
				return
73
			}
74
		}
75
		if err != nil {
76
			// read is already closed - we need to close out
77
			_ = closeWriter(dst)
78
			return
79
		}
80
	}
81
}
82

83
// CloseWriter is one of possible interfaces implemented by Out to send a FIN, without closing
84
// the input. Some writers only do this when Close is called.
85
type CloseWriter interface {
86
	CloseWrite() error
87
}
88

89
func closeWriter(dst io.Writer) error {
90
	if cw, ok := dst.(CloseWriter); ok {
91
		return cw.CloseWrite()
92
	}
93
	if c, ok := dst.(io.Closer); ok {
94
		return c.Close()
95
	}
96
	if rw, ok := dst.(http.ResponseWriter); ok {
97
		// Server side HTTP stream. For client side, FIN can be sent by closing the pipe (or
98
		// request body). For server, the FIN will be sent when the handler returns - but
99
		// this only happen after request is completed and body has been read. If server wants
100
		// to send FIN first - while still reading the body - we are in trouble.
101

102
		// That means HTTP2 TCP servers provide no way to send a FIN from server, without
103
		// having the request fully read.
104

105
		// This works for H2 with the current library - but very tricky, if not set as trailer.
106
		rw.Header().Set("X-Close", "0")
107
		rw.(http.Flusher).Flush()
108
		return nil
109
	}
110
	log.Infof("Server out not Closer nor CloseWriter nor ResponseWriter: %v", dst)
111
	return nil
112
}
113

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.