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 Diff line number Diff line
@@ -2,7 +2,7 @@ import org.jetbrains.dokka.gradle.DokkaTask

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

    // XmlPullParser library
    const val xpp3Version = "1.1.6"
+15 −4
Original line number Diff line number Diff line
@@ -82,6 +82,7 @@ open class DavResource @JvmOverloads constructor(
     *
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
    @Throws(IOException::class, HttpException::class)
    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 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)
    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 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)
    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 HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
    @Throws(IOException::class, HttpException::class)
    fun mkCol(xmlBody: String?, callback: (response: Response) -> Unit) {
@@ -206,6 +208,7 @@ open class DavResource @JvmOverloads constructor(
     *
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
    @Throws(IOException::class, HttpException::class)
    fun get(accept: String, callback: (response: Response) -> Unit) {
@@ -235,6 +238,7 @@ open class DavResource @JvmOverloads constructor(
     *
     * @throws IOException on I/O error
     * @throws HttpException on HTTP error
     * @throws DavException on HTTPS -> HTTP redirect
     */
    @Throws(IOException::class, HttpException::class)
    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 HttpException on HTTP errors, or when 207 Multi-Status is returned
     *         (because then there was probably a problem with a member resource)
     * @throws DavException on HTTPS -> HTTP redirect
     */
    @Throws(IOException::class, HttpException::class)
    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 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)
    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)
     *
     * @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
        for (attempt in 1..MAX_REDIRECTS) {
            response = sendRequest()
@@ -397,6 +404,10 @@ open class DavResource @JvmOverloads constructor(
                    val target = it.header("Location")?.let { location.resolve(it) }
                    if (target != null) {
                        log.fine("Redirected, new location = $target")

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

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

}