loading up the forgejo repo on tangled to test page performance
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request '[REFACTOR] PKT protocol' (#2868) from gusted/forgejo-refactor-pkt into forgejo

Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/2868
Reviewed-by: Earl Warren <earl-warren@noreply.codeberg.org>

+93 -52
+24 -30
cmd/hook.go
··· 606 606 607 607 for { 608 608 // note: pktLineTypeUnknow means pktLineTypeFlush and pktLineTypeData all allowed 609 - rs, err = readPktLine(ctx, reader, pktLineTypeUnknow) 609 + rs, err = readPktLine(ctx, reader, pktLineTypeUnknown) 610 610 if err != nil { 611 611 return err 612 612 } ··· 627 627 628 628 if hasPushOptions { 629 629 for { 630 - rs, err = readPktLine(ctx, reader, pktLineTypeUnknow) 630 + rs, err = readPktLine(ctx, reader, pktLineTypeUnknown) 631 631 if err != nil { 632 632 return err 633 633 } ··· 722 722 type pktLineType int64 723 723 724 724 const ( 725 - // UnKnow type 726 - pktLineTypeUnknow pktLineType = 0 725 + // Unknown type 726 + pktLineTypeUnknown pktLineType = 0 727 727 // flush-pkt "0000" 728 728 pktLineTypeFlush pktLineType = iota 729 729 // data line ··· 737 737 Data []byte 738 738 } 739 739 740 + // Reads an Pkt-Line from `in`. If requestType is not unknown, it will a 740 741 func readPktLine(ctx context.Context, in *bufio.Reader, requestType pktLineType) (*gitPktLine, error) { 741 - var ( 742 - err error 743 - r *gitPktLine 744 - ) 745 - 746 - // read prefix 742 + // Read length prefix 747 743 lengthBytes := make([]byte, 4) 748 - for i := 0; i < 4; i++ { 749 - lengthBytes[i], err = in.ReadByte() 750 - if err != nil { 751 - return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err) 752 - } 744 + if n, err := in.Read(lengthBytes); n != 4 || err != nil { 745 + return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err) 753 746 } 754 747 755 - r = new(gitPktLine) 748 + var err error 749 + r := &gitPktLine{} 756 750 r.Length, err = strconv.ParseUint(string(lengthBytes), 16, 32) 757 751 if err != nil { 758 752 return nil, fail(ctx, "Protocol: format parse error", "Pkt-Line format is wrong :%v", err) ··· 771 765 } 772 766 773 767 r.Data = make([]byte, r.Length-4) 774 - for i := range r.Data { 775 - r.Data[i], err = in.ReadByte() 776 - if err != nil { 777 - return nil, fail(ctx, "Protocol: data error", "Pkt-Line: read stdin failed : %v", err) 778 - } 768 + if n, err := io.ReadFull(in, r.Data); uint64(n) != r.Length-4 || err != nil { 769 + return nil, fail(ctx, "Protocol: stdin error", "Pkt-Line: read stdin failed : %v", err) 779 770 } 780 771 781 772 r.Type = pktLineTypeData ··· 791 782 return nil 792 783 } 793 784 785 + // Write an Pkt-Line based on `data` to `out` according to the specifcation. 786 + // https://git-scm.com/docs/protocol-common 794 787 func writeDataPktLine(ctx context.Context, out io.Writer, data []byte) error { 795 - hexchar := []byte("0123456789abcdef") 796 - hex := func(n uint64) byte { 797 - return hexchar[(n)&15] 788 + // Implementations SHOULD NOT send an empty pkt-line ("0004"). 789 + if len(data) == 0 { 790 + return fail(ctx, "Protocol: write error", "Not allowed to write empty Pkt-Line") 798 791 } 799 792 800 793 length := uint64(len(data) + 4) 801 - tmp := make([]byte, 4) 802 - tmp[0] = hex(length >> 12) 803 - tmp[1] = hex(length >> 8) 804 - tmp[2] = hex(length >> 4) 805 - tmp[3] = hex(length) 794 + 795 + // The maximum length of a pkt-line’s data component is 65516 bytes. 796 + // Implementations MUST NOT send pkt-line whose length exceeds 65520 (65516 bytes of payload + 4 bytes of length data). 797 + if length > 65520 { 798 + return fail(ctx, "Protocol: write error", "Pkt-Line exceeds maximum of 65520 bytes") 799 + } 806 800 807 - lr, err := out.Write(tmp) 801 + lr, err := fmt.Fprintf(out, "%04x", length) 808 802 if err != nil || lr != 4 { 809 803 return fail(ctx, "Protocol: write error", "Pkt-Line response failed: %v", err) 810 804 }
+64 -21
cmd/hook_test.go
··· 14 14 ) 15 15 16 16 func TestPktLine(t *testing.T) { 17 - // test read 18 17 ctx := context.Background() 19 - s := strings.NewReader("0000") 20 - r := bufio.NewReader(s) 21 - result, err := readPktLine(ctx, r, pktLineTypeFlush) 22 - assert.NoError(t, err) 23 - assert.Equal(t, pktLineTypeFlush, result.Type) 18 + 19 + t.Run("Read", func(t *testing.T) { 20 + s := strings.NewReader("0000") 21 + r := bufio.NewReader(s) 22 + result, err := readPktLine(ctx, r, pktLineTypeFlush) 23 + assert.NoError(t, err) 24 + assert.Equal(t, pktLineTypeFlush, result.Type) 25 + 26 + s = strings.NewReader("0006a\n") 27 + r = bufio.NewReader(s) 28 + result, err = readPktLine(ctx, r, pktLineTypeData) 29 + assert.NoError(t, err) 30 + assert.Equal(t, pktLineTypeData, result.Type) 31 + assert.Equal(t, []byte("a\n"), result.Data) 32 + 33 + s = strings.NewReader("0004") 34 + r = bufio.NewReader(s) 35 + result, err = readPktLine(ctx, r, pktLineTypeData) 36 + assert.Error(t, err) 37 + assert.Nil(t, result) 38 + 39 + data := strings.Repeat("x", 65516) 40 + r = bufio.NewReader(strings.NewReader("fff0" + data)) 41 + result, err = readPktLine(ctx, r, pktLineTypeData) 42 + assert.NoError(t, err) 43 + assert.Equal(t, pktLineTypeData, result.Type) 44 + assert.Equal(t, []byte(data), result.Data) 45 + 46 + r = bufio.NewReader(strings.NewReader("fff1a")) 47 + result, err = readPktLine(ctx, r, pktLineTypeData) 48 + assert.Error(t, err) 49 + assert.Nil(t, result) 50 + }) 51 + 52 + t.Run("Write", func(t *testing.T) { 53 + w := bytes.NewBuffer([]byte{}) 54 + err := writeFlushPktLine(ctx, w) 55 + assert.NoError(t, err) 56 + assert.Equal(t, []byte("0000"), w.Bytes()) 57 + 58 + w.Reset() 59 + err = writeDataPktLine(ctx, w, []byte("a\nb")) 60 + assert.NoError(t, err) 61 + assert.Equal(t, []byte("0007a\nb"), w.Bytes()) 24 62 25 - s = strings.NewReader("0006a\n") 26 - r = bufio.NewReader(s) 27 - result, err = readPktLine(ctx, r, pktLineTypeData) 28 - assert.NoError(t, err) 29 - assert.Equal(t, pktLineTypeData, result.Type) 30 - assert.Equal(t, []byte("a\n"), result.Data) 63 + w.Reset() 64 + data := bytes.Repeat([]byte{0x05}, 288) 65 + err = writeDataPktLine(ctx, w, data) 66 + assert.NoError(t, err) 67 + assert.Equal(t, append([]byte("0124"), data...), w.Bytes()) 31 68 32 - // test write 33 - w := bytes.NewBuffer([]byte{}) 34 - err = writeFlushPktLine(ctx, w) 35 - assert.NoError(t, err) 36 - assert.Equal(t, []byte("0000"), w.Bytes()) 69 + w.Reset() 70 + err = writeDataPktLine(ctx, w, nil) 71 + assert.Error(t, err) 72 + assert.Empty(t, w.Bytes()) 73 + 74 + w.Reset() 75 + data = bytes.Repeat([]byte{0x64}, 65516) 76 + err = writeDataPktLine(ctx, w, data) 77 + assert.NoError(t, err) 78 + assert.Equal(t, append([]byte("fff0"), data...), w.Bytes()) 37 79 38 - w.Reset() 39 - err = writeDataPktLine(ctx, w, []byte("a\nb")) 40 - assert.NoError(t, err) 41 - assert.Equal(t, []byte("0007a\nb"), w.Bytes()) 80 + w.Reset() 81 + err = writeDataPktLine(ctx, w, bytes.Repeat([]byte{0x64}, 65516+1)) 82 + assert.Error(t, err) 83 + assert.Empty(t, w.Bytes()) 84 + }) 42 85 }
+5 -1
cmd/serv.go
··· 14 14 "regexp" 15 15 "strconv" 16 16 "strings" 17 + "testing" 17 18 "time" 18 19 "unicode" 19 20 ··· 106 107 logMsg = userMessage + ". " + logMsg 107 108 } 108 109 } 109 - _ = private.SSHLog(ctx, true, logMsg) 110 + // Don't send an log if this is done in a test and no InternalToken is set. 111 + if !testing.Testing() || setting.InternalToken != "" { 112 + _ = private.SSHLog(ctx, true, logMsg) 113 + } 110 114 } 111 115 return cli.Exit("", 1) 112 116 }