scalaunfiltered

URL decoding with unfiltered


I'm working with Unfiltered 0.6.8 (using the Jetty connector) and have encountered an odd behaviour: path segments aren't URL decoded.

The following bit of code is my minimal test case:

import unfiltered.request._
import unfiltered.response._

object Test extends App with unfiltered.filter.Plan {
  def intent = {

    case reg @ Path(Seg(test :: Nil)) =>
      println(test)
      ResponseString(test)
  }

  unfiltered.jetty.Http.local(8080).filter(Test).run()
}

Querying http://localhost:8080/some_string yields the expected result: some_string, both on the client and server side.

On the other hand, http://localhost:8080/some%20string yields some%20string on both client and server, rather than the some string I was expecting.

Working around the issue is trivial (java.net.URLDecoder#decode(String, String)), but I'd like to know if:

As a side note, the unfiltered tag doesn't exist and I do not have enough reputation to create it, which is why I defaulted to scala.


Solution

  • Strange, I'm seeing this behavior too. There is nothing in the Seg object that does any sort of url decoding prior to splitting up the path segments and I don't see anything else in the framework for this either. I ran into a post that detailed a solution using a custom extractor as follows:

    object Decode {
      import java.net.URLDecoder
      import java.nio.charset.Charset
    
      trait Extract {
        def charset: Charset
        def unapply(raw: String) = 
          Try(URLDecoder.decode(raw, charset.name())).toOption
      }
    
      object utf8 extends Extract {
        val charset = Charset.forName("utf8")
      }
    }
    

    Then you could use it like this:

    case reg @ Path(Seg(Decode.utf8(test) :: Nil)) =>
      println(test)
      ResponseString(test)
    

    Or like this if you wanted the entire path decoded:

    case reg @ Path(Decode.utf8(Seg(test :: Nil))) =>
      println(test)
      ResponseString(test)
    

    Thankfully the framework is flexible and open to extension like this, so you certainly have options.