Skip to content
This repository has been archived by the owner on Jun 20, 2023. It is now read-only.

Commit

Permalink
Complex HTTP Errors (#213)
Browse files Browse the repository at this point in the history
* Complex HTTP Errors

Signed-off-by: d067928 <jakob.moeller@sap.com>

* Correct Boolean Logic for Client/Server Error Check

Signed-off-by: d067928 <jakob.moeller@sap.com>

* Moved error handling of submission flow to CwaWebExceptions (#220)

Co-authored-by: Kolya Opahle <k.opahle@sap.com>
  • Loading branch information
Jakob Möller and kolyaopahle committed Jun 6, 2020
1 parent 56e35c7 commit 16f016a
Show file tree
Hide file tree
Showing 15 changed files with 231 additions and 201 deletions.
14 changes: 11 additions & 3 deletions Corona-Warn-App/config/detekt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ complexity:
active: true
threshold: 15
ignoreSingleWhenExpression: false
ignoreSimpleWhenEntries: false
ignoreSimpleWhenEntries: true
ignoreNestingFunctions: false
nestingFunctions: [run, let, apply, with, also, use, forEach, isNotNull, ifNull]
LabeledExpression:
Expand Down Expand Up @@ -514,7 +514,15 @@ style:
maxJumpCount: 1
MagicNumber:
active: true
excludes: ['**/test/**', '**/androidTest/**', '**/*.Test.kt', '**/*.Spec.kt', '**/*.Spek.kt']
excludes: [
'**/test/**',
'**/androidTest/**',
'**/*.Test.kt',
'**/*.Spec.kt',
'**/*.Spek.kt',
'**/CwaWebException.kt',
'**/HttpErrorParser.kt'
]
ignoreNumbers: ['-1', '0', '1', '2']
ignoreHashCodeFunction: true
ignorePropertyDeclaration: false
Expand All @@ -523,7 +531,7 @@ style:
ignoreCompanionObjectPropertyDeclaration: true
ignoreAnnotation: false
ignoreNamedArgument: true
ignoreEnums: false
ignoreEnums: true
ignoreRanges: false
MandatoryBracesIfStatements:
active: false
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package de.rki.coronawarnapp.exception.http

import java.io.IOException

open class CwaWebException(statusCode: Int) : IOException(
"error during web request, http status $statusCode"
)

open class CwaServerError(val statusCode: Int) : CwaWebException(statusCode) {
init {
if (statusCode !in 500..599)
throw IllegalArgumentException("a server error has to have code 5xx")
}
}

open class CwaClientError(val statusCode: Int) : CwaWebException(statusCode) {
init {
if (statusCode !in 400..499)
throw IllegalArgumentException("a client error has to have code 4xx")
}
}

open class CwaSuccessResponseWithCodeMismatchNotSupportedError(val statusCode: Int) : CwaWebException(statusCode)
open class CwaInformationalNotSupportedError(val statusCode: Int) : CwaWebException(statusCode)
open class CwaRedirectNotSupportedError(val statusCode: Int) : CwaWebException(statusCode)

class BadRequestException : CwaClientError(400)
class UnauthorizedException : CwaClientError(401)
class ForbiddenException : CwaClientError(403)
class NotFoundException : CwaClientError(404)
class ConflictException : CwaClientError(409)
class GoneException : CwaClientError(410)
class UnsupportedMediaTypeException : CwaClientError(415)
class TooManyRequestsException : CwaClientError(429)

class InternalServerErrorException : CwaServerError(500)
class NotImplementedException : CwaServerError(501)
class BadGatewayException : CwaServerError(502)
class ServiceUnavailableException : CwaServerError(503)
class GatewayTimeoutException : CwaServerError(504)
class HTTPVersionNotSupported : CwaServerError(505)
class NetworkAuthenticationRequiredException : CwaServerError(511)
class NetworkReadTimeoutException : CwaServerError(598)
class NetworkConnectTimeoutException : CwaServerError(599)
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package de.rki.coronawarnapp.http

import de.rki.coronawarnapp.exception.http.BadGatewayException
import de.rki.coronawarnapp.exception.http.CwaWebException
import de.rki.coronawarnapp.exception.http.BadRequestException
import de.rki.coronawarnapp.exception.http.ConflictException
import de.rki.coronawarnapp.exception.http.CwaClientError
import de.rki.coronawarnapp.exception.http.CwaInformationalNotSupportedError
import de.rki.coronawarnapp.exception.http.CwaRedirectNotSupportedError
import de.rki.coronawarnapp.exception.http.CwaServerError
import de.rki.coronawarnapp.exception.http.CwaSuccessResponseWithCodeMismatchNotSupportedError
import de.rki.coronawarnapp.exception.http.ForbiddenException
import de.rki.coronawarnapp.exception.http.GatewayTimeoutException
import de.rki.coronawarnapp.exception.http.GoneException
import de.rki.coronawarnapp.exception.http.HTTPVersionNotSupported
import de.rki.coronawarnapp.exception.http.InternalServerErrorException
import de.rki.coronawarnapp.exception.http.NetworkAuthenticationRequiredException
import de.rki.coronawarnapp.exception.http.NetworkConnectTimeoutException
import de.rki.coronawarnapp.exception.http.NetworkReadTimeoutException
import de.rki.coronawarnapp.exception.http.NotFoundException
import de.rki.coronawarnapp.exception.http.NotImplementedException
import de.rki.coronawarnapp.exception.http.ServiceUnavailableException
import de.rki.coronawarnapp.exception.http.TooManyRequestsException
import de.rki.coronawarnapp.exception.http.UnauthorizedException
import de.rki.coronawarnapp.exception.http.UnsupportedMediaTypeException
import okhttp3.Interceptor
import okhttp3.Response

class HttpErrorParser : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
return when (val code = response.code) {
200 -> response
201 -> response
202 -> response
204 -> response
400 -> throw BadRequestException()
401 -> throw UnauthorizedException()
403 -> throw ForbiddenException()
404 -> throw NotFoundException()
409 -> throw ConflictException()
410 -> throw GoneException()
415 -> throw UnsupportedMediaTypeException()
429 -> throw TooManyRequestsException()
500 -> throw InternalServerErrorException()
501 -> throw NotImplementedException()
502 -> throw BadGatewayException()
503 -> throw ServiceUnavailableException()
504 -> throw GatewayTimeoutException()
505 -> throw HTTPVersionNotSupported()
511 -> throw NetworkAuthenticationRequiredException()
598 -> throw NetworkReadTimeoutException()
599 -> throw NetworkConnectTimeoutException()
else -> {
if (code in 100..199) throw CwaInformationalNotSupportedError(code)
if (code in 200..299) throw CwaSuccessResponseWithCodeMismatchNotSupportedError(code)
if (code in 300..399) throw CwaRedirectNotSupportedError(code)
if (code in 400..499) throw CwaClientError(code)
if (code in 500..599) throw CwaServerError(code)
throw CwaWebException(code)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class ServiceFactory {
if (BuildConfig.DEBUG) it.setLevel(HttpLoggingInterceptor.Level.BODY)
},
OfflineCacheInterceptor(CoronaWarnApplication.getAppContext()),
RetryInterceptor()
RetryInterceptor(),
HttpErrorParser()
)

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ import KeyExportFormat
import android.util.Log
import de.rki.coronawarnapp.exception.DiagnosisKeyRetrievalException
import de.rki.coronawarnapp.exception.DiagnosisKeySubmissionException
import de.rki.coronawarnapp.exception.SubmissionTanInvalidException
import de.rki.coronawarnapp.http.WebRequestBuilder
import de.rki.coronawarnapp.service.diagnosiskey.DiagnosisKeyConstants.SERVER_ERROR_CODE_403
import retrofit2.HttpException

/**
* The Diagnosis Key Service is used to interact with the Server to submit and retrieve keys through
Expand All @@ -50,21 +47,11 @@ object DiagnosisKeyService {
* @param keysToReport - KeyList in the Server Format to submit to the Server
*/
suspend fun asyncSubmitKeys(authCode: String, keysToReport: List<KeyExportFormat.TemporaryExposureKey>) {
try {
Log.d(TAG, "Diagnosis Keys will be submitted.")
WebRequestBuilder.asyncSubmitKeysToServer(
authCode,
false,
keysToReport
)
} catch (e: HttpException) {
if (e.code() == SERVER_ERROR_CODE_403) {
throw SubmissionTanInvalidException(
"the test paring to the device is invalid",
e
)
}
throw e
}
Log.d(TAG, "Diagnosis Keys will be submitted.")
WebRequestBuilder.asyncSubmitKeysToServer(
authCode,
false,
keysToReport
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,24 @@ package de.rki.coronawarnapp.service.submission

import de.rki.coronawarnapp.exception.NoGUIDOrTANSetException
import de.rki.coronawarnapp.exception.NoRegistrationTokenSetException
import de.rki.coronawarnapp.exception.TestAlreadyPairedException
import de.rki.coronawarnapp.exception.TestPairingInvalidException
import de.rki.coronawarnapp.http.WebRequestBuilder
import de.rki.coronawarnapp.service.submission.SubmissionConstants.QR_CODE_KEY_TYPE
import de.rki.coronawarnapp.service.submission.SubmissionConstants.SERVER_ERROR_CODE_400
import de.rki.coronawarnapp.service.submission.SubmissionConstants.TELE_TAN_KEY_TYPE
import de.rki.coronawarnapp.storage.LocalData
import de.rki.coronawarnapp.transaction.SubmitDiagnosisKeysTransaction
import de.rki.coronawarnapp.util.formatter.TestResult
import retrofit2.HttpException

object SubmissionService {
suspend fun asyncRegisterDevice() {
try {
val testGUID = LocalData.testGUID()
val testTAN = LocalData.teletan()

when {
testGUID != null -> asyncRegisterDeviceViaGUID(testGUID)
testTAN != null -> asyncRegisterDeviceViaTAN(testTAN)
else -> throw NoGUIDOrTANSetException()
}
LocalData.devicePairingSuccessfulTimestamp(System.currentTimeMillis())
} catch (err: HttpException) {
if (err.code() == SERVER_ERROR_CODE_400) {
throw TestAlreadyPairedException(
"the test was already paired to a different device",
err
)
}
throw err
val testGUID = LocalData.testGUID()
val testTAN = LocalData.teletan()

when {
testGUID != null -> asyncRegisterDeviceViaGUID(testGUID)
testTAN != null -> asyncRegisterDeviceViaTAN(testTAN)
else -> throw NoGUIDOrTANSetException()
}
LocalData.devicePairingSuccessfulTimestamp(System.currentTimeMillis())
}

private suspend fun asyncRegisterDeviceViaGUID(guid: String) {
Expand All @@ -59,17 +45,7 @@ object SubmissionService {
}

suspend fun asyncRequestAuthCode(registrationToken: String): String {
try {
return WebRequestBuilder.asyncGetTan(registrationToken)
} catch (err: HttpException) {
if (err.code() == SERVER_ERROR_CODE_400) {
throw TestPairingInvalidException(
"the test paring to the device is invalid",
err
)
}
throw err
}
return WebRequestBuilder.asyncGetTan(registrationToken)
}

suspend fun asyncSubmitExposureKeys() {
Expand Down
Loading

0 comments on commit 16f016a

Please sign in to comment.