diff options
Diffstat (limited to 'internal/ipc/ipc.go')
| -rw-r--r-- | internal/ipc/ipc.go | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/internal/ipc/ipc.go b/internal/ipc/ipc.go index 691dadf..f890715 100644 --- a/internal/ipc/ipc.go +++ b/internal/ipc/ipc.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "net" + "sync" "mitmux/internal/store" ) @@ -51,7 +52,15 @@ type EntryDetail struct { // Client talks to a mitmuxd instance for request/response queries // (list, get). Use Subscribe separately for the live-update stream. +// +// One request/response round trip is in flight on the connection at a +// time, guarded by mu - a caller like the mitmux TUI dispatches each +// request as its own goroutine (a Bubble Tea tea.Cmd), and without this +// two overlapping calls (e.g. opening two entries in quick succession) +// would interleave their JSON on the wire or hand one call the other's +// response. type Client struct { + mu sync.Mutex conn net.Conn dec *json.Decoder enc *json.Encoder @@ -84,6 +93,8 @@ func (c *Client) Search(query string, limit int, beforeID int64) ([]store.Summar } func (c *Client) list(req Request) ([]store.Summary, error) { + c.mu.Lock() + defer c.mu.Unlock() if err := c.enc.Encode(req); err != nil { return nil, err } @@ -99,6 +110,8 @@ func (c *Client) list(req Request) ([]store.Summary, error) { // Get returns the full entry (raw bytes included) for id. func (c *Client) Get(id int64) (*EntryDetail, error) { + c.mu.Lock() + defer c.mu.Unlock() if err := c.enc.Encode(Request{Type: "get", ID: id}); err != nil { return nil, err } @@ -116,6 +129,8 @@ func (c *Client) Get(id int64) (*EntryDetail, error) { // no header injection) and returns the resulting entry, including the raw // response bytes. The exchange is also recorded to history. func (c *Client) Repeat(scheme, host string, raw []byte) (*EntryDetail, error) { + c.mu.Lock() + defer c.mu.Unlock() if err := c.enc.Encode(Request{Type: "repeat", Scheme: scheme, Host: host, Raw: raw}); err != nil { return nil, err } |