diff options
| author | 2026-03-25 16:22:03 +0000 | |
|---|---|---|
| committer | 2026-03-25 16:22:03 +0000 | |
| commit | 311edcd50f3a84f4b860bde3cb887451d74eaa11 (patch) | |
| tree | be7aa5e9a51e636358f33b1c90637b5024b70dc3 /protocol/pktline | |
| parent | README: Split off contrib, benchmarks, remove history for now I guess, etc. (diff) | |
| signature | No signature | |
network/protocol: Rename from protocol v0.1.110
Diffstat (limited to 'protocol/pktline')
26 files changed, 0 insertions, 1182 deletions
diff --git a/protocol/pktline/append.go b/protocol/pktline/append.go deleted file mode 100644 index 9425e58e..00000000 --- a/protocol/pktline/append.go +++ /dev/null @@ -1,39 +0,0 @@ -package pktline - -import "fmt" - -// AppendData appends one data frame to dst. -// -// Empty payload is encoded as 0004. -func AppendData(dst, payload []byte) ([]byte, error) { - if len(payload) > LargePacketDataMax { - return dst, fmt.Errorf("%w: %d > %d", ErrTooLarge, len(payload), LargePacketDataMax) - } - - var hdr [4]byte - - err := EncodeLengthHeader(&hdr, len(payload)+4) - if err != nil { - return dst, err - } - - dst = append(dst, hdr[:]...) - dst = append(dst, payload...) - - return dst, nil -} - -// AppendFlushPkt appends control frame 0000 (flush-pkt). -func AppendFlushPkt(dst []byte) []byte { - return append(dst, '0', '0', '0', '0') -} - -// AppendDelimPkt appends control frame 0001 (delim-pkt). -func AppendDelimPkt(dst []byte) []byte { - return append(dst, '0', '0', '0', '1') -} - -// AppendResponseEndPkt appends control frame 0002 (response-end-pkt). -func AppendResponseEndPkt(dst []byte) []byte { - return append(dst, '0', '0', '0', '2') -} diff --git a/protocol/pktline/append_data_preserves_dst_on_error_test.go b/protocol/pktline/append_data_preserves_dst_on_error_test.go deleted file mode 100644 index 2888be16..00000000 --- a/protocol/pktline/append_data_preserves_dst_on_error_test.go +++ /dev/null @@ -1,25 +0,0 @@ -package pktline_test - -import ( - "bytes" - "errors" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestAppendDataPreservesDstOnError(t *testing.T) { - t.Parallel() - - orig := []byte("seed") - dst := append([]byte(nil), orig...) - - out, err := pktline.AppendData(dst, bytes.Repeat([]byte{'x'}, pktline.LargePacketDataMax+1)) - if !errors.Is(err, pktline.ErrTooLarge) { - t.Fatalf("got err %v, want ErrTooLarge", err) - } - - if !bytes.Equal(out, orig) { - t.Fatalf("got %q, want %q", string(out), string(orig)) - } -} diff --git a/protocol/pktline/append_helpers_test.go b/protocol/pktline/append_helpers_test.go deleted file mode 100644 index ae5f4748..00000000 --- a/protocol/pktline/append_helpers_test.go +++ /dev/null @@ -1,24 +0,0 @@ -package pktline_test - -import ( - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestAppendHelpers(t *testing.T) { - t.Parallel() - - out, err := pktline.AppendData(nil, []byte("ok")) - if err != nil { - t.Fatalf("AppendData: %v", err) - } - - out = pktline.AppendFlushPkt(out) - out = pktline.AppendDelimPkt(out) - out = pktline.AppendResponseEndPkt(out) - - if got, want := string(out), "0006ok000000010002"; got != want { - t.Fatalf("got %q, want %q", got, want) - } -} diff --git a/protocol/pktline/chunk_writer.go b/protocol/pktline/chunk_writer.go deleted file mode 100644 index b258ff20..00000000 --- a/protocol/pktline/chunk_writer.go +++ /dev/null @@ -1,65 +0,0 @@ -package pktline - -import "io" - -// ChunkWriter packetizes arbitrary stream bytes into data pkt-lines. -// It never writes control packets automatically. -type ChunkWriter struct { - enc *Encoder -} - -// NewChunkWriter creates a chunking adapter over enc. -func NewChunkWriter(enc *Encoder) *ChunkWriter { - return &ChunkWriter{enc: enc} -} - -// Write splits p into data frames not larger than enc's maxData. -// -// It implements io.Writer. -func (cw *ChunkWriter) Write(p []byte) (int, error) { - total := 0 - maxData := cw.enc.effectiveMaxData() - - for len(p) > 0 { - n := min(len(p), maxData) - - err := cw.enc.WriteData(p[:n]) - if err != nil { - return total, err - } - - total += n - p = p[n:] - } - - return total, nil -} - -// ReadFrom reads from r and writes pkt-line data frames to the encoder. -// -// It implements io.ReaderFrom. -func (cw *ChunkWriter) ReadFrom(r io.Reader) (int64, error) { - buf := make([]byte, cw.enc.effectiveMaxData()) - - var total int64 - - for { - n, err := r.Read(buf) - if n > 0 { - werr := cw.enc.WriteData(buf[:n]) - if werr != nil { - return total, werr - } - - total += int64(n) - } - - if err != nil { - if err == io.EOF { - return total, nil - } - - return total, err - } - } -} diff --git a/protocol/pktline/chunk_writer_write_and_read_from_test.go b/protocol/pktline/chunk_writer_write_and_read_from_test.go deleted file mode 100644 index f34aa754..00000000 --- a/protocol/pktline/chunk_writer_write_and_read_from_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package pktline_test - -import ( - "bufio" - "bytes" - "strings" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestChunkWriterWriteAndReadFrom(t *testing.T) { - t.Parallel() - - var out bytes.Buffer - - bw := bufio.NewWriter(&out) - - enc := pktline.NewEncoder(bw) - enc.SetMaxData(3) - cw := pktline.NewChunkWriter(enc) - - n, err := cw.Write([]byte("abcdefg")) - if err != nil { - t.Fatalf("Write: %v", err) - } - - if n != 7 { - t.Fatalf("Write n=%d, want 7", n) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - if got, want := out.String(), "0007abc0007def0005g"; got != want { - t.Fatalf("got %q, want %q", got, want) - } - - out.Reset() - - rn, err := cw.ReadFrom(strings.NewReader("wxyz")) - if err != nil { - t.Fatalf("ReadFrom: %v", err) - } - - if rn != 4 { - t.Fatalf("ReadFrom n=%d, want 4", rn) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - if got, want := out.String(), "0007wxy0005z"; got != want { - t.Fatalf("got %q, want %q", got, want) - } -} diff --git a/protocol/pktline/constants.go b/protocol/pktline/constants.go deleted file mode 100644 index 811eb3c6..00000000 --- a/protocol/pktline/constants.go +++ /dev/null @@ -1,12 +0,0 @@ -package pktline - -const ( - // DefaultPacketMax is a conservative packet size commonly used by - // line-oriented protocol messages. - DefaultPacketMax = 1000 - // LargePacketMax is the maximum on-wire packet size including the - // 4-byte hexadecimal length header. - LargePacketMax = 65520 - // LargePacketDataMax is the maximum payload size in one packet. - LargePacketDataMax = LargePacketMax - 4 -) diff --git a/protocol/pktline/decoder.go b/protocol/pktline/decoder.go deleted file mode 100644 index 898d8ad6..00000000 --- a/protocol/pktline/decoder.go +++ /dev/null @@ -1,187 +0,0 @@ -package pktline - -import ( - "errors" - "fmt" - "io" -) - -// ReadOptions controls decoding behavior. -type ReadOptions struct { - // ChompLF removes one trailing '\n' from PacketData payloads. - ChompLF bool -} - -// Decoder reads pkt-line frames from an io.Reader. -// -// It is advisable to supply a buffered reader. -// -// It preserves frame boundaries and supports one-frame lookahead via PeekFrame. -type Decoder struct { - r io.Reader - maxData int - opts ReadOptions - - peeked bool - peek Frame - peekErr error -} - -// NewDecoder creates a decoder over r. -func NewDecoder(r io.Reader, opts ReadOptions) *Decoder { - return &Decoder{ - r: r, - maxData: LargePacketDataMax, - opts: opts, - } -} - -// SetMaxData sets maximum payload size accepted for one data packet. -// -// Non-positive n resets to LargePacketDataMax. -func (d *Decoder) SetMaxData(n int) { - if n <= 0 { - d.maxData = LargePacketDataMax - - return - } - - d.maxData = n -} - -func cloneFrame(f Frame) Frame { - if f.Type != PacketData { - return Frame{Type: f.Type} - } - - out := Frame{Type: f.Type} - if f.Payload != nil { - out.Payload = append([]byte(nil), f.Payload...) - } - - return out -} - -// ReadFrame reads one frame. -// -// 0000 is a PacketFlush -// 0001 is a PacketDelim -// 0002 is a PacketResponseEnd -// 0004 is a PacketData with empty payload -// -// 0003 and malformed headers return *ProtocolError. -func (d *Decoder) ReadFrame() (Frame, error) { - if d.peeked { - d.peeked = false - - return cloneFrame(d.peek), d.peekErr - } - - return d.readFrame() -} - -// PeekFrame returns the next frame without consuming it. -// -// A subsequent ReadFrame returns the same frame. -func (d *Decoder) PeekFrame() (Frame, error) { - if !d.peeked { - d.peek, d.peekErr = d.readFrame() - d.peeked = true - } - - return cloneFrame(d.peek), d.peekErr -} - -func (d *Decoder) readFrame() (Frame, error) { - var hdr [4]byte - - _, err := io.ReadFull(d.r, hdr[:]) - if err != nil { - if errors.Is(err, io.EOF) { - return Frame{}, io.EOF - } - - if errors.Is(err, io.ErrUnexpectedEOF) { - return Frame{}, io.ErrUnexpectedEOF - } - - return Frame{}, err - } - - n, err := ParseLengthHeader(hdr) - if err != nil { - return Frame{}, &ProtocolError{Header: hdr, Reason: err.Error()} - } - - switch n { - case 0: - return Frame{Type: PacketFlush}, nil - case 1: - return Frame{Type: PacketDelim}, nil - case 2: - return Frame{Type: PacketResponseEnd}, nil - case 3: - return Frame{}, &ProtocolError{Header: hdr, Reason: "invalid pkt-line length 3"} - } - - if n < 4 { - return Frame{}, &ProtocolError{Header: hdr, Reason: fmt.Sprintf("invalid pkt-line length %d", n)} - } - - if n > LargePacketMax { - perr := &ProtocolError{Header: hdr, Reason: fmt.Sprintf("pkt-line length %d exceeds max %d", n, LargePacketMax)} - - err := d.discardPayload(n - 4) - if err != nil { - return Frame{}, errors.Join(perr, err) - } - - return Frame{}, perr - } - - payloadLen := n - 4 - if payloadLen > d.maxData { - serr := fmt.Errorf("%w: %d > %d", ErrTooLarge, payloadLen, d.maxData) - - err := d.discardPayload(payloadLen) - if err != nil { - return Frame{}, errors.Join(serr, err) - } - - return Frame{}, serr - } - - payload := make([]byte, payloadLen) - - _, err = io.ReadFull(d.r, payload) - if err != nil { - if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { - return Frame{}, io.ErrUnexpectedEOF - } - - return Frame{}, err - } - - if d.opts.ChompLF && len(payload) > 0 && payload[len(payload)-1] == '\n' { - payload = payload[:len(payload)-1] - } - - return Frame{Type: PacketData, Payload: payload}, nil -} - -func (d *Decoder) discardPayload(n int) error { - if n <= 0 { - return nil - } - - _, err := io.CopyN(io.Discard, d.r, int64(n)) - if err == nil { - return nil - } - - if errors.Is(err, io.EOF) || errors.Is(err, io.ErrUnexpectedEOF) { - return io.ErrUnexpectedEOF - } - - return err -} diff --git a/protocol/pktline/decoder_data_control_and_0004_test.go b/protocol/pktline/decoder_data_control_and_0004_test.go deleted file mode 100644 index 727e1063..00000000 --- a/protocol/pktline/decoder_data_control_and_0004_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package pktline_test - -import ( - "strings" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderDataControlAnd0004(t *testing.T) { - t.Parallel() - - input := "0006a\n0004000100020000" - dec := pktline.NewDecoder(strings.NewReader(input), pktline.ReadOptions{ChompLF: true}) - - f, err := dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #1: %v", err) - } - - if f.Type != pktline.PacketData || string(f.Payload) != "a" { - t.Fatalf("frame #1 = %#v", f) - } - - f, err = dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #2: %v", err) - } - - if f.Type != pktline.PacketData || len(f.Payload) != 0 { - t.Fatalf("frame #2 = %#v, want empty data", f) - } - - f, err = dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #3: %v", err) - } - - if f.Type != pktline.PacketDelim { - t.Fatalf("frame #3 type = %v, want PacketDelim", f.Type) - } - - f, err = dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #4: %v", err) - } - - if f.Type != pktline.PacketResponseEnd { - t.Fatalf("frame #4 type = %v, want PacketResponseEnd", f.Type) - } - - f, err = dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #5: %v", err) - } - - if f.Type != pktline.PacketFlush { - t.Fatalf("frame #5 type = %v, want PacketFlush", f.Type) - } -} diff --git a/protocol/pktline/decoder_invalid_0003_test.go b/protocol/pktline/decoder_invalid_0003_test.go deleted file mode 100644 index 9414d715..00000000 --- a/protocol/pktline/decoder_invalid_0003_test.go +++ /dev/null @@ -1,20 +0,0 @@ -package pktline_test - -import ( - "errors" - "strings" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderInvalid0003(t *testing.T) { - t.Parallel() - - dec := pktline.NewDecoder(strings.NewReader("0003"), pktline.ReadOptions{}) - _, err := dec.ReadFrame() - - if _, ok := errors.AsType[*pktline.ProtocolError](err); !ok { - t.Fatalf("got err %v, want ProtocolError", err) - } -} diff --git a/protocol/pktline/decoder_peek_test.go b/protocol/pktline/decoder_peek_test.go deleted file mode 100644 index 4b2fe2d9..00000000 --- a/protocol/pktline/decoder_peek_test.go +++ /dev/null @@ -1,32 +0,0 @@ -package pktline_test - -import ( - "strings" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderPeek(t *testing.T) { - t.Parallel() - - dec := pktline.NewDecoder(strings.NewReader("0005x0000"), pktline.ReadOptions{}) - - f, err := dec.PeekFrame() - if err != nil { - t.Fatalf("PeekFrame: %v", err) - } - - if f.Type != pktline.PacketData || string(f.Payload) != "x" { - t.Fatalf("peek frame = %#v", f) - } - - f, err = dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame: %v", err) - } - - if f.Type != pktline.PacketData || string(f.Payload) != "x" { - t.Fatalf("read frame = %#v", f) - } -} diff --git a/protocol/pktline/decoder_rejects_over_maximum_length_test.go b/protocol/pktline/decoder_rejects_over_maximum_length_test.go deleted file mode 100644 index 67dd5053..00000000 --- a/protocol/pktline/decoder_rejects_over_maximum_length_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package pktline_test - -import ( - "errors" - "strings" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderRejectsOverMaximumLength(t *testing.T) { - t.Parallel() - - dec := pktline.NewDecoder(strings.NewReader("fffe"), pktline.ReadOptions{}) - dec.SetMaxData(70000) - - _, err := dec.ReadFrame() - - if _, ok := errors.AsType[*pktline.ProtocolError](err); !ok { - t.Fatalf("got err %v, want ProtocolError", err) - } -} diff --git a/protocol/pktline/decoder_resync_after_over_max_data_test.go b/protocol/pktline/decoder_resync_after_over_max_data_test.go deleted file mode 100644 index 798ca91f..00000000 --- a/protocol/pktline/decoder_resync_after_over_max_data_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package pktline_test - -import ( - "bufio" - "bytes" - "errors" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderResyncAfterOverMaxData(t *testing.T) { - t.Parallel() - - var b bytes.Buffer - - bw := bufio.NewWriter(&b) - enc := pktline.NewEncoder(bw) - - err := enc.WriteData([]byte("abcd")) - if err != nil { - t.Fatalf("WriteData #1: %v", err) - } - - err = enc.WriteData([]byte("z")) - if err != nil { - t.Fatalf("WriteData #2: %v", err) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - dec := pktline.NewDecoder(bytes.NewReader(b.Bytes()), pktline.ReadOptions{}) - dec.SetMaxData(1) - - _, err = dec.ReadFrame() - if !errors.Is(err, pktline.ErrTooLarge) { - t.Fatalf("got err %v, want ErrTooLarge", err) - } - - f, err := dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #2: %v", err) - } - - if f.Type != pktline.PacketData || string(f.Payload) != "z" { - t.Fatalf("got frame %#v, want data z", f) - } -} diff --git a/protocol/pktline/decoder_resync_after_over_wire_max_test.go b/protocol/pktline/decoder_resync_after_over_wire_max_test.go deleted file mode 100644 index 3ba98d62..00000000 --- a/protocol/pktline/decoder_resync_after_over_wire_max_test.go +++ /dev/null @@ -1,37 +0,0 @@ -package pktline_test - -import ( - "bytes" - "errors" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderResyncAfterOverWireMax(t *testing.T) { - t.Parallel() - - var b bytes.Buffer - - _, _ = b.WriteString("ffff") - _, _ = b.Write(bytes.Repeat([]byte{'a'}, 65531)) - _, _ = b.WriteString("0005z") - - dec := pktline.NewDecoder(bytes.NewReader(b.Bytes()), pktline.ReadOptions{}) - dec.SetMaxData(70000) - - _, err := dec.ReadFrame() - - if _, ok := errors.AsType[*pktline.ProtocolError](err); !ok { - t.Fatalf("got err %v, want ProtocolError", err) - } - - f, err := dec.ReadFrame() - if err != nil { - t.Fatalf("ReadFrame #2: %v", err) - } - - if f.Type != pktline.PacketData || string(f.Payload) != "z" { - t.Fatalf("got frame %#v, want data z", f) - } -} diff --git a/protocol/pktline/decoder_unexpected_eof_test.go b/protocol/pktline/decoder_unexpected_eof_test.go deleted file mode 100644 index b86b5540..00000000 --- a/protocol/pktline/decoder_unexpected_eof_test.go +++ /dev/null @@ -1,21 +0,0 @@ -package pktline_test - -import ( - "errors" - "io" - "strings" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestDecoderUnexpectedEOF(t *testing.T) { - t.Parallel() - - dec := pktline.NewDecoder(strings.NewReader("0006a"), pktline.ReadOptions{}) - - _, err := dec.ReadFrame() - if !errors.Is(err, io.ErrUnexpectedEOF) { - t.Fatalf("got err %v, want io.ErrUnexpectedEOF", err) - } -} diff --git a/protocol/pktline/doc.go b/protocol/pktline/doc.go deleted file mode 100644 index 3f7cca89..00000000 --- a/protocol/pktline/doc.go +++ /dev/null @@ -1,2 +0,0 @@ -// Package pktline implements the pkt-line format specified in gitprotocol-common(5). -package pktline diff --git a/protocol/pktline/encode_length_header_test.go b/protocol/pktline/encode_length_header_test.go deleted file mode 100644 index 5ad76daf..00000000 --- a/protocol/pktline/encode_length_header_test.go +++ /dev/null @@ -1,28 +0,0 @@ -package pktline_test - -import ( - "errors" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestEncodeLengthHeader(t *testing.T) { - t.Parallel() - - var hdr [4]byte - - err := pktline.EncodeLengthHeader(&hdr, 4) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if got := string(hdr[:]); got != "0004" { - t.Fatalf("got %q, want %q", got, "0004") - } - - err = pktline.EncodeLengthHeader(&hdr, pktline.LargePacketMax+1) - if !errors.Is(err, pktline.ErrInvalidLength) { - t.Fatalf("got err %v, want ErrInvalidLength", err) - } -} diff --git a/protocol/pktline/encoder.go b/protocol/pktline/encoder.go deleted file mode 100644 index b4c6dbf0..00000000 --- a/protocol/pktline/encoder.go +++ /dev/null @@ -1,145 +0,0 @@ -package pktline - -import ( - "fmt" - "io" -) - -// WriteFlusher is the output transport contract required by Encoder. -// -// Write emits framed bytes and Flush pushes buffered transport state. -type WriteFlusher interface { - io.Writer - Flush() error -} - -// Encoder writes pkt-line frames to a flush-capable output transport. -// -// It writes exactly one frame per method call and does not auto-chunk data. -type Encoder struct { - w WriteFlusher - maxData int -} - -// NewEncoder creates an encoder over w. -func NewEncoder(w WriteFlusher) *Encoder { - return &Encoder{ - w: w, - maxData: LargePacketDataMax, - } -} - -// SetMaxData sets the maximum payload size accepted by WriteData. -// -// Non-positive n resets to LargePacketDataMax. -func (e *Encoder) SetMaxData(n int) { - if n <= 0 { - e.maxData = LargePacketDataMax - - return - } - - e.maxData = n -} - -func writeAll(w io.Writer, b []byte) error { - for len(b) > 0 { - n, err := w.Write(b) - if err != nil { - return err - } - - if n <= 0 { - return io.ErrShortWrite - } - - b = b[n:] - } - - return nil -} - -// WriteData writes one data frame. -// -// Empty payload is encoded as 0004. -func (e *Encoder) WriteData(p []byte) error { - maxData := e.effectiveMaxData() - if len(p) > maxData { - return fmt.Errorf("%w: %d > %d", ErrTooLarge, len(p), maxData) - } - - var hdr [4]byte - - err := EncodeLengthHeader(&hdr, len(p)+4) - if err != nil { - return err - } - - err = writeAll(e.w, hdr[:]) - if err != nil { - return err - } - - return writeAll(e.w, p) -} - -// WriteString writes one data frame containing s and returns len(s) on success. -func (e *Encoder) WriteString(s string) (int, error) { - err := e.WriteData([]byte(s)) - if err != nil { - return 0, err - } - - return len(s), nil -} - -// WriteFlush writes control frame 0000 (flush-pkt). -func (e *Encoder) WriteFlush() error { - return e.writeControl(0) -} - -// WriteDelim writes control frame 0001 (delim-pkt). -func (e *Encoder) WriteDelim() error { - return e.writeControl(1) -} - -// WriteResponseEnd writes control frame 0002 (response-end-pkt). -func (e *Encoder) WriteResponseEnd() error { - return e.writeControl(2) -} - -// FlushIO flushes buffered output in the underlying transport. -// -// FlushIO does not emit any pkt-line control frame. -func (e *Encoder) FlushIO() error { - return e.w.Flush() -} - -// WriteFlushAndFlushIO writes a flush-pkt (0000) then flushes transport I/O. -func (e *Encoder) WriteFlushAndFlushIO() error { - err := e.WriteFlush() - if err != nil { - return err - } - - return e.FlushIO() -} - -func (e *Encoder) writeControl(n int) error { - var hdr [4]byte - - err := EncodeLengthHeader(&hdr, n) - if err != nil { - return err - } - - return writeAll(e.w, hdr[:]) -} - -func (e *Encoder) effectiveMaxData() int { - if e.maxData <= 0 || e.maxData > LargePacketDataMax { - return LargePacketDataMax - } - - return e.maxData -} diff --git a/protocol/pktline/encoder_buffered_flush_and_f_flush_test.go b/protocol/pktline/encoder_buffered_flush_and_f_flush_test.go deleted file mode 100644 index 395d7310..00000000 --- a/protocol/pktline/encoder_buffered_flush_and_f_flush_test.go +++ /dev/null @@ -1,50 +0,0 @@ -package pktline_test - -import ( - "bufio" - "bytes" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestEncoderBufferedFlushAndFFlush(t *testing.T) { - t.Parallel() - - var out bytes.Buffer - - bw := bufio.NewWriter(&out) - enc := pktline.NewEncoder(bw) - - err := enc.WriteData([]byte("x")) - if err != nil { - t.Fatalf("WriteData: %v", err) - } - - if out.Len() != 0 { - t.Fatalf("unexpected immediate output: %q", out.String()) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - if out.String() != "0005x" { - t.Fatalf("got %q, want %q", out.String(), "0005x") - } - - out.Reset() - bw = bufio.NewWriter(&out) - - enc = pktline.NewEncoder(bw) - - err = enc.WriteFlushAndFlushIO() - if err != nil { - t.Fatalf("WriteFlushAndFlushIO: %v", err) - } - - if out.String() != "0000" { - t.Fatalf("got %q, want %q", out.String(), "0000") - } -} diff --git a/protocol/pktline/encoder_buffered_flush_behavior_test.go b/protocol/pktline/encoder_buffered_flush_behavior_test.go deleted file mode 100644 index 89ae5fcf..00000000 --- a/protocol/pktline/encoder_buffered_flush_behavior_test.go +++ /dev/null @@ -1,86 +0,0 @@ -package pktline_test - -import ( - "bufio" - "bytes" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestEncoderBufferedFlushBehavior(t *testing.T) { - t.Parallel() - - var out bytes.Buffer - - bw := bufio.NewWriter(&out) - enc := pktline.NewEncoder(bw) - - err := enc.WriteData([]byte("hello")) - if err != nil { - t.Fatalf("WriteData: %v", err) - } - - err = enc.WriteFlush() - if err != nil { - t.Fatalf("WriteFlush: %v", err) - } - - if out.Len() != 0 { - t.Fatalf("WriteFlush should not flush I/O, got %q", out.String()) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - if got, want := out.String(), "0009hello0000"; got != want { - t.Fatalf("got %q, want %q", got, want) - } - - out.Reset() - bw = bufio.NewWriter(&out) - enc = pktline.NewEncoder(bw) - - err = enc.WriteData([]byte("ok")) - if err != nil { - t.Fatalf("WriteData: %v", err) - } - - err = enc.WriteFlush() - if err != nil { - t.Fatalf("WriteFlush: %v", err) - } - - if out.Len() != 0 { - t.Fatalf("WriteFlush should not flush I/O, got %q", out.String()) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - if got, want := out.String(), "0006ok0000"; got != want { - t.Fatalf("got %q, want %q", got, want) - } - - out.Reset() - bw = bufio.NewWriter(&out) - enc = pktline.NewEncoder(bw) - - err = enc.WriteData([]byte("yo")) - if err != nil { - t.Fatalf("WriteData: %v", err) - } - - err = enc.WriteFlushAndFlushIO() - if err != nil { - t.Fatalf("WriteFlushAndFlushIO: %v", err) - } - - if got, want := out.String(), "0006yo0000"; got != want { - t.Fatalf("got %q, want %q", got, want) - } -} diff --git a/protocol/pktline/encoder_set_max_data_cannot_exceed_wire_limit_test.go b/protocol/pktline/encoder_set_max_data_cannot_exceed_wire_limit_test.go deleted file mode 100644 index c4c4f5c9..00000000 --- a/protocol/pktline/encoder_set_max_data_cannot_exceed_wire_limit_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package pktline_test - -import ( - "bufio" - "bytes" - "errors" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestEncoderSetMaxDataCannotExceedWireLimit(t *testing.T) { - t.Parallel() - - var out bytes.Buffer - - bw := bufio.NewWriter(&out) - - enc := pktline.NewEncoder(bw) - enc.SetMaxData(pktline.LargePacketDataMax + 100) - - err := enc.WriteData(bytes.Repeat([]byte{'x'}, pktline.LargePacketDataMax+1)) - if !errors.Is(err, pktline.ErrTooLarge) { - t.Fatalf("got err %v, want ErrTooLarge", err) - } -} diff --git a/protocol/pktline/encoder_writes_frames_test.go b/protocol/pktline/encoder_writes_frames_test.go deleted file mode 100644 index 2a595730..00000000 --- a/protocol/pktline/encoder_writes_frames_test.go +++ /dev/null @@ -1,51 +0,0 @@ -package pktline_test - -import ( - "bufio" - "bytes" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestEncoderWritesFrames(t *testing.T) { - t.Parallel() - - var b bytes.Buffer - - bw := bufio.NewWriter(&b) - - enc := pktline.NewEncoder(bw) - - err := enc.WriteData([]byte("hi")) - if err != nil { - t.Fatalf("WriteData: %v", err) - } - - err = enc.WriteFlush() - if err != nil { - t.Fatalf("WriteFlush: %v", err) - } - - err = enc.WriteDelim() - if err != nil { - t.Fatalf("WriteDelim: %v", err) - } - - err = enc.WriteResponseEnd() - if err != nil { - t.Fatalf("WriteResponseEnd: %v", err) - } - - err = enc.FlushIO() - if err != nil { - t.Fatalf("FlushIO: %v", err) - } - - got := b.String() - - want := "0006hi000000010002" - if got != want { - t.Fatalf("got %q, want %q", got, want) - } -} diff --git a/protocol/pktline/errors.go b/protocol/pktline/errors.go deleted file mode 100644 index 866ff467..00000000 --- a/protocol/pktline/errors.go +++ /dev/null @@ -1,31 +0,0 @@ -package pktline - -import "errors" - -var ( - // ErrInvalidLength indicates a malformed 4-byte hexadecimal length header. - ErrInvalidLength = errors.New("pktline: invalid length header") - // ErrTooLarge indicates a payload exceeds configured packet data limits. - ErrTooLarge = errors.New("pktline: payload too large") -) - -// ProtocolError reports invalid pkt-line framing. -// -// It is returned for protocol violations such as invalid control values -// (for example 0003) or non-hex length headers. -type ProtocolError struct { - Header [4]byte - Reason string -} - -func (e *ProtocolError) Error() string { - if e == nil { - return "<nil>" - } - - if e.Reason == "" { - return "pktline: protocol error" - } - - return "pktline: protocol error: " + e.Reason -} diff --git a/protocol/pktline/frame.go b/protocol/pktline/frame.go deleted file mode 100644 index a1cf708c..00000000 --- a/protocol/pktline/frame.go +++ /dev/null @@ -1,10 +0,0 @@ -package pktline - -// Frame is one decoded pkt-line frame. -// -// For PacketData, Payload holds frame bytes (possibly empty for 0004). -// For control frames, Payload is nil. -type Frame struct { - Type PacketType - Payload []byte -} diff --git a/protocol/pktline/header.go b/protocol/pktline/header.go deleted file mode 100644 index 41e50e04..00000000 --- a/protocol/pktline/header.go +++ /dev/null @@ -1,57 +0,0 @@ -package pktline - -import "fmt" - -func hexval(b byte) int { - switch { - case b >= '0' && b <= '9': - return int(b - '0') - case b >= 'a' && b <= 'f': - return int(b-'a') + 10 - case b >= 'A' && b <= 'F': - return int(b-'A') + 10 - default: - return -1 - } -} - -// ParseLengthHeader parses a 4-byte hexadecimal pkt-line length header. -// -// The returned value is the full on-wire packet size, including the 4-byte -// header. Semantic interpretation (data/control/error) is done by Decoder. -// -// The 4-byte header is only an actual length when above or equal to 4. -// Otherwise, it indicates some control packet. -func ParseLengthHeader(h [4]byte) (int, error) { - a := hexval(h[0]) - b := hexval(h[1]) - c := hexval(h[2]) - d := hexval(h[3]) - - if a < 0 || b < 0 || c < 0 || d < 0 { - return 0, fmt.Errorf("%w: %q", ErrInvalidLength, string(h[:])) - } - - return (a << 12) | (b << 8) | (c << 4) | d, nil -} - -// EncodeLengthHeader encodes n as a 4-byte hexadecimal pkt-line header. -// -// n is the full on-wire packet size including the 4-byte header. -// -// The 4-byte header is only an actual length when above or equal to 4. -// Otherwise, it indicates some control packet. -func EncodeLengthHeader(dst *[4]byte, n int) error { - if n < 0 || n > LargePacketMax { - return fmt.Errorf("%w: %d", ErrInvalidLength, n) - } - - const hex = "0123456789abcdef" - - dst[0] = hex[(n>>12)&0xf] - dst[1] = hex[(n>>8)&0xf] - dst[2] = hex[(n>>4)&0xf] - dst[3] = hex[n&0xf] - - return nil -} diff --git a/protocol/pktline/parse_length_header_test.go b/protocol/pktline/parse_length_header_test.go deleted file mode 100644 index 4bc743dd..00000000 --- a/protocol/pktline/parse_length_header_test.go +++ /dev/null @@ -1,26 +0,0 @@ -package pktline_test - -import ( - "errors" - "testing" - - "codeberg.org/lindenii/furgit/protocol/pktline" -) - -func TestParseLengthHeader(t *testing.T) { - t.Parallel() - - n, err := pktline.ParseLengthHeader([4]byte{'0', '0', '0', '4'}) - if err != nil { - t.Fatalf("unexpected error: %v", err) - } - - if n != 4 { - t.Fatalf("got %d, want 4", n) - } - - _, err = pktline.ParseLengthHeader([4]byte{'0', '0', '0', 'x'}) - if !errors.Is(err, pktline.ErrInvalidLength) { - t.Fatalf("got err %v, want ErrInvalidLength", err) - } -} diff --git a/protocol/pktline/type.go b/protocol/pktline/type.go deleted file mode 100644 index 641d1c6c..00000000 --- a/protocol/pktline/type.go +++ /dev/null @@ -1,15 +0,0 @@ -package pktline - -// PacketType identifies the kind of pkt-line frame. -type PacketType uint8 - -const ( - // PacketData is a regular data frame whose payload is application-defined. - PacketData PacketType = iota - // PacketFlush is control frame 0000 and marks end of a message. - PacketFlush - // PacketDelim is control frame 0001 and separates sections in protocol v2. - PacketDelim - // PacketResponseEnd is control frame 0002 and marks response end on stateless v2 transports. - PacketResponseEnd -) |
