mirror of
https://github.com/Gouryella/drip.git
synced 2026-02-26 22:31:35 +00:00
enhancements - Add adaptive HTTP response handling with automatic streaming for large responses (>1MB) - Implement zero-copy streaming using buffer pools for better performance - Add compression module for reduced bandwidth usage - Add GitHub Container Registry workflow for automated Docker builds - Add production-optimized Dockerfile and docker-compose configuration - Simplify background mode with -d flag and improved daemon management - Update documentation with new command syntax and deployment guides - Clean up unused code and improve error handling - Fix lipgloss style usage (remove unnecessary .Copy() calls)
125 lines
3.2 KiB
Go
125 lines
3.2 KiB
Go
package hpack
|
|
|
|
import (
|
|
"fmt"
|
|
)
|
|
|
|
// DynamicTable implements the HPACK dynamic table (RFC 7541 Section 2.3.2)
|
|
// The dynamic table is a FIFO queue where new entries are added at the beginning
|
|
// and old entries are evicted when the table size exceeds the maximum
|
|
type DynamicTable struct {
|
|
entries []HeaderField
|
|
size uint32 // Current size in bytes
|
|
maxSize uint32 // Maximum size in bytes
|
|
}
|
|
|
|
// HeaderField represents a header name-value pair
|
|
type HeaderField struct {
|
|
Name string
|
|
Value string
|
|
}
|
|
|
|
// Size returns the size of this header field in bytes
|
|
// RFC 7541: size = len(name) + len(value) + 32
|
|
func (h *HeaderField) Size() uint32 {
|
|
return uint32(len(h.Name) + len(h.Value) + 32)
|
|
}
|
|
|
|
// NewDynamicTable creates a new dynamic table with the specified maximum size
|
|
func NewDynamicTable(maxSize uint32) *DynamicTable {
|
|
return &DynamicTable{
|
|
entries: make([]HeaderField, 0, 32),
|
|
size: 0,
|
|
maxSize: maxSize,
|
|
}
|
|
}
|
|
|
|
// Add adds a header field to the dynamic table
|
|
// New entries are added at the beginning (index 0)
|
|
func (dt *DynamicTable) Add(name, value string) {
|
|
field := HeaderField{Name: name, Value: value}
|
|
fieldSize := field.Size()
|
|
|
|
// If the field is larger than maxSize, don't add it
|
|
if fieldSize > dt.maxSize {
|
|
dt.evictAll()
|
|
return
|
|
}
|
|
|
|
// Evict entries if necessary to make room
|
|
for dt.size+fieldSize > dt.maxSize && len(dt.entries) > 0 {
|
|
dt.evictOldest()
|
|
}
|
|
|
|
// Add new entry at the beginning
|
|
dt.entries = append([]HeaderField{field}, dt.entries...)
|
|
dt.size += fieldSize
|
|
}
|
|
|
|
// Get retrieves a header field by index (0-based)
|
|
// Index 0 is the most recently added entry
|
|
func (dt *DynamicTable) Get(index uint32) (string, string, error) {
|
|
if index >= uint32(len(dt.entries)) {
|
|
return "", "", fmt.Errorf("index %d out of range (table size: %d)", index, len(dt.entries))
|
|
}
|
|
|
|
field := dt.entries[index]
|
|
return field.Name, field.Value, nil
|
|
}
|
|
|
|
// FindExact searches for an exact match (name and value)
|
|
// Returns the index (0-based) and true if found
|
|
func (dt *DynamicTable) FindExact(name, value string) (uint32, bool) {
|
|
for i, field := range dt.entries {
|
|
if field.Name == name && field.Value == value {
|
|
return uint32(i), true
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// FindName searches for a name match
|
|
// Returns the index (0-based) and true if found
|
|
func (dt *DynamicTable) FindName(name string) (uint32, bool) {
|
|
for i, field := range dt.entries {
|
|
if field.Name == name {
|
|
return uint32(i), true
|
|
}
|
|
}
|
|
return 0, false
|
|
}
|
|
|
|
// SetMaxSize updates the maximum table size
|
|
// If the new size is smaller, entries are evicted
|
|
func (dt *DynamicTable) SetMaxSize(maxSize uint32) {
|
|
dt.maxSize = maxSize
|
|
|
|
// Evict entries if current size exceeds new max
|
|
for dt.size > dt.maxSize && len(dt.entries) > 0 {
|
|
dt.evictOldest()
|
|
}
|
|
}
|
|
|
|
// CurrentSize returns the current size of the table in bytes
|
|
func (dt *DynamicTable) CurrentSize() uint32 {
|
|
return dt.size
|
|
}
|
|
|
|
// evictOldest removes the oldest entry (last in the slice)
|
|
func (dt *DynamicTable) evictOldest() {
|
|
if len(dt.entries) == 0 {
|
|
return
|
|
}
|
|
|
|
lastIndex := len(dt.entries) - 1
|
|
evicted := dt.entries[lastIndex]
|
|
dt.entries = dt.entries[:lastIndex]
|
|
dt.size -= evicted.Size()
|
|
}
|
|
|
|
// evictAll removes all entries
|
|
func (dt *DynamicTable) evictAll() {
|
|
dt.entries = dt.entries[:0]
|
|
dt.size = 0
|
|
}
|