Skip to content

Commit 41714c2

Browse files
committed
[FAB-6355] Fix GetPrivateData() error on CouchDB
The problem was that the retrieve of the public hash from couch state db fails due to a URL encoding issue of a plus sign in the hashed key. Keys were already URL encoded using golang URL encoding, but the encoding skips plus signs in the path component. CouchDB unencodes the plus sign as a space. The fix is to explicitly URL encode plus character when interacting with CouchDB. Also add unit test to verify the fix and test all other URL special characters. Also clarified the error message received when private version does not match public hash. Change-Id: I9b99d3446542e9eae0196158270205d3ea09db9f Signed-off-by: David Enyeart <enyeart@us.ibm.com>
1 parent dbe3c78 commit 41714c2

File tree

3 files changed

+29
-4
lines changed

3 files changed

+29
-4
lines changed

core/ledger/kvledger/txmgmt/txmgr/lockbasedtxmgr/helper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func (h *queryHelper) getPrivateData(ns, coll, key string) ([]byte, error) {
119119
}
120120
if !version.AreSame(hashVersion, ver) {
121121
return nil, &txmgr.ErrPvtdataNotAvailable{Msg: fmt.Sprintf(
122-
"The available copy of the private data is not latest. The latest version = %#v, available version = %#v",
122+
"Private data matching public hash version is not available. Public hash version = %#v, Private data version = %#v",
123123
hashVersion, ver)}
124124
}
125125
if h.rwsetBuilder != nil {

core/ledger/util/couchdb/couchdb.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1407,13 +1407,16 @@ func IsJSON(s string) bool {
14071407
return json.Unmarshal([]byte(s), &js) == nil
14081408
}
14091409

1410-
// encodePathElement uses Golang for encoding and in addition, replaces a '/' by %2F.
1411-
// Otherwise, in the regular encoding, a '/' is treated as a path separator in the url
1410+
// encodePathElement uses Golang for url path encoding, additionally:
1411+
// '/' is replaced by %2F, otherwise path encoding will treat as path separator and ignore it
1412+
// '+' is replaced by %2B, otherwise path encoding will ignore it, while CouchDB will unencode the plus as a space
1413+
// Note that all other URL special characters have been tested successfully without need for special handling
14121414
func encodePathElement(str string) string {
14131415
u := &url.URL{}
14141416
u.Path = str
1415-
encodedStr := u.String()
1417+
encodedStr := u.String() // url encode using golang url path encoding rules
14161418
encodedStr = strings.Replace(encodedStr, "/", "%2F", -1)
1419+
encodedStr = strings.Replace(encodedStr, "+", "%2B", -1)
14171420
return encodedStr
14181421
}
14191422

core/ledger/util/couchdb/couchdb_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,6 +1130,7 @@ func TestBatchBatchOperations(t *testing.T) {
11301130
byteJSON03 := []byte(`{"_id":"marble03","asset_name":"marble03","color":"green","size":"3","owner":"jerry"}`)
11311131
byteJSON04 := []byte(`{"_id":"marble04","asset_name":"marble04","color":"purple","size":"4","owner":"tom"}`)
11321132
byteJSON05 := []byte(`{"_id":"marble05","asset_name":"marble05","color":"blue","size":"5","owner":"jerry"}`)
1133+
byteJSON06 := []byte(`{"_id":"marble06#$&'()*+,/:;=?@[]","asset_name":"marble06#$&'()*+,/:;=?@[]","color":"blue","size":"6","owner":"jerry"}`)
11331134

11341135
attachment1 := &AttachmentInfo{}
11351136
attachment1.AttachmentBytes = []byte(`marble01 - test attachment`)
@@ -1166,6 +1167,13 @@ func TestBatchBatchOperations(t *testing.T) {
11661167
attachments5 := []*AttachmentInfo{}
11671168
attachments5 = append(attachments5, attachment5)
11681169

1170+
attachment6 := &AttachmentInfo{}
1171+
attachment6.AttachmentBytes = []byte(`marble06#$&'()*+,/:;=?@[] - test attachment`)
1172+
attachment6.ContentType = "application/octet-stream"
1173+
attachment6.Name = "data"
1174+
attachments6 := []*AttachmentInfo{}
1175+
attachments6 = append(attachments6, attachment6)
1176+
11691177
database := "testbatch"
11701178
err := cleanup(database)
11711179
testutil.AssertNoError(t, err, fmt.Sprintf("Error when trying to cleanup Error: %s", err))
@@ -1188,12 +1196,14 @@ func TestBatchBatchOperations(t *testing.T) {
11881196
value3 := &CouchDoc{JSONValue: byteJSON03, Attachments: attachments3}
11891197
value4 := &CouchDoc{JSONValue: byteJSON04, Attachments: attachments4}
11901198
value5 := &CouchDoc{JSONValue: byteJSON05, Attachments: attachments5}
1199+
value6 := &CouchDoc{JSONValue: byteJSON06, Attachments: attachments6}
11911200

11921201
batchUpdateDocs = append(batchUpdateDocs, value1)
11931202
batchUpdateDocs = append(batchUpdateDocs, value2)
11941203
batchUpdateDocs = append(batchUpdateDocs, value3)
11951204
batchUpdateDocs = append(batchUpdateDocs, value4)
11961205
batchUpdateDocs = append(batchUpdateDocs, value5)
1206+
batchUpdateDocs = append(batchUpdateDocs, value6)
11971207

11981208
batchUpdateResp, err := db.BatchUpdateDocuments(batchUpdateDocs)
11991209
testutil.AssertNoError(t, err, fmt.Sprintf("Error when attempting to update a batch of documents"))
@@ -1214,6 +1224,18 @@ func TestBatchBatchOperations(t *testing.T) {
12141224
//Verify the owner retrieved matches
12151225
testutil.AssertEquals(t, assetResp.Owner, "jerry")
12161226

1227+
//----------------------------------------------
1228+
// Test Retrieve JSON using ID with URL special characters,
1229+
// this will confirm that batch document IDs and URL IDs are consistent, even if they include special characters
1230+
dbGetResp, _, geterr = db.ReadDoc("marble06#$&'()*+,/:;=?@[]")
1231+
testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when attempting read a document"))
1232+
1233+
assetResp = &Asset{}
1234+
geterr = json.Unmarshal(dbGetResp.JSONValue, &assetResp)
1235+
testutil.AssertNoError(t, geterr, fmt.Sprintf("Error when trying to retrieve a document"))
1236+
//Verify the owner retrieved matches
1237+
testutil.AssertEquals(t, assetResp.Owner, "jerry")
1238+
12171239
//----------------------------------------------
12181240
//Test retrieve binary
12191241
dbGetResp, _, geterr = db.ReadDoc("marble03")

0 commit comments

Comments
 (0)