summaryrefslogtreecommitdiff
path: root/cashier/src/main/java/net/taler/cashier/HttpHelper.kt
blob: 49a43d1bbf143518143728ae5a3d8d5a2a2d6eb9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/*
 * This file is part of GNU Taler
 * (C) 2020 Taler Systems S.A.
 *
 * GNU Taler is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 3, or (at your option) any later version.
 *
 * GNU Taler is distributed in the hope that it will be useful, but WITHOUT ANY
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
 * A PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with
 * GNU Taler; see the file COPYING.  If not, see <http://www.gnu.org/licenses/>
 */

package net.taler.cashier

import android.util.Log
import androidx.annotation.WorkerThread
import okhttp3.Credentials
import okhttp3.MediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody
import okhttp3.Response
import org.json.JSONException
import org.json.JSONObject

object HttpHelper {

    private val TAG = HttpHelper::class.java.simpleName
    private const val MIME_TYPE_JSON = "application/json"

    @WorkerThread
    fun makeJsonGetRequest(url: String, config: Config): HttpJsonResult {
        val request = Request.Builder()
            .addHeader("Accept", MIME_TYPE_JSON)
            .url(url)
            .get()
            .build()
        val response = try {
            getHttpClient(config.username, config.password)
                .newCall(request)
                .execute()
        } catch (e: Exception) {
            Log.e(TAG, "Error retrieving $url", e)
            return HttpJsonResult.Error(0)
        }
        return if (response.code() == 200 && response.body() != null) {
            val jsonObject = JSONObject(response.body()!!.string())
            HttpJsonResult.Success(jsonObject)
        } else {
            Log.e(TAG, "Received status ${response.code()} from $url expected 200")
            HttpJsonResult.Error(response.code(), getErrorBody(response))
        }
    }

    private val MEDIA_TYPE_JSON = MediaType.parse("$MIME_TYPE_JSON; charset=utf-8")

    @WorkerThread
    fun makeJsonPostRequest(url: String, body: JSONObject, config: Config): HttpJsonResult {
        val request = Request.Builder()
            .addHeader("Accept", MIME_TYPE_JSON)
            .url(url)
            .post(RequestBody.create(MEDIA_TYPE_JSON, body.toString()))
            .build()
        val response = try {
            getHttpClient(config.username, config.password)
                .newCall(request)
                .execute()
        } catch (e: Exception) {
            Log.e(TAG, "Error retrieving $url", e)
            return HttpJsonResult.Error(0)
        }
        return if (response.code() == 200 && response.body() != null) {
            val jsonObject = JSONObject(response.body()!!.string())
            HttpJsonResult.Success(jsonObject)
        } else {
            Log.e(TAG, "Received status ${response.code()} from $url expected 200")
            HttpJsonResult.Error(response.code(), getErrorBody(response))
        }
    }

    private fun getHttpClient(username: String, password: String) =
        OkHttpClient.Builder().authenticator { _, response ->
            val credential = Credentials.basic(username, password)
            if (credential == response.request().header("Authorization")) {
                // If we already failed with these credentials, don't retry
                return@authenticator null
            }
            response
                .request()
                .newBuilder()
                .header("Authorization", credential)
                .build()
        }.build()

    private fun getErrorBody(response: Response): String? {
        val body = response.body()?.string() ?: return null
        Log.e(TAG, "Response body: $body")
        return try {
            val json = JSONObject(body)
            "${json.optString("ec")} ${json.optString("error")}"
        } catch (e: JSONException) {
            null
        }
    }

}

sealed class HttpJsonResult {
    class Error(val statusCode: Int, private val errorMsg: String? = null) : HttpJsonResult() {
        val msg: String
            get() = errorMsg?.let { "\n\n$statusCode $it" } ?: ": $statusCode"
    }

    class Success(val json: JSONObject) : HttpJsonResult()
}