Skip to content

Commit

Permalink
Match path maps in order of longest matching key prefix (akka#394)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonas committed Dec 1, 2016
1 parent 3620e7b commit 47a0321
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package akka.http.scaladsl.server.directives

import scala.collection.immutable.ListMap
import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.server._
import org.scalactic.source.Position
Expand Down Expand Up @@ -63,6 +64,73 @@ class PathDirectivesSpec extends RoutingSpec with Inside {
"accept [/] and clear the unmatchedPath" in test("")
}

"""path(Map("a" → 1, "aa" → 2))""" should {
val test = testFor(path(Map("a" 1, "aa" 2)) { echoCaptureAndUnmatchedPath })
"accept [/a]" inThe test("1:")
"accept [/aa]" inThe test("2:")
"reject [/aaa]" inThe test()
}

"""path(Map("sv_SE" → 3, "sv" → 1, "sv_FI" → 2))""" should {
val test = testFor(path(Map("sv_SE" 3, "sv" 1, "sv_FI" 2)) { echoCaptureAndUnmatchedPath })
"accept [/sv]" inThe test("1:")
"accept [/sv_FI]" inThe test("2:")
"accept [/sv_SE]" inThe test("3:")
"reject [/sv_DK]" inThe test()
}

"""path(Map("a" -> 1, "ab" -> 2, "ba" -> 3, "b" -> 4, "c" -> 5, "d" -> 6, "da" -> 7))""" should {
val test = testFor(path(Map("a" 1, "ab" 2, "ba" 3, "b" 4, "c" 5, "d" 6, "da" 7)) { echoCaptureAndUnmatchedPath })
"accept [/a]" inThe test("1:")
"accept [/ab]" inThe test("2:") // FAIL
"accept [/ba]" inThe test("3:")
"accept [/b]" inThe test("4:")
"accept [/c]" inThe test("5:")
"accept [/d]" inThe test("6:")
"accept [/da]" inThe test("7:")
"reject [/e]" inThe test()
"reject [/ac]" inThe test()
}

"""path(ListMap("a" -> 1, "ab" -> 2, "ba" -> 3, "b" -> 4, "c" -> 5, "d" -> 6, "da" -> 7))""" should {
val test = testFor(path(ListMap("a" 1, "ab" 2, "ba" 3, "b" 4, "c" 5, "d" 6, "da" 7)) { echoCaptureAndUnmatchedPath })
"accept [/a]" inThe test("1:")
"accept [/ab]" inThe test("2:")
"accept [/ba]" inThe test("3:")
"accept [/b]" inThe test("4:")
"accept [/c]" inThe test("5:")
"accept [/d]" inThe test("6:")
"accept [/da]" inThe test("7:")
"reject [/e]" inThe test()
"reject [/ac]" inThe test()
}

"""path(ListMap("a" -> 1, "aa" -> 2, "bb" -> 3, "b" -> 4, "c" -> 5, "d" -> 6, "dd" -> 7))""" should {
val test = testFor(path(ListMap("a" 1, "aa" 2, "bb" 3, "b" 4, "c" 5, "d" 6, "dd" 7)) { echoCaptureAndUnmatchedPath })
"accept [/a]" inThe test("1:")
"accept [/aa]" inThe test("2:")
"accept [/bb]" inThe test("3:")
"accept [/b]" inThe test("4:")
"accept [/c]" inThe test("5:")
"accept [/d]" inThe test("6:")
"accept [/dd]" inThe test("7:")
"reject [/e]" inThe test()
"reject [/ac]" inThe test()
}

"""path(Map("a" -> 1, "aa" -> 2, "bb" -> 3, "b" -> 4, "c" -> 5, "d" -> 6, "dd" -> 7))""" should {
val test = testFor(path(Map("a" 1, "aa" 2, "bb" 3, "b" 4, "c" 5, "d" 6, "dd" 7)) { echoCaptureAndUnmatchedPath })
"accept [/a]" inThe test("1:")
"accept [/aa]" inThe test("2:")
"accept [/bb]" inThe test("3:")
"accept [/b]" inThe test("4:")
"accept [/c]" inThe test("5:")
"accept [/d]" inThe test("6:")
"accept [/dd]" inThe test("7:")
"reject [/e]" inThe test()
"reject [/ac]" inThe test()
}

"""pathPrefix("foo")""" should {
val test = testFor(pathPrefix("foo") { echoUnmatchedPath })
"reject [/bar]" inThe test()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -289,12 +289,13 @@ trait ImplicitPathMatcherConstruction {
* Creates a PathMatcher from the given Map of path segments (prefixes) to extracted values.
* If the unmatched path starts with a segment having one of the maps keys as a prefix
* the matcher consumes this path segment (prefix) and extracts the corresponding map value.
* For keys sharing a common prefix the longest matching prefix is selected.
*
* @group pathmatcherimpl
*/
implicit def _valueMap2PathMatcher[T](valueMap: Map[String, T]): PathMatcher1[T] =
if (valueMap.isEmpty) PathMatchers.nothingMatcher
else valueMap.map { case (prefix, value) _stringExtractionPair2PathMatcher((prefix, value)) }.reduceLeft(_ | _)
else valueMap.toSeq.sortWith(_._1 > _._1).map(_stringExtractionPair2PathMatcher).reduceLeft(_ | _)
}

/**
Expand Down

0 comments on commit 47a0321

Please sign in to comment.