Update XHTTP

This commit is contained in:
Shtorm
2025-12-11 02:46:57 +03:00
parent 92beba066b
commit 0f38dbba4c
9 changed files with 94 additions and 43 deletions

View File

@@ -13,7 +13,7 @@ const (
Size = 8192 Size = 8192
) )
var zero = [Size * 10]byte{0} var ErrBufferFull = E.New("buffer is full")
var pool = bytespool.GetPool(Size) var pool = bytespool.GetPool(Size)
@@ -144,7 +144,7 @@ func (b *Buffer) Bytes() []byte {
} }
// Extend increases the buffer size by n bytes, and returns the extended part. // Extend increases the buffer size by n bytes, and returns the extended part.
// It panics if result size is larger than buf.Size. // It panics if result size is larger than size of this buffer.
func (b *Buffer) Extend(n int32) []byte { func (b *Buffer) Extend(n int32) []byte {
end := b.end + n end := b.end + n
if end > int32(len(b.v)) { if end > int32(len(b.v)) {
@@ -152,7 +152,7 @@ func (b *Buffer) Extend(n int32) []byte {
} }
ext := b.v[b.end:end] ext := b.v[b.end:end]
b.end = end b.end = end
copy(ext, zero[:]) clear(ext)
return ext return ext
} }
@@ -215,7 +215,7 @@ func (b *Buffer) Resize(from, to int32) {
b.start += from b.start += from
b.Check() b.Check()
if b.end > oldEnd { if b.end > oldEnd {
copy(b.v[oldEnd:b.end], zero[:]) clear(b.v[oldEnd:b.end])
} }
} }
@@ -244,6 +244,14 @@ func (b *Buffer) Cap() int32 {
return int32(len(b.v)) return int32(len(b.v))
} }
// Available returns the available capacity of the buffer content.
func (b *Buffer) Available() int32 {
if b == nil {
return 0
}
return int32(len(b.v)) - b.end
}
// IsEmpty returns true if the buffer is empty. // IsEmpty returns true if the buffer is empty.
func (b *Buffer) IsEmpty() bool { func (b *Buffer) IsEmpty() bool {
return b.Len() == 0 return b.Len() == 0
@@ -258,13 +266,16 @@ func (b *Buffer) IsFull() bool {
func (b *Buffer) Write(data []byte) (int, error) { func (b *Buffer) Write(data []byte) (int, error) {
nBytes := copy(b.v[b.end:], data) nBytes := copy(b.v[b.end:], data)
b.end += int32(nBytes) b.end += int32(nBytes)
if nBytes < len(data) {
return nBytes, ErrBufferFull
}
return nBytes, nil return nBytes, nil
} }
// WriteByte writes a single byte into the buffer. // WriteByte writes a single byte into the buffer.
func (b *Buffer) WriteByte(v byte) error { func (b *Buffer) WriteByte(v byte) error {
if b.IsFull() { if b.IsFull() {
return E.New("buffer full") return ErrBufferFull
} }
b.v[b.end] = v b.v[b.end] = v
b.end++ b.end++

View File

@@ -22,6 +22,7 @@ var ErrReadTimeout = E.New("IO timeout")
// TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout. // TimeoutReader is a reader that returns error if Read() operation takes longer than the given timeout.
type TimeoutReader interface { type TimeoutReader interface {
Reader
ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error) ReadMultiBufferTimeout(time.Duration) (MultiBuffer, error)
} }

View File

@@ -144,7 +144,7 @@ func Compact(mb MultiBuffer) MultiBuffer {
for i := 1; i < len(mb); i++ { for i := 1; i < len(mb); i++ {
curr := mb[i] curr := mb[i]
if last.Len()+curr.Len() > Size { if curr.Len() > last.Available() {
mb2 = append(mb2, last) mb2 = append(mb2, last)
last = curr last = curr
} else { } else {

View File

@@ -75,9 +75,10 @@ func (w *BufferToBytesWriter) ReadFrom(reader io.Reader) (int64, error) {
// BufferedWriter is a Writer with internal buffer. // BufferedWriter is a Writer with internal buffer.
type BufferedWriter struct { type BufferedWriter struct {
sync.Mutex sync.Mutex
writer Writer writer Writer
buffer *Buffer buffer *Buffer
buffered bool buffered bool
flushNext bool
} }
// NewBufferedWriter creates a new BufferedWriter. // NewBufferedWriter creates a new BufferedWriter.
@@ -161,6 +162,12 @@ func (w *BufferedWriter) WriteMultiBuffer(b MultiBuffer) error {
} }
} }
if w.flushNext {
w.buffered = false
w.flushNext = false
return w.flushInternal()
}
return nil return nil
} }
@@ -201,6 +208,13 @@ func (w *BufferedWriter) SetBuffered(f bool) error {
return nil return nil
} }
// SetFlushNext will wait the next WriteMultiBuffer to flush and set buffered = false
func (w *BufferedWriter) SetFlushNext() {
w.Lock()
defer w.Unlock()
w.flushNext = true
}
// ReadFrom implements io.ReaderFrom. // ReadFrom implements io.ReaderFrom.
func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) { func (w *BufferedWriter) ReadFrom(reader io.Reader) (int64, error) {
if err := w.SetBuffered(false); err != nil { if err := w.SetBuffered(false); err != nil {

View File

@@ -1,5 +1,7 @@
package common package common
import "reflect"
// Must panics if err is not nil. // Must panics if err is not nil.
func Must(err error) { func Must(err error) {
if err != nil { if err != nil {
@@ -17,3 +19,14 @@ func Must2(v interface{}, err error) interface{} {
func Error2(v interface{}, err error) error { func Error2(v interface{}, err error) error {
return err return err
} }
// CloseIfExists call obj.Close() if obj is not nil.
func CloseIfExists(obj any) error {
if obj != nil {
v := reflect.ValueOf(obj)
if !v.IsNil() {
return Close(obj)
}
}
return nil
}

View File

@@ -9,6 +9,9 @@ func RandBetween(from int64, to int64) int64 {
if from == to { if from == to {
return from return from
} }
if from > to {
from, to = to, from
}
bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from)) bigInt, _ := rand.Int(rand.Reader, big.NewInt(to-from))
return from + bigInt.Int64() return from + bigInt.Int64()
} }

View File

@@ -200,16 +200,19 @@ func (p *pipe) Interrupt() {
p.Lock() p.Lock()
defer p.Unlock() defer p.Unlock()
if !p.data.IsEmpty() {
buf.ReleaseMulti(p.data)
p.data = nil
if p.state == closed {
p.state = errord
}
}
if p.state == closed || p.state == errord { if p.state == closed || p.state == errord {
return return
} }
p.state = errord p.state = errord
if !p.data.IsEmpty() {
buf.ReleaseMulti(p.data)
p.data = nil
}
common.Must(p.done.Close()) common.Must(p.done.Close())
} }

View File

@@ -3,6 +3,7 @@ package signal
import ( import (
"context" "context"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/common/xray" "github.com/sagernet/sing-box/common/xray"
@@ -14,10 +15,12 @@ type ActivityUpdater interface {
} }
type ActivityTimer struct { type ActivityTimer struct {
sync.RWMutex mu sync.RWMutex
updated chan struct{} updated chan struct{}
checkTask *task.Periodic checkTask *task.Periodic
onTimeout func() onTimeout func()
consumed atomic.Bool
once sync.Once
} }
func (t *ActivityTimer) Update() { func (t *ActivityTimer) Update() {
@@ -37,39 +40,39 @@ func (t *ActivityTimer) check() error {
} }
func (t *ActivityTimer) finish() { func (t *ActivityTimer) finish() {
t.Lock() t.once.Do(func() {
defer t.Unlock() t.consumed.Store(true)
t.mu.Lock()
defer t.mu.Unlock()
if t.onTimeout != nil { common.CloseIfExists(t.checkTask)
t.onTimeout() t.onTimeout()
t.onTimeout = nil })
}
if t.checkTask != nil {
t.checkTask.Close()
t.checkTask = nil
}
} }
func (t *ActivityTimer) SetTimeout(timeout time.Duration) { func (t *ActivityTimer) SetTimeout(timeout time.Duration) {
if t.consumed.Load() {
return
}
if timeout == 0 { if timeout == 0 {
t.finish() t.finish()
return return
} }
checkTask := &task.Periodic{ t.mu.Lock()
defer t.mu.Unlock()
// double check, just in case
if t.consumed.Load() {
return
}
newCheckTask := &task.Periodic{
Interval: timeout, Interval: timeout,
Execute: t.check, Execute: t.check,
} }
common.CloseIfExists(t.checkTask)
t.Lock() t.checkTask = newCheckTask
if t.checkTask != nil {
t.checkTask.Close()
}
t.checkTask = checkTask
t.Unlock()
t.Update() t.Update()
common.Must(checkTask.Start()) common.Must(newCheckTask.Start())
} }
func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer { func CancelAfterInactivity(ctx context.Context, cancel context.CancelFunc, timeout time.Duration) *ActivityTimer {

View File

@@ -1,6 +1,7 @@
package xhttp package xhttp
import ( import (
common "github.com/sagernet/sing-box/common/xray"
"github.com/sagernet/sing-box/common/xray/buf" "github.com/sagernet/sing-box/common/xray/buf"
"github.com/sagernet/sing-box/common/xray/pipe" "github.com/sagernet/sing-box/common/xray/pipe"
) )
@@ -24,15 +25,17 @@ func (w uploadWriter) Write(b []byte) (int, error) {
b = b[:capacity] b = b[:capacity]
} }
*/ */
buffer := buf.New()
n, err := buffer.Write(b)
if err != nil {
return 0, err
}
err = w.WriteMultiBuffer([]*buf.Buffer{buffer}) buffer := buf.MultiBufferContainer{}
if err != nil { common.Must2(buffer.Write(b))
return 0, err
var writed int
for _, buff := range buffer.MultiBuffer {
err := w.WriteMultiBuffer(buf.MultiBuffer{buff})
if err != nil {
return writed, err
}
writed += int(buff.Len())
} }
return n, nil return writed, nil
} }