Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7eaa2b6b authored by Ricki Hirner's avatar Ricki Hirner
Browse files

Don't follow redirects from HTTPS to HTTP

parent 5abed623
Loading
Loading
Loading
Loading
+1 −1
Original line number Original line Diff line number Diff line
@@ -2,7 +2,7 @@ import org.jetbrains.dokka.gradle.DokkaTask


object Libs {
object Libs {
    // okhttp HTTP library
    // okhttp HTTP library
    const val okhttpVersion = "4.7.2"
    const val okhttpVersion = "4.8.0"


    // XmlPullParser library
    // XmlPullParser library
    const val xpp3Version = "1.1.6"
    const val xpp3Version = "1.1.6"
+15 −4
Original line number Original line Diff line number Diff line
@@ -82,6 +82,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class)
    @Throws(IOException::class, HttpException::class)
    fun options(callback: (davCapabilities: Set<String>, response: Response) -> Unit) {
    fun options(callback: (davCapabilities: Set<String>, response: Response) -> Unit) {
@@ -104,7 +105,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on WebDAV error
     * @throws DavException on WebDAV error or HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class, DavException::class)
    @Throws(IOException::class, HttpException::class, DavException::class)
    fun move(destination: HttpUrl, forceOverride: Boolean, callback: (response: Response) -> Unit) {
    fun move(destination: HttpUrl, forceOverride: Boolean, callback: (response: Response) -> Unit) {
@@ -145,7 +146,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on WebDAV error
     * @throws DavException on WebDAV error or HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class, DavException::class)
    @Throws(IOException::class, HttpException::class, DavException::class)
    fun copy(destination:HttpUrl, forceOverride:Boolean, callback: (response: Response) -> Unit) {
    fun copy(destination:HttpUrl, forceOverride:Boolean, callback: (response: Response) -> Unit) {
@@ -179,6 +180,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class)
    @Throws(IOException::class, HttpException::class)
    fun mkCol(xmlBody: String?, callback: (response: Response) -> Unit) {
    fun mkCol(xmlBody: String?, callback: (response: Response) -> Unit) {
@@ -206,6 +208,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class)
    @Throws(IOException::class, HttpException::class)
    fun get(accept: String, callback: (response: Response) -> Unit) {
    fun get(accept: String, callback: (response: Response) -> Unit) {
@@ -235,6 +238,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class)
    @Throws(IOException::class, HttpException::class)
    fun put(body: RequestBody, ifETag: String? = null, ifScheduleTag: String? = null, ifNoneMatch: Boolean = false, callback: (Response) -> Unit) {
    fun put(body: RequestBody, ifETag: String? = null, ifScheduleTag: String? = null, ifNoneMatch: Boolean = false, callback: (Response) -> Unit) {
@@ -273,6 +277,7 @@ open class DavResource @JvmOverloads constructor(
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP errors, or when 207 Multi-Status is returned
     * @throws HttpException on HTTP errors, or when 207 Multi-Status is returned
     *         (because then there was probably a problem with a member resource)
     *         (because then there was probably a problem with a member resource)
     * @throws DavException on HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class)
    @Throws(IOException::class, HttpException::class)
    fun delete(ifETag: String? = null, ifScheduleTag: String? = null, callback: (Response) -> Unit) {
    fun delete(ifETag: String? = null, ifScheduleTag: String? = null, callback: (Response) -> Unit) {
@@ -310,7 +315,7 @@ open class DavResource @JvmOverloads constructor(
     *
     *
     * @throws IOException on I/O error
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws HttpException on HTTP error
     * @throws DavException on WebDAV error (like no 207 Multi-Status response)
     * @throws DavException on WebDAV error (like no 207 Multi-Status response) or HTTPS -> HTTP redirect
     */
     */
    @Throws(IOException::class, HttpException::class, DavException::class)
    @Throws(IOException::class, HttpException::class, DavException::class)
    fun propfind(depth: Int, vararg reqProp: Property.Name, callback: DavResponseCallback) {
    fun propfind(depth: Int, vararg reqProp: Property.Name, callback: DavResponseCallback) {
@@ -386,8 +391,10 @@ open class DavResource @JvmOverloads constructor(
     * @param sendRequest called to send the request (may be called multiple times)
     * @param sendRequest called to send the request (may be called multiple times)
     *
     *
     * @return response of the last request (whether it is a redirect or not)
     * @return response of the last request (whether it is a redirect or not)
     *
     * @throws DavException on HTTPS -> HTTP redirect
     */
     */
    protected fun followRedirects(sendRequest: () -> Response): Response {
    internal fun followRedirects(sendRequest: () -> Response): Response {
        lateinit var response: Response
        lateinit var response: Response
        for (attempt in 1..MAX_REDIRECTS) {
        for (attempt in 1..MAX_REDIRECTS) {
            response = sendRequest()
            response = sendRequest()
@@ -397,6 +404,10 @@ open class DavResource @JvmOverloads constructor(
                    val target = it.header("Location")?.let { location.resolve(it) }
                    val target = it.header("Location")?.let { location.resolve(it) }
                    if (target != null) {
                    if (target != null) {
                        log.fine("Redirected, new location = $target")
                        log.fine("Redirected, new location = $target")

                        if (location.isHttps && !target.isHttps)
                            throw DavException("Received redirect from HTTPS to HTTP")

                        location = target
                        location = target
                    } else
                    } else
                        throw DavException("Redirected without new Location")
                        throw DavException("Redirected without new Location")
+57 −0
Original line number Original line Diff line number Diff line
@@ -13,9 +13,13 @@ import at.bitfire.dav4jvm.property.DisplayName
import at.bitfire.dav4jvm.property.GetContentType
import at.bitfire.dav4jvm.property.GetContentType
import at.bitfire.dav4jvm.property.GetETag
import at.bitfire.dav4jvm.property.GetETag
import at.bitfire.dav4jvm.property.ResourceType
import at.bitfire.dav4jvm.property.ResourceType
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.OkHttpClient
import okhttp3.Protocol
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.ResponseBody.Companion.toResponseBody
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockResponse
import okhttp3.mockwebserver.MockWebServer
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.After
@@ -722,4 +726,57 @@ class DavResourceTest {
        assertTrue(called)
        assertTrue(called)
    }
    }



    @Test
    fun testFollowRedirects_302() {
        val url = sampleUrl()
        val dav = DavResource(httpClient, url)
        var i = 0
        dav.followRedirects {
            if (i++ == 0)
                okhttp3.Response.Builder()
                        .protocol(Protocol.HTTP_1_1)
                        .code(302)
                        .message("Found")
                        .header("Location", "http://to.com/")
                        .request(Request.Builder()
                                .get()
                                .url("http://from.com/")
                                .build())
                        .body("New location!".toResponseBody())
                        .build()
            else
                okhttp3.Response.Builder()
                        .protocol(Protocol.HTTP_1_1)
                        .code(204)
                        .message("No Content")
                        .request(Request.Builder()
                                .get()
                                .url("http://to.com/")
                                .build())
                        .build()
        }.let { response ->
            assertEquals(204, response.code)
            assertEquals("http://to.com/".toHttpUrl(), dav.location)
        }
    }

    @Test(expected = DavException::class)
    fun testFollowRedirects_HttpsToHttp() {
        val dav = DavResource(httpClient, "https://from.com".toHttpUrl())
        dav.followRedirects {
            okhttp3.Response.Builder()
                    .protocol(Protocol.HTTP_1_1)
                    .code(302)
                    .message("Found")
                    .header("Location", "http://to.com/")
                    .request(Request.Builder()
                            .get()
                            .url("https://from.com/")
                            .build())
                    .body("New location!".toResponseBody())
                    .build()
        }
    }

}
}