77 lines
2.8 KiB
Go
77 lines
2.8 KiB
Go
package proxy
|
|
|
|
import (
|
|
"net/http"
|
|
"sync"
|
|
"time"
|
|
)
|
|
|
|
// Entry — одна перехваченная транзакция запрос/ответ, готовая к показу
|
|
// в TUI и (по Raw) к загрузке прямо в Request Builder.
|
|
type Entry struct {
|
|
ID int
|
|
Timestamp time.Time
|
|
Method string
|
|
URL string
|
|
Raw string // сырой HTTP-запрос целиком — то, что вставляется в §маркеры§ форму
|
|
StatusCode int
|
|
Length int64
|
|
Headers http.Header // заголовки ответа — для цветовой маркировки по Content-Type в TUI
|
|
ResponseBody string // тело ответа, обрезанное до maxResponseCapture байт — для полнотекстового поиска в Project
|
|
Err error // не nil, если запрос не удалось выполнить (таймаут, обрыв соединения и т.п.)
|
|
}
|
|
|
|
// Store хранит историю перехваченных запросов и рассылает новые записи
|
|
// подписчикам (обычно единственный подписчик — TUI) через каналы.
|
|
type Store struct {
|
|
mu sync.Mutex
|
|
entries []Entry
|
|
nextID int
|
|
subs []chan Entry
|
|
}
|
|
|
|
// NewStore создаёт пустое хранилище.
|
|
func NewStore() *Store {
|
|
return &Store{}
|
|
}
|
|
|
|
// Add сохраняет запись, присваивает ей ID и рассылает подписчикам.
|
|
// Рассылка неблокирующая: если подписчик не успевает вычитывать канал,
|
|
// запись всё равно остаётся в общей истории (доступна через All),
|
|
// прокси-сервер из-за медленного TUI не подвиснет.
|
|
func (s *Store) Add(e Entry) Entry {
|
|
s.mu.Lock()
|
|
s.nextID++
|
|
e.ID = s.nextID
|
|
s.entries = append(s.entries, e)
|
|
subs := append([]chan Entry(nil), s.subs...)
|
|
s.mu.Unlock()
|
|
|
|
for _, ch := range subs {
|
|
select {
|
|
case ch <- e:
|
|
default:
|
|
}
|
|
}
|
|
return e
|
|
}
|
|
|
|
// All возвращает копию текущей истории — используется для первичной
|
|
// загрузки TUI при старте, если прокси уже что-то успел перехватить.
|
|
func (s *Store) All() []Entry {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
out := make([]Entry, len(s.entries))
|
|
copy(out, s.entries)
|
|
return out
|
|
}
|
|
|
|
// Subscribe возвращает канал, в который будут падать все новые записи,
|
|
// добавленные после момента подписки.
|
|
func (s *Store) Subscribe() <-chan Entry {
|
|
ch := make(chan Entry, 64)
|
|
s.mu.Lock()
|
|
s.subs = append(s.subs, ch)
|
|
s.mu.Unlock()
|
|
return ch
|
|
}
|