mirror of
https://github.com/seaweedfs/seaweedfs.git
synced 2026-10-09 07:47:54 +02:00
* image: add an optional public image processing gateway * image: fix representation metadata and processing bounds * image: restrict passthrough to non-executable media types Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * image: tighten source media-type validation Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * image: write passthrough body on the inner response writer CodeQL still flagged the passthrough write: the content type was set on the wrapper while the body reached w.ResponseWriter, so the validated header could not be associated with the write. Set headers and copy the body on the same inner writer. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * image: serve processed output on the inner response writer * image: reject XML source types and unsafe conditional metadata --------- Co-authored-by: zhaoyuchen <yc.zhao@yinzon.com> Co-authored-by: Chris Lu <chrislusf@users.noreply.github.com> Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
66 lines
1.6 KiB
Go
66 lines
1.6 KiB
Go
package gateway
|
|
|
|
import (
|
|
"container/list"
|
|
"sync"
|
|
)
|
|
|
|
type result struct {
|
|
data []byte
|
|
contentType, etag string
|
|
}
|
|
|
|
type cacheEntry struct {
|
|
key string
|
|
value *result
|
|
size int64
|
|
}
|
|
|
|
// cache is a byte-bounded LRU with an entry limit to bound metadata for small objects.
|
|
type cache struct {
|
|
mu sync.Mutex
|
|
entries map[string]*list.Element
|
|
order *list.List
|
|
capacity, used int64
|
|
}
|
|
|
|
// newCache creates a disposable in-process cache without creating storage objects.
|
|
func newCache(capacity int64) *cache {
|
|
return &cache{entries: make(map[string]*list.Element), order: list.New(), capacity: capacity}
|
|
}
|
|
|
|
// get returns immutable results and updates recency.
|
|
func (c *cache) get(key string) *result {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
if e := c.entries[key]; e != nil {
|
|
c.order.MoveToFront(e)
|
|
return e.Value.(*cacheEntry).value
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// put accounts for data and index overhead, skipping results larger than capacity.
|
|
func (c *cache) put(key string, value *result) {
|
|
c.mu.Lock()
|
|
defer c.mu.Unlock()
|
|
size := int64(len(key) + len(value.data) + len(value.contentType) + len(value.etag) + 128)
|
|
if c.capacity == 0 || size > c.capacity {
|
|
return
|
|
}
|
|
if old := c.entries[key]; old != nil {
|
|
c.used -= old.Value.(*cacheEntry).size
|
|
c.order.Remove(old)
|
|
delete(c.entries, key)
|
|
}
|
|
for c.used+size > c.capacity || len(c.entries) >= 1024 {
|
|
old := c.order.Back()
|
|
entry := old.Value.(*cacheEntry)
|
|
delete(c.entries, entry.key)
|
|
c.used -= entry.size
|
|
c.order.Remove(old)
|
|
}
|
|
c.entries[key] = c.order.PushFront(&cacheEntry{key: key, value: value, size: size})
|
|
c.used += size
|
|
}
|