diff --git a/core/src/main/scala/org/http4s/Message.scala b/core/src/main/scala/org/http4s/Message.scala index ed6c74f7ea4..b00b38ef54f 100644 --- a/core/src/main/scala/org/http4s/Message.scala +++ b/core/src/main/scala/org/http4s/Message.scala @@ -294,13 +294,15 @@ sealed abstract case class Request[F[_]]( attributes = attributes ) - lazy val (scriptName, pathInfo) = { - val caret = attributes.lookup(Request.Keys.PathInfoCaret).getOrElse(0) + lazy val (scriptName, pathInfo) = uri.path.splitAt(caret) - } + + private def caret = + attributes.lookup(Request.Keys.PathInfoCaret).getOrElse(0) def withPathInfo(pi: String): Self = - withUri(uri.withPath(scriptName + pi)) + // Don't use withUri, which clears the caret + copy(uri = uri.withPath(scriptName + pi)) def pathTranslated: Option[File] = attributes.lookup(Keys.PathTranslated) diff --git a/server/src/main/scala/org/http4s/server/middleware/AutoSlash.scala b/server/src/main/scala/org/http4s/server/middleware/AutoSlash.scala index e131447f6e7..ad76f863ee0 100644 --- a/server/src/main/scala/org/http4s/server/middleware/AutoSlash.scala +++ b/server/src/main/scala/org/http4s/server/middleware/AutoSlash.scala @@ -15,22 +15,18 @@ import cats.implicits._ object AutoSlash { def apply[F[_], G[_], B](http: Kleisli[F, Request[G], B])( implicit F: MonoidK[F], - G: Functor[G]): Kleisli[F, Request[G], B] = + G: Functor[G]): Kleisli[F, Request[G], B] = { + val _ = G // for binary compatibility in 0.20, remove on master Kleisli { req => http(req) <+> { val pathInfo = req.pathInfo - val scriptName = req.scriptName if (pathInfo.isEmpty || pathInfo.charAt(pathInfo.length - 1) != '/') { F.empty - } else if (scriptName.isEmpty) { - // Request has not been translated already - http.apply(req.withPathInfo(pathInfo.substring(0, pathInfo.length - 1))) } else { - // Request has been translated at least once, redo the translation - val translated = TranslateUri(scriptName)(http) - translated.apply(req.withPathInfo(pathInfo.substring(0, pathInfo.length - 1))) + http.apply(req.withPathInfo(pathInfo.substring(0, pathInfo.length - 1))) } } } + } } diff --git a/tests/src/test/scala/org/http4s/MessageSpec.scala b/tests/src/test/scala/org/http4s/MessageSpec.scala index f0575896199..859782674df 100644 --- a/tests/src/test/scala/org/http4s/MessageSpec.scala +++ b/tests/src/test/scala/org/http4s/MessageSpec.scala @@ -96,6 +96,16 @@ class MessageSpec extends Http4sSpec { originalReq.pathInfo mustEqual updatedReq.pathInfo originalReq.scriptName mustEqual updatedReq.scriptName } + + "preserve caret in withPathInfo" in { + val originalReq = Request( + uri = Uri(path = "/foo/bar"), + attributes = Vault.empty.insert(Request.Keys.PathInfoCaret, 4)) + val updatedReq = originalReq.withPathInfo("/quux") + + updatedReq.scriptName mustEqual "/foo" + updatedReq.pathInfo mustEqual "/quux" + } } "toString" should {