aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authoradamw <adam@warski.org>2017-08-31 12:26:46 +0200
committeradamw <adam@warski.org>2017-08-31 12:26:46 +0200
commit5bc89ddefab16dd814d0b716a72490451b697b32 (patch)
tree30d907effc67ce976af5cd01dd4c6ef4d1bc6242 /core
parent1fab77128b7ebd8a7f14d8e02c801b1fb6e28046 (diff)
downloadsttp-5bc89ddefab16dd814d0b716a72490451b697b32.tar.gz
sttp-5bc89ddefab16dd814d0b716a72490451b697b32.tar.bz2
sttp-5bc89ddefab16dd814d0b716a72490451b697b32.zip
Follow-redirect support
Diffstat (limited to 'core')
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala5
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/RequestT.scala8
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/SttpHandler.scala36
-rw-r--r--core/src/main/scala/com/softwaremill/sttp/package.scala8
4 files changed, 53 insertions, 4 deletions
diff --git a/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala b/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala
index 76d897b..548dd9b 100644
--- a/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/HttpURLConnectionHandler.scala
@@ -13,13 +13,16 @@ import scala.io.Source
import scala.collection.JavaConverters._
object HttpURLConnectionHandler extends SttpHandler[Id, Nothing] {
- override def send[T](r: Request[T, Nothing]): Response[T] = {
+ override protected def doSend[T](r: Request[T, Nothing]): Response[T] = {
val c =
new URL(r.uri.toString).openConnection().asInstanceOf[HttpURLConnection]
c.setRequestMethod(r.method.m)
r.headers.foreach { case (k, v) => c.setRequestProperty(k, v) }
c.setDoInput(true)
+ // redirects are handled in SttpHandler
+ c.setInstanceFollowRedirects(false)
+
if (r.body != NoBody) {
c.setDoOutput(true)
// we need to take care to:
diff --git a/core/src/main/scala/com/softwaremill/sttp/RequestT.scala b/core/src/main/scala/com/softwaremill/sttp/RequestT.scala
index 5e4d33e..95dc56b 100644
--- a/core/src/main/scala/com/softwaremill/sttp/RequestT.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/RequestT.scala
@@ -31,7 +31,8 @@ case class RequestT[U[_], T, +S](
uri: U[Uri],
body: RequestBody[S],
headers: Seq[(String, String)],
- response: ResponseAs[T, S]
+ response: ResponseAs[T, S],
+ options: RequestOptions
) {
def get(uri: Uri): Request[T, S] =
this.copy[Id, T, S](uri = uri, method = Method.GET)
@@ -218,6 +219,9 @@ case class RequestT[U[_], T, +S](
def mapResponse[T2](f: T => T2): RequestT[U, T2, S] =
this.copy(response = response.map(f))
+ def followRedirects(fr: Boolean): RequestT[U, T, S] =
+ this.copy(options = options.copy(followRedirects = fr))
+
def send[R[_]]()(implicit handler: SttpHandler[R, S],
isIdInRequest: IsIdInRequest[U]): R[Response[T]] = {
// we could avoid the asInstanceOf by creating an artificial copy
@@ -268,3 +272,5 @@ class SpecifyAuthScheme[U[_], T, +S](hn: String, rt: RequestT[U, T, S]) {
def bearer(token: String): RequestT[U, T, S] =
rt.header(hn, s"Bearer $token")
}
+
+case class RequestOptions(followRedirects: Boolean)
diff --git a/core/src/main/scala/com/softwaremill/sttp/SttpHandler.scala b/core/src/main/scala/com/softwaremill/sttp/SttpHandler.scala
index c6df151..fd836bd 100644
--- a/core/src/main/scala/com/softwaremill/sttp/SttpHandler.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/SttpHandler.scala
@@ -1,5 +1,7 @@
package com.softwaremill.sttp
+import java.net.URI
+
import scala.language.higherKinds
/**
@@ -9,9 +11,41 @@ import scala.language.higherKinds
* if streaming requests/responses is not supported by this handler.
*/
trait SttpHandler[R[_], -S] {
- def send[T](request: Request[T, S]): R[Response[T]]
+ def send[T](request: Request[T, S]): R[Response[T]] = {
+ val resp = doSend(request)
+ if (request.options.followRedirects) {
+ responseMonad.flatMap(resp, { response: Response[T] =>
+ if (response.isRedirect) {
+ followRedirect(request, response)
+ } else {
+ responseMonad.unit(response)
+ }
+ })
+ } else {
+ resp
+ }
+ }
+
+ private def followRedirect[T](request: Request[T, S],
+ response: Response[T]): R[Response[T]] = {
+ def isRelative(uri: String) = !uri.contains("://")
+
+ response.header(LocationHeader).fold(responseMonad.unit(response)) { loc =>
+ val uri = if (isRelative(loc)) {
+ // using java's URI to resolve a relative URI
+ uri"${new URI(request.uri.toString).resolve(loc).toString}"
+ } else {
+ uri"$loc"
+ }
+
+ send(request.copy[Id, T, S](uri = uri))
+ }
+ }
+
def close(): Unit = {}
+ protected def doSend[T](request: Request[T, S]): R[Response[T]]
+
/**
* The monad in which the responses are wrapped. Allows writing wrapper
* handlers, which map/flatMap over the return value of [[send]].
diff --git a/core/src/main/scala/com/softwaremill/sttp/package.scala b/core/src/main/scala/com/softwaremill/sttp/package.scala
index a0a6c57..3c4e844 100644
--- a/core/src/main/scala/com/softwaremill/sttp/package.scala
+++ b/core/src/main/scala/com/softwaremill/sttp/package.scala
@@ -37,6 +37,7 @@ package object sttp {
private[sttp] val AcceptEncodingHeader = "Accept-Encoding"
private[sttp] val ContentEncodingHeader = "Content-Encoding"
private[sttp] val ContentDispositionHeader = "Content-Disposition"
+ private[sttp] val LocationHeader = "Location"
private[sttp] val Utf8 = "utf-8"
private[sttp] val Iso88591 = "iso-8859-1"
private[sttp] val CrLf = "\r\n"
@@ -54,7 +55,12 @@ package object sttp {
* An empty request with no headers.
*/
val emptyRequest: RequestT[Empty, String, Nothing] =
- RequestT[Empty, String, Nothing](None, None, NoBody, Vector(), asString)
+ RequestT[Empty, String, Nothing](None,
+ None,
+ NoBody,
+ Vector(),
+ asString,
+ RequestOptions(followRedirects = true))
/**
* A starting request, with the following modifications comparing to