mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-04-16 12:35:54 +00:00
1. **Fixed XPadding Placement Dropdown**: - Added the missing `cookie` and `query` options to `xPaddingPlacement` (`stream_xhttp.html`). - *Why:* Previously, users wanting `cookie` obfuscation were forced to use the `header` placement string. This caused Xray-core to blindly intercept the entire monolithic HTTP Cookie header, failing internal padding-length validations and causing the inbound to silently drop the connection. 2. **Fixed Uplink Data Placement Validation**: - Replaced the unsupported `query` option with `cookie` in `uplinkDataPlacement`. - *Why:* Xray-core's `transport_internet.go` explicitly forbids `query` as an uplink placement option. Selecting it from the UI previously sent a payload that would cause Xray-core to instantly throw an `unsupported uplink data placement: query` panic. Adding `cookie` perfectly aligns the UI with Xray-core restrictions. ### Related Issues - Resolves #3992
89 lines
2.2 KiB
Go
89 lines
2.2 KiB
Go
package cache
|
|
|
|
import (
|
|
"container/list"
|
|
"sync"
|
|
)
|
|
|
|
// Lru simple, fast lru cache implementation
|
|
type Lru interface {
|
|
Get(key interface{}) (value interface{}, ok bool)
|
|
GetKeyFromValue(value interface{}) (key interface{}, ok bool)
|
|
PeekKeyFromValue(value interface{}) (key interface{}, ok bool) // Peek means check but NOT bring to top
|
|
Put(key, value interface{})
|
|
}
|
|
|
|
type lru struct {
|
|
capacity int
|
|
doubleLinkedlist *list.List
|
|
keyToElement *sync.Map
|
|
valueToElement *sync.Map
|
|
mu *sync.Mutex
|
|
}
|
|
|
|
type lruElement struct {
|
|
key interface{}
|
|
value interface{}
|
|
}
|
|
|
|
// NewLru initializes a lru cache
|
|
func NewLru(cap int) Lru {
|
|
return &lru{
|
|
capacity: cap,
|
|
doubleLinkedlist: list.New(),
|
|
keyToElement: new(sync.Map),
|
|
valueToElement: new(sync.Map),
|
|
mu: new(sync.Mutex),
|
|
}
|
|
}
|
|
|
|
func (l *lru) Get(key interface{}) (value interface{}, ok bool) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
if v, ok := l.keyToElement.Load(key); ok {
|
|
element := v.(*list.Element)
|
|
l.doubleLinkedlist.MoveToFront(element)
|
|
return element.Value.(*lruElement).value, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (l *lru) GetKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
|
l.mu.Lock()
|
|
defer l.mu.Unlock()
|
|
if k, ok := l.valueToElement.Load(value); ok {
|
|
element := k.(*list.Element)
|
|
l.doubleLinkedlist.MoveToFront(element)
|
|
return element.Value.(*lruElement).key, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (l *lru) PeekKeyFromValue(value interface{}) (key interface{}, ok bool) {
|
|
if k, ok := l.valueToElement.Load(value); ok {
|
|
element := k.(*list.Element)
|
|
return element.Value.(*lruElement).key, true
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func (l *lru) Put(key, value interface{}) {
|
|
l.mu.Lock()
|
|
e := &lruElement{key, value}
|
|
if v, ok := l.keyToElement.Load(key); ok {
|
|
element := v.(*list.Element)
|
|
element.Value = e
|
|
l.doubleLinkedlist.MoveToFront(element)
|
|
} else {
|
|
element := l.doubleLinkedlist.PushFront(e)
|
|
l.keyToElement.Store(key, element)
|
|
l.valueToElement.Store(value, element)
|
|
if l.doubleLinkedlist.Len() > l.capacity {
|
|
toBeRemove := l.doubleLinkedlist.Back()
|
|
l.doubleLinkedlist.Remove(toBeRemove)
|
|
l.keyToElement.Delete(toBeRemove.Value.(*lruElement).key)
|
|
l.valueToElement.Delete(toBeRemove.Value.(*lruElement).value)
|
|
}
|
|
}
|
|
l.mu.Unlock()
|
|
}
|