Skip to content
This repository has been archived by the owner on Apr 24, 2024. It is now read-only.

Commit

Permalink
! routing: fix getFromDirectory and getFromResourceDirectory not …
Browse files Browse the repository at this point in the history
…working properly for URIs with encoded chars

Previously the unmatched path of the request context was directly used for retrieving the file/resource content. If the path contains non-token chars that need to be encoded this results in file system/resource accesses to something like `foo%20bar.txt` instead of `foo bar.txt`. This patch fixes this problem.

The "breakingness" of this patch results from marking two internal methods private that were previously (and erroneously) public.
  • Loading branch information
sirthias committed Sep 10, 2013
1 parent d255cf7 commit ab35761
Showing 1 changed file with 25 additions and 4 deletions.
Expand Up @@ -19,6 +19,7 @@ package directives

import java.io.File
import org.parboiled.common.FileUtils
import scala.annotation.tailrec
import akka.actor.ActorRefFactory
import spray.httpx.marshalling.{ Marshaller, BasicMarshallers }
import spray.util._
Expand Down Expand Up @@ -131,7 +132,10 @@ trait FileAndResourceDirectives {
refFactory: ActorRefFactory, log: LoggingContext): Route = {
val base = withTrailingSlash(directoryName)
unmatchedPath { path
getFromFile(base + stripLeadingSlash(path))
fileSystemPath(base, path) match {
case "" reject
case fileName getFromFile(fileName)
}
}
}

Expand Down Expand Up @@ -183,14 +187,31 @@ trait FileAndResourceDirectives {
refFactory: ActorRefFactory, log: LoggingContext): Route = {
val base = if (directoryName.isEmpty) "" else withTrailingSlash(directoryName)
unmatchedPath { path
getFromResource(base + stripLeadingSlash(path).toString)
fileSystemPath(base, path, separator = '/') match {
case "" reject
case resourceName getFromResource(resourceName)
}
}
}
}

object FileAndResourceDirectives extends FileAndResourceDirectives {
def stripLeadingSlash(path: Uri.Path) = if (path.startsWithSlash) path.tail else path
def withTrailingSlash(path: String) = if (path endsWith "/") path else path + '/'
private def withTrailingSlash(path: String): String = if (path endsWith "/") path else path + '/'
private def fileSystemPath(base: String, path: Uri.Path, separator: Char = File.separatorChar)(implicit log: LoggingContext): String = {
import java.lang.StringBuilder
@tailrec def rec(p: Uri.Path, result: StringBuilder = new StringBuilder(base)): String =
p match {
case Uri.Path.Empty result.toString
case Uri.Path.Slash(tail) rec(tail, result.append(separator))
case Uri.Path.Segment(head, tail)
if (head.indexOf('/') >= 0 || head == "..") {
log.warning("File-system path for base [{}] and Uri.Path [{}] contains suspicious path segment [{}], " +
"GET access was disallowed", base, path, head)
""
} else rec(tail, result.append(head))
}
rec(if (path.startsWithSlash) path.tail else path)
}
}

trait ContentTypeResolver {
Expand Down

0 comments on commit ab35761

Please sign in to comment.