From 1310649331648d747c57a52ea3bc92da85e7d4d1 Mon Sep 17 00:00:00 2001
From: Rowan Bohde <rowan.bohde@gmail.com>
Date: Wed, 14 Aug 2024 16:50:09 -0500
Subject: [PATCH] render plain text file if the LFS object doesn't exist
 (#31812)

We had an issue where a repo was using LFS to store a file, but the user
did not push the file. When trying to view the file, Gitea returned a
500 HTTP status code referencing `ErrLFSObjectNotExist`. It appears the
intent was the render this file as plain text, but the conditional was
flipped. I've also added a test to verify that the file is rendered as
plain text.
---
 routers/web/repo/view.go                          |   6 ++----
 .../30/77e1c4c8964613df72c37d14275c1eda5228a9     |   2 ++
 .../6b/bc79965141058b0026f2064dfb6d2eae3c4540     | Bin 0 -> 259 bytes
 .../b0/89e97ee59224e8c5676673c096ee4b6a8b9342     | Bin 0 -> 123 bytes
 .../e9/c32647bab825977942598c0efa415de300304b     | Bin 0 -> 170 bytes
 .../user2/lfs.git/refs/heads/master               |   2 +-
 tests/integration/lfs_view_test.go                |  13 +++++++++++++
 7 files changed, 18 insertions(+), 5 deletions(-)
 create mode 100644 tests/gitea-repositories-meta/user2/lfs.git/objects/30/77e1c4c8964613df72c37d14275c1eda5228a9
 create mode 100644 tests/gitea-repositories-meta/user2/lfs.git/objects/6b/bc79965141058b0026f2064dfb6d2eae3c4540
 create mode 100644 tests/gitea-repositories-meta/user2/lfs.git/objects/b0/89e97ee59224e8c5676673c096ee4b6a8b9342
 create mode 100644 tests/gitea-repositories-meta/user2/lfs.git/objects/e9/c32647bab825977942598c0efa415de300304b

diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index dfc33ff36d..5e67386457 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -234,14 +234,12 @@ func getFileReader(ctx gocontext.Context, repoID int64, blob *git.Blob) ([]byte,
 	}
 
 	meta, err := git_model.GetLFSMetaObjectByOid(ctx, repoID, pointer.Oid)
-	if err != nil && err != git_model.ErrLFSObjectNotExist { // fallback to plain file
+	if err != nil { // fallback to plain file
+		log.Warn("Unable to access LFS pointer %s in repo %d: %v", pointer.Oid, repoID, err)
 		return buf, dataRc, &fileInfo{isTextFile, false, blob.Size(), nil, st}, nil
 	}
 
 	dataRc.Close()
-	if err != nil {
-		return nil, nil, nil, err
-	}
 
 	dataRc, err = lfs.ReadMetaObject(pointer)
 	if err != nil {
diff --git a/tests/gitea-repositories-meta/user2/lfs.git/objects/30/77e1c4c8964613df72c37d14275c1eda5228a9 b/tests/gitea-repositories-meta/user2/lfs.git/objects/30/77e1c4c8964613df72c37d14275c1eda5228a9
new file mode 100644
index 0000000000..c2dc6e5a4f
--- /dev/null
+++ b/tests/gitea-repositories-meta/user2/lfs.git/objects/30/77e1c4c8964613df72c37d14275c1eda5228a9
@@ -0,0 +1,2 @@
+xK��OR0�0`p��	�t
+
��s��MQH��)I-��I+VH�LK3rS��S�,ݒԊ.-���t"U&e��23�,1'�8���A�
\ No newline at end of file
diff --git a/tests/gitea-repositories-meta/user2/lfs.git/objects/6b/bc79965141058b0026f2064dfb6d2eae3c4540 b/tests/gitea-repositories-meta/user2/lfs.git/objects/6b/bc79965141058b0026f2064dfb6d2eae3c4540
new file mode 100644
index 0000000000000000000000000000000000000000..97455cbc46ed6801ec009d2a6b4cd2ce2347bcfa
GIT binary patch
literal 259
zcmV+e0sQ`W0V^p=O;s>5GiER}FfcPQQP4}zEJ-XWDauSLElDkAFera`<is>L;rm60
zYem#!<ZcCNtc0p`_V)`3@^lIf@$_@o%S~a>&dKpx_e*7yzQUx#SH0EjKjpuUfGQ1g
zb#(D{1u1GOyR>L}<@y;qT)(Dg->$R{y5h6~swlarvY<pSDKn4Z$`UDF-z`(-3C+Hw
z-!54AYDOdTd#Iw!yt2fc%oK(VoiFR2PEvVsG(D~Oz_fSXS>2PJph~g|Qq%Ra3ep)$
z6c<P=fBZ4-X{NlGF5ivXgEN{wm>2+oLUCzQN@fwmo~L{(J~6+WWE+*j%c{_|--yj4
J4*(iHX&$FKd=UTu

literal 0
HcmV?d00001

diff --git a/tests/gitea-repositories-meta/user2/lfs.git/objects/b0/89e97ee59224e8c5676673c096ee4b6a8b9342 b/tests/gitea-repositories-meta/user2/lfs.git/objects/b0/89e97ee59224e8c5676673c096ee4b6a8b9342
new file mode 100644
index 0000000000000000000000000000000000000000..33ab64e7303e418c3270708ab1134aa417e2f8a5
GIT binary patch
literal 123
zcmV->0EGW|0S(H*5yBu406^bVK?4Ti;0Wo4<3N~+k`c_q>dk9EOM54&jlZ4wGg^Pk
zI_EJqrJilx_cE5t`lTiHml{V->eQk)mZL`Fa0{&cO0H=4um~0kgDKW&E&*anhL}S}
d@IcvKG2ohQij0J4Jvc2!`(<gI_yePiDF;b@I<No$

literal 0
HcmV?d00001

diff --git a/tests/gitea-repositories-meta/user2/lfs.git/objects/e9/c32647bab825977942598c0efa415de300304b b/tests/gitea-repositories-meta/user2/lfs.git/objects/e9/c32647bab825977942598c0efa415de300304b
new file mode 100644
index 0000000000000000000000000000000000000000..f513e2a308b1e4dd23eb0a4c541dbafa619711f7
GIT binary patch
literal 170
zcmV;b09F5Z0iBLpYQr!P0Q;>|>;)QDtA}L>CG-fnfu!AS1h!QiCB1%~E97$q2B!9P
zZ3D>7A7dARSW2DdIR@)3hExzKDq-}jB{E4CSAFnke)BHdfXP)w$0bS?=fzUd*-A>m
zaSci1l$10PoBSBJzQeWu<qf|3jRns83r^()m!CDa<y8Cn1$H6|-dc3<i2>0Z_Lv;<
YW^OVwwC$Of#<1uev@K%(0i~r&qPFu<cK`qY

literal 0
HcmV?d00001

diff --git a/tests/gitea-repositories-meta/user2/lfs.git/refs/heads/master b/tests/gitea-repositories-meta/user2/lfs.git/refs/heads/master
index 8832a3e857..487a433af2 100644
--- a/tests/gitea-repositories-meta/user2/lfs.git/refs/heads/master
+++ b/tests/gitea-repositories-meta/user2/lfs.git/refs/heads/master
@@ -1 +1 @@
-73cf03db6ece34e12bf91e8853dc58f678f2f82d
+e9c32647bab825977942598c0efa415de300304b
diff --git a/tests/integration/lfs_view_test.go b/tests/integration/lfs_view_test.go
index c28ecf1d7a..05770e5e0a 100644
--- a/tests/integration/lfs_view_test.go
+++ b/tests/integration/lfs_view_test.go
@@ -89,6 +89,19 @@ func TestLFSRender(t *testing.T) {
 		content := doc.Find("div.file-view").Text()
 		assert.Contains(t, content, "Testing READMEs in LFS")
 	})
+
+	// check that an invalid lfs entry defaults to plaintext
+	t.Run("Invalid", func(t *testing.T) {
+		defer tests.PrintCurrentTest(t)()
+
+		req := NewRequest(t, "GET", "/user2/lfs/src/branch/master/invalid")
+		resp := session.MakeRequest(t, req, http.StatusOK)
+
+		doc := NewHTMLParser(t, resp.Body).doc
+
+		content := doc.Find("div.file-view").Text()
+		assert.Contains(t, content, "oid sha256:9d178b5f15046343fd32f451df93acc2bdd9e6373be478b968e4cad6b6647351")
+	})
 }
 
 // TestLFSLockView tests the LFS lock view on settings page of repositories