Skip to content

Commit 921aaa1

Browse files
authored
Merge pull request #394 from aartigao/to-string-safe-uri
`Uri.toStringSafe` for hiding sensitive query params
2 parents 2d5f05a + a6825e0 commit 921aaa1

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

core/src/main/scala/sttp/model/Uri.scala

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -301,7 +301,9 @@ case class Uri(
301301
/** Serializes the query to a string, encoding the segments. The leading `?` is not included. Might be an empty
302302
* string, if there's no query.
303303
*/
304-
def queryToString: String = {
304+
def queryToString: String = queryToStringSafe()
305+
306+
private def queryToStringSafe(sensitiveQueryParams: Set[String] = Set.empty): String = {
305307
@tailrec
306308
def encodeQuerySegments(qss: List[QuerySegment], previousWasPlain: Boolean, sb: StringBuilder): String =
307309
qss match {
@@ -317,7 +319,7 @@ case class Uri(
317319

318320
case KeyValue(k, v, kEnc, vEnc) :: t =>
319321
if (!previousWasPlain) sb.append("&")
320-
sb.append(kEnc(k)).append("=").append(vEnc(v))
322+
sb.append(kEnc(k)).append("=").append(if (sensitiveQueryParams(k)) "***" else vEnc(v))
321323
encodeQuerySegments(t, previousWasPlain = false, sb)
322324
}
323325
encodeQuerySegments(querySegments.toList, previousWasPlain = true, new StringBuilder())
@@ -331,14 +333,19 @@ case class Uri(
331333
fragmentSegment.fold("")(s => s.encoded)
332334
}
333335

334-
override def toString: String = {
336+
override def toString: String = toStringSafe()
337+
338+
/** @return
339+
* Representation where sensitive query params value is omitted.
340+
*/
341+
def toStringSafe(sensitiveQueryParams: Set[String] = Set.empty): String = {
335342
val schemeS = scheme.map(s => encode(Rfc3986.Scheme)(s) + ":").getOrElse("")
336343
val authorityS = authority.fold("")(_.toString)
337344

338345
val pathS = pathToString
339346

340347
val queryPrefixS = if (querySegments.isEmpty) "" else "?"
341-
val queryS = queryToString
348+
val queryS = queryToStringSafe(sensitiveQueryParams)
342349

343350
val fragS = fragmentSegment.fold("")(s => "#" + s.encoded)
344351

core/src/test/scala/sttp/model/UriTests.scala

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class UriTests extends AnyFunSuite with Matchers with TryValues with UriTestsExt
129129
for {
130130
(segments, expected) <- querySegmentsTestData
131131
} {
132-
test(s"$segments should serialize to$expected") {
132+
test(s"$segments should serialize to $expected") {
133133
testUri.copy(querySegments = segments).toString should endWith(expected)
134134
}
135135
}
@@ -145,7 +145,7 @@ class UriTests extends AnyFunSuite with Matchers with TryValues with UriTestsExt
145145
for {
146146
(segments, expected) <- bodyPartEncodingTestData
147147
} {
148-
test(s"$segments should serialize to$expected") {
148+
test(s"$segments should serialize to $expected") {
149149
UriCompatibility.encodeBodyPart(segments, "utf-8") should endWith(expected)
150150
}
151151
}
@@ -282,4 +282,9 @@ class UriTests extends AnyFunSuite with Matchers with TryValues with UriTestsExt
282282
test("should serialize scheme") {
283283
uri"http://x.com/a/b/c".schemeToString shouldBe "http"
284284
}
285+
286+
test("should serialize query safe") {
287+
uri"http://x.com?a=b&c=d".toStringSafe(Set("c")) shouldBe "http://x.com?a=b&c=***"
288+
uri"http://x.com/a/b/c?p1=1%202".toStringSafe(Set("p1")) shouldBe "http://x.com/a/b/c?p1=***"
289+
}
285290
}

0 commit comments

Comments
 (0)