From f9594e9dc3cf0eec8c849544f70798dfba1e1487 Mon Sep 17 00:00:00 2001 From: "Erik C. Thauvin" Date: Mon, 3 Jan 2022 12:47:53 -0800 Subject: [PATCH] API URL must not be null. --- .../net/thauvin/erik/akismet/Akismet.kt | 76 +++++++++---------- .../thauvin/erik/akismet/AkismetComment.kt | 7 +- .../net/thauvin/erik/akismet/AkismetTest.kt | 43 +++++------ 3 files changed, 59 insertions(+), 67 deletions(-) diff --git a/src/main/kotlin/net/thauvin/erik/akismet/Akismet.kt b/src/main/kotlin/net/thauvin/erik/akismet/Akismet.kt index 8c69c65..becf783 100644 --- a/src/main/kotlin/net/thauvin/erik/akismet/Akismet.kt +++ b/src/main/kotlin/net/thauvin/erik/akismet/Akismet.kt @@ -35,7 +35,7 @@ import kotlinx.serialization.json.Json import net.thauvin.erik.semver.Version import okhttp3.FormBody import okhttp3.HttpUrl -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.OkHttpClient import okhttp3.Request import okhttp3.logging.HttpLoggingInterceptor @@ -45,7 +45,7 @@ import java.time.OffsetDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter import java.time.temporal.ChronoUnit -import java.util.* +import java.util.Date import java.util.logging.Level import java.util.logging.Logger @@ -206,8 +206,8 @@ open class Akismet(apiKey: String) { init { require( (apiKey.isNotBlank() && - apiKey.length == 12 && - apiKey.matches(Regex("[A-Za-z0-9\\-]+"))) + apiKey.length == 12 && + apiKey.matches(Regex("[A-Za-z0-9\\-]+"))) ) { "An Akismet API key must be specified." } @@ -325,41 +325,37 @@ open class Akismet(apiKey: String) { * @param trueOnError Set to return `true` on error (IO, empty response, etc.) */ @JvmOverloads - fun executeMethod(apiUrl: HttpUrl?, formBody: FormBody, trueOnError: Boolean = false): Boolean { + fun executeMethod(apiUrl: HttpUrl, formBody: FormBody, trueOnError: Boolean = false): Boolean { reset() - if (apiUrl != null) { - val request = if (formBody.size == 0) { - Request.Builder().url(apiUrl).header("User-Agent", buildUserAgent()).build() - } else { - Request.Builder().url(apiUrl).post(formBody).header("User-Agent", buildUserAgent()).build() - } - try { - val result = client.newCall(request).execute() - httpStatusCode = result.code - proTip = result.header("x-akismet-pro-tip", "").toString().trim() - isDiscard = (proTip == "discard") - debugHelp = result.header("x-akismet-debug-help", "").toString().trim() - val body = result.body?.string() - if (body != null) { - response = body.trim() - if (response == "valid" || response == "true" || response.startsWith("Thanks")) { - return true - } else if (response != "false" && response != "invalid") { - errorMessage = "Unexpected response: " + if (body.isBlank()) "" else body - } - } else { - val message = "No response body was received from Akismet." - errorMessage = if (debugHelp.isNotBlank()) { - "$message: $debugHelp" - } else { - message - } - } - } catch (e: IOException) { - errorMessage = "An IO error occurred while communicating with the Akismet service." - } + val request = if (formBody.size == 0) { + Request.Builder().url(apiUrl).header("User-Agent", buildUserAgent()).build() } else { - errorMessage = "Invalid API end point URL." + Request.Builder().url(apiUrl).post(formBody).header("User-Agent", buildUserAgent()).build() + } + try { + val result = client.newCall(request).execute() + httpStatusCode = result.code + proTip = result.header("x-akismet-pro-tip", "").toString().trim() + isDiscard = (proTip == "discard") + debugHelp = result.header("x-akismet-debug-help", "").toString().trim() + val body = result.body?.string() + if (body != null) { + response = body.trim() + if (response == "valid" || response == "true" || response.startsWith("Thanks")) { + return true + } else if (response != "false" && response != "invalid") { + errorMessage = "Unexpected response: " + if (body.isBlank()) "" else body + } + } else { + val message = "No response body was received from Akismet." + errorMessage = if (debugHelp.isNotBlank()) { + "$message: $debugHelp" + } else { + message + } + } + } catch (e: IOException) { + errorMessage = "An IO error occurred while communicating with the Akismet service: ${e.message}" } if (errorMessage.isNotEmpty()) { @@ -384,11 +380,11 @@ open class Akismet(apiKey: String) { response = "" } - private fun String.toApiUrl(): HttpUrl? { + private fun String.toApiUrl(): HttpUrl { return if (this == verifyMethod) { - String.format(apiEndPoint, "", this).toHttpUrlOrNull() + String.format(apiEndPoint, "", this).toHttpUrl() } else { - String.format(apiEndPoint, "$apiKey.", this).toHttpUrlOrNull() + String.format(apiEndPoint, "$apiKey.", this).toHttpUrl() } } diff --git a/src/main/kotlin/net/thauvin/erik/akismet/AkismetComment.kt b/src/main/kotlin/net/thauvin/erik/akismet/AkismetComment.kt index 9740f71..963e324 100644 --- a/src/main/kotlin/net/thauvin/erik/akismet/AkismetComment.kt +++ b/src/main/kotlin/net/thauvin/erik/akismet/AkismetComment.kt @@ -36,9 +36,6 @@ import kotlinx.serialization.Serializable import kotlinx.serialization.encodeToString import kotlinx.serialization.json.Json import javax.servlet.http.HttpServletRequest -import kotlin.collections.Map -import kotlin.collections.emptyMap -import kotlin.collections.iterator import kotlin.collections.set private fun String?.ifNull() = this ?: "" @@ -241,8 +238,8 @@ open class AkismetComment(val userIp: String, val userAgent: String) { * @see [serverEnv] */ constructor(request: HttpServletRequest) : this( - request.remoteAddr, - request.getHeader("User-Agent").ifNull() + request.remoteAddr, + request.getHeader("User-Agent").ifNull() ) { referrer = request.getHeader("referer").ifNull() serverEnv = buildServerEnv(request) diff --git a/src/test/kotlin/net/thauvin/erik/akismet/AkismetTest.kt b/src/test/kotlin/net/thauvin/erik/akismet/AkismetTest.kt index 0d31a4c..e743302 100644 --- a/src/test/kotlin/net/thauvin/erik/akismet/AkismetTest.kt +++ b/src/test/kotlin/net/thauvin/erik/akismet/AkismetTest.kt @@ -33,7 +33,7 @@ package net.thauvin.erik.akismet import okhttp3.FormBody -import okhttp3.HttpUrl.Companion.toHttpUrlOrNull +import okhttp3.HttpUrl.Companion.toHttpUrl import org.mockito.Mockito import org.mockito.Mockito.`when` import org.testng.Assert.assertEquals @@ -82,8 +82,8 @@ class AkismetTest { private val referer = "http://www.google.com" private val date = Date() private val comment = AkismetComment( - userIp = "127.0.0.1", - userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" + userIp = "127.0.0.1", + userAgent = "Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.2) Gecko/20100115 Firefox/3.6" ) private val akismet = Akismet(apiKey, blog) private val mockComment: AkismetComment = AkismetComment(request = getMockRequest()) @@ -255,9 +255,9 @@ class AkismetTest { fun emptyResponseTest() { with(akismet) { assertTrue( - executeMethod( - "https://postman-echo.com/status/200".toHttpUrlOrNull(), emptyFormBody, true - ) + executeMethod( + "https://postman-echo.com/status/200".toHttpUrl(), emptyFormBody, true + ) ) var expected = "{\"status\":200}" assertEquals(response, expected, "response: $expected") @@ -267,9 +267,9 @@ class AkismetTest { assertTrue(httpStatusCode == 0 && errorMessage.isEmpty(), "reset") assertTrue( - executeMethod( - "https://erik.thauvin.net/blank.html".toHttpUrlOrNull(), emptyFormBody, true - ) + executeMethod( + "https://erik.thauvin.net/blank.html".toHttpUrl(), emptyFormBody, true + ) ) expected = "" assertEquals(response, expected, "response: $expected") @@ -281,10 +281,10 @@ class AkismetTest { fun proTipResponseTest() { with(akismet) { assertFalse( - executeMethod( - "https://postman-echo.com/response-headers?x-akismet-pro-tip=discard".toHttpUrlOrNull(), - emptyFormBody - ) + executeMethod( + "https://postman-echo.com/response-headers?x-akismet-pro-tip=discard".toHttpUrl(), + emptyFormBody + ) ) assertEquals(proTip, "discard") assertTrue(isDiscard, "isDiscard") @@ -317,8 +317,8 @@ class AkismetTest { fun executeMethodTest() { with(akismet) { executeMethod( - "https://$apiKey.rest.akismet.com/1.1/comment-check".toHttpUrlOrNull(), - FormBody.Builder().apply { add("is_test", "1") }.build() + "https://$apiKey.rest.akismet.com/1.1/comment-check".toHttpUrl(), + FormBody.Builder().apply { add("is_test", "1") }.build() ) assertTrue(debugHelp.isNotEmpty(), "debugHelp not empty") @@ -327,15 +327,14 @@ class AkismetTest { } } - @Test + @Test(expectedExceptions = [IllegalArgumentException::class]) fun invalidApiTest() { - akismet.executeMethod("https://.com".toHttpUrlOrNull(), emptyFormBody) - assertTrue(akismet.errorMessage.startsWith("Invalid API")) + akismet.executeMethod("https://.com".toHttpUrl(), emptyFormBody) } @Test fun ioErrorTest() { - akismet.executeMethod("https://www.doesnotexists.com".toHttpUrlOrNull(), emptyFormBody) + akismet.executeMethod("https://www.foobarxyz.com".toHttpUrl(), emptyFormBody) assertTrue(akismet.errorMessage.contains("IO error")) } @@ -375,8 +374,8 @@ class AkismetTest { akismet.appUserAgent = "My App/1.0" assertEquals( - akismet.buildUserAgent(), "${akismet.appUserAgent} | $libAgent", - "my app" + akismet.buildUserAgent(), "${akismet.appUserAgent} | $libAgent", + "my app" ) } @@ -398,7 +397,7 @@ class AkismetTest { `when`(getHeader("User-Agent")).thenReturn(comment.userAgent) `when`(getHeader("Accept-Encoding")).thenReturn("gzip") `when`(headerNames).thenReturn( - Collections.enumeration(listOf("User-Agent", "referer", "Cookie", "Accept-Encoding", "Null")) + Collections.enumeration(listOf("User-Agent", "referer", "Cookie", "Accept-Encoding", "Null")) ) } return request