mirror of
				https://gitee.com/gitea/gitea
				synced 2025-11-04 00:20:25 +08:00 
			
		
		
		
	* Handle incomplete diff files properly (#13669)
The code for parsing diff hunks has a bug whereby a very long line in a very long diff would not be completely read leading to an unexpected character. This PR ensures that the line is completely cleared * Also allow git max line length <4096 * Add test case Fix #13602 Signed-off-by: Andrew Thornton <art27@cantab.net> Co-authored-by: Andrew Thornton <art27@cantab.net>
This commit is contained in:
		@@ -613,6 +613,15 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
 | 
				
			|||||||
	leftLine, rightLine := 1, 1
 | 
						leftLine, rightLine := 1, 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for {
 | 
						for {
 | 
				
			||||||
 | 
							for isFragment {
 | 
				
			||||||
 | 
								curFile.IsIncomplete = true
 | 
				
			||||||
 | 
								_, isFragment, err = input.ReadLine()
 | 
				
			||||||
 | 
								if err != nil {
 | 
				
			||||||
 | 
									// Now by the definition of ReadLine this cannot be io.EOF
 | 
				
			||||||
 | 
									err = fmt.Errorf("Unable to ReadLine: %v", err)
 | 
				
			||||||
 | 
									return
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		sb.Reset()
 | 
							sb.Reset()
 | 
				
			||||||
		lineBytes, isFragment, err = input.ReadLine()
 | 
							lineBytes, isFragment, err = input.ReadLine()
 | 
				
			||||||
		if err != nil {
 | 
							if err != nil {
 | 
				
			||||||
@@ -726,6 +735,10 @@ func parseHunks(curFile *DiffFile, maxLines, maxLineCharacters int, input *bufio
 | 
				
			|||||||
				}
 | 
									}
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if len(line) > maxLineCharacters {
 | 
				
			||||||
 | 
								curFile.IsIncomplete = true
 | 
				
			||||||
 | 
								line = line[:maxLineCharacters]
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
		curSection.Lines[len(curSection.Lines)-1].Content = line
 | 
							curSection.Lines[len(curSection.Lines)-1].Content = line
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// handle LFS
 | 
							// handle LFS
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -9,6 +9,7 @@ import (
 | 
				
			|||||||
	"encoding/json"
 | 
						"encoding/json"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"html/template"
 | 
						"html/template"
 | 
				
			||||||
 | 
						"strconv"
 | 
				
			||||||
	"strings"
 | 
						"strings"
 | 
				
			||||||
	"testing"
 | 
						"testing"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -95,11 +96,11 @@ func TestParsePatch_singlefile(t *testing.T) {
 | 
				
			|||||||
			name: "really weird filename",
 | 
								name: "really weird filename",
 | 
				
			||||||
			gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/file b/a a/file"
 | 
								gitdiff: `diff --git "\\a/a b/file b/a a/file" "\\b/a b/file b/a a/file"
 | 
				
			||||||
index d2186f1..f5c8ed2 100644
 | 
					index d2186f1..f5c8ed2 100644
 | 
				
			||||||
--- "\\a/a b/file b/a a/file"	
 | 
					--- "\\a/a b/file b/a a/file"	` + `
 | 
				
			||||||
+++ "\\b/a b/file b/a a/file"	
 | 
					+++ "\\b/a b/file b/a a/file"	` + `
 | 
				
			||||||
@@ -1,3 +1,2 @@
 | 
					@@ -1,3 +1,2 @@
 | 
				
			||||||
 Create a weird file.
 | 
					 Create a weird file.
 | 
				
			||||||
 
 | 
					 ` + `
 | 
				
			||||||
-and what does diff do here?
 | 
					-and what does diff do here?
 | 
				
			||||||
\ No newline at end of file`,
 | 
					\ No newline at end of file`,
 | 
				
			||||||
			addition:    0,
 | 
								addition:    0,
 | 
				
			||||||
@@ -112,7 +113,7 @@ index d2186f1..f5c8ed2 100644
 | 
				
			|||||||
			gitdiff: `diff --git "\\a/file with blanks" "\\b/file with blanks"
 | 
								gitdiff: `diff --git "\\a/file with blanks" "\\b/file with blanks"
 | 
				
			||||||
deleted file mode 100644
 | 
					deleted file mode 100644
 | 
				
			||||||
index 898651a..0000000
 | 
					index 898651a..0000000
 | 
				
			||||||
--- "\\a/file with blanks"	
 | 
					--- "\\a/file with blanks" ` + `
 | 
				
			||||||
+++ /dev/null
 | 
					+++ /dev/null
 | 
				
			||||||
@@ -1,5 +0,0 @@
 | 
					@@ -1,5 +0,0 @@
 | 
				
			||||||
-a blank file
 | 
					-a blank file
 | 
				
			||||||
@@ -205,7 +206,83 @@ index 6961180..9ba1a00 100644
 | 
				
			|||||||
		})
 | 
							})
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	var diff = `diff --git "a/README.md" "b/README.md"
 | 
						// Test max lines
 | 
				
			||||||
 | 
						diffBuilder := &strings.Builder{}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						var diff = `diff --git a/newfile2 b/newfile2
 | 
				
			||||||
 | 
					new file mode 100644
 | 
				
			||||||
 | 
					index 0000000..6bb8f39
 | 
				
			||||||
 | 
					--- /dev/null
 | 
				
			||||||
 | 
					+++ b/newfile2
 | 
				
			||||||
 | 
					@@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
 | 
						diffBuilder.WriteString(diff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < 35; i++ {
 | 
				
			||||||
 | 
							diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						diff = diffBuilder.String()
 | 
				
			||||||
 | 
						result, err := ParsePatch(20, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("There should not be an error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !result.Files[0].IsIncomplete {
 | 
				
			||||||
 | 
							t.Errorf("Files should be incomplete! %v", result.Files[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result, err = ParsePatch(40, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("There should not be an error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if result.Files[0].IsIncomplete {
 | 
				
			||||||
 | 
							t.Errorf("Files should not be incomplete! %v", result.Files[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result, err = ParsePatch(40, 5, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("There should not be an error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !result.Files[0].IsIncomplete {
 | 
				
			||||||
 | 
							t.Errorf("Files should be incomplete! %v", result.Files[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Test max characters
 | 
				
			||||||
 | 
						diff = `diff --git a/newfile2 b/newfile2
 | 
				
			||||||
 | 
					new file mode 100644
 | 
				
			||||||
 | 
					index 0000000..6bb8f39
 | 
				
			||||||
 | 
					--- /dev/null
 | 
				
			||||||
 | 
					+++ b/newfile2
 | 
				
			||||||
 | 
					@@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					`
 | 
				
			||||||
 | 
						diffBuilder.Reset()
 | 
				
			||||||
 | 
						diffBuilder.WriteString(diff)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for i := 0; i < 33; i++ {
 | 
				
			||||||
 | 
							diffBuilder.WriteString("+line" + strconv.Itoa(i) + "\n")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						diffBuilder.WriteString("+line33")
 | 
				
			||||||
 | 
						for i := 0; i < 512; i++ {
 | 
				
			||||||
 | 
							diffBuilder.WriteString("0123456789ABCDEF")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						diffBuilder.WriteByte('\n')
 | 
				
			||||||
 | 
						diffBuilder.WriteString("+line" + strconv.Itoa(34) + "\n")
 | 
				
			||||||
 | 
						diffBuilder.WriteString("+line" + strconv.Itoa(35) + "\n")
 | 
				
			||||||
 | 
						diff = diffBuilder.String()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						result, err = ParsePatch(20, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("There should not be an error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !result.Files[0].IsIncomplete {
 | 
				
			||||||
 | 
							t.Errorf("Files should be incomplete! %v", result.Files[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						result, err = ParsePatch(40, 4096, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							t.Errorf("There should not be an error: %v", err)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						if !result.Files[0].IsIncomplete {
 | 
				
			||||||
 | 
							t.Errorf("Files should be incomplete! %v", result.Files[0])
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						diff = `diff --git "a/README.md" "b/README.md"
 | 
				
			||||||
--- a/README.md
 | 
					--- a/README.md
 | 
				
			||||||
+++ b/README.md
 | 
					+++ b/README.md
 | 
				
			||||||
@@ -1,3 +1,6 @@
 | 
					@@ -1,3 +1,6 @@
 | 
				
			||||||
@@ -216,7 +293,7 @@ index 6961180..9ba1a00 100644
 | 
				
			|||||||
 Docker Pulls
 | 
					 Docker Pulls
 | 
				
			||||||
+ cut off
 | 
					+ cut off
 | 
				
			||||||
+ cut off`
 | 
					+ cut off`
 | 
				
			||||||
	result, err := ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
						result, err = ParsePatch(setting.Git.MaxGitDiffLines, setting.Git.MaxGitDiffLineCharacters, setting.Git.MaxGitDiffFiles, strings.NewReader(diff))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		t.Errorf("ParsePatch failed: %s", err)
 | 
							t.Errorf("ParsePatch failed: %s", err)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user