Ktor unable to receive POST body on Server - kotlin

I have the following Server and Client code:
Server:
fun Application.main() {
install(DefaultHeaders)
install(CallLogging)
install(Routing) {
post("/") {
val requestBody = call.receiveText()
println("Received $requestBody")
call.respond("Hello from server - received $requestBody")
}
}
}
fun main(args: Array<String>) {
embeddedServer(Netty, 8080) {
main()
}.start(wait = true)
}
Client:
fun main(args: Array<String>) = runBlocking {
HttpClient(CIO).use {
val postResult = it.post<String>("http://localhost:8080/") {
body = "Client Hello"
}
println(postResult)
}
}
So, the client just sends "Client Hello" to the server in the POST-body, and the Server responds to that.
But I didn't see the content of the body on the server-side. What am I doing wrong?
The call.receiveText() is always empty.

The issue fixed in recent alphas(>= 0.9.2-alpha-5) and would appear in next 0.9.2 release soon.

And if you have parameters in your body request, try it:
val requestBody = call.receiveParameters()
val value = requestBody["key_name"]

Related

Retrofit response body returning null

I've been stuck with this problem for some time now, and I can't seem to find the problem especially when all I did was following a guide online.
I'm trying to make a POST request, and receive a response in exchange:
Request body:
{
"Email":"test#gmail.com",
"firebaseUid":"Test_UID",
"IsBanned":1
}
Response body:
`
{
"Email": "test#gmail.com",
"UserId": 7
}
So basically whenever I submit a request to /users/ to create an account, I get both the email and UserId returned.
data class UserLogin(
#SerializedName("Email") val Email: String,
#SerializedName("UserId") val UserId: Int?,
#SerializedName("IsBanned") val IsBanned: Boolean?,
#SerializedName("firebaseUid") val firebaseUid: String?
)
object ServiceBuilder {
private val client = OkHttpClient.Builder().build()
private val retrofit = Retrofit.Builder()
.baseUrl("http://10.0.2.2/8000/")
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()
fun<T> buildService(service: Class<T>): T{
return retrofit.create(service)
}
}
class RestApiService {
fun addUser(userData: UserLogin, onResult: (UserLogin?) -> Unit){
val retrofit = ServiceBuilder.buildService(RestApi::class.java)
retrofit.addUser(userData).enqueue(
object : Callback<UserLogin> {
override fun onFailure(call: Call<UserLogin>, t: Throwable) {
Log.d("Failed retrofit",t.message.toString())
onResult(null)
}
override fun onResponse( call: Call<UserLogin>, response: Response<UserLogin>) {
val addedUser = response.body()
onResult(addedUser)
}
}
)
}
}
onFailure doesn't seem to be printing anything on the console. I'm calling the API from a button like this and both Email and UserId keep returning null for some reason:
`
val apiService = RestApiService()
val userInfo = UserLogin(UserId = null,firebaseUid = "TestTestTest", IsBanned = false, Email = "test#gmail.com");
apiService.addUser(userInfo){
Log.d("Retrofit user added", it?.Email.toString())
}
`
I tried to:
Set default values for the data class members.
Tried to check if response is successfull, and then print the errorBody if not. That didn't help either. I'm getting unreadable errors like $1#9afe35d instead.
Everything seem to be working fine when I do requests manually with POSTMAN.
It turned out there was nothing with the code. I just typed the port the wrong way and used a / instead of :
private val retrofit = Retrofit.Builder()
.baseUrl("http://10.0.2.2:8000/") // this
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build()

Kotlin Ktor client 403 forbidden cloudflare

So im trying to request a side with proxies that is protected with cloudflare. The problem is i get 403 forbidden cloduflare error but only when im using proxies without it works. But the proxies are not the problem i tried them with python(requests module) and in my browser there i dont get blocked. My code
suspend fun scrape() {
val client = HttpClient {
followRedirects = true
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
engine {
proxy =
ProxyBuilder.http("http://ProxyIP:proxyPort")
}
defaultRequest {
val credentials = Base64.getEncoder().encodeToString("ProxyUser:ProxyPassword".toByteArray())
header(HttpHeaders.ProxyAuthorization, "Basic $credentials")
}
}
val response = client.get("http://example.com")
val body = response.bodyAsText()
println(body)
println(response.status.hashCode())
Fixxed it
suspend fun scrape() {
val client = HttpClient(Apache) {
install(ContentNegotiation) {
json(Json {
ignoreUnknownKeys = true
})
}
engine {
followRedirects = false
customizeClient {
setProxy(HttpHost("hostname", port))
val credentialsProvider = BasicCredentialsProvider()
credentialsProvider .setCredentials(
AuthScope("hostname", port),
UsernamePasswordCredentials("username", "password")
)
setDefaultCredentialsProvider(credentialsProvider )
}
}
}
val response =
client.get("http://example.com") {
}
val body = response.bodyAsText()
println(body)
println(response.status.hashCode())
}
There is a problem with making a request through a proxy server using the CIO engine. I've created an issue to address this problem. As a workaround, please use the OkHttp engine instead of CIO.
Here is how you can use a proxy with the Basic authentication:
import io.ktor.client.*
import io.ktor.client.engine.okhttp.*
import io.ktor.client.request.*
import kotlinx.coroutines.runBlocking
import okhttp3.Authenticator
import okhttp3.Credentials
import okhttp3.OkHttpClient
import java.net.Proxy
fun main(): Unit = runBlocking {
val proxyAuthenticator = Authenticator { _, response ->
response.request.newBuilder()
.header("Proxy-Authorization", Credentials.basic("<username>", "<password>"))
.build()
}
val client = HttpClient(OkHttp) {
engine {
preconfigured = OkHttpClient.Builder()
.proxy(Proxy(Proxy.Type.HTTP, java.net.InetSocketAddress("127.0.0.1", 3128)))
.proxyAuthenticator(proxyAuthenticator)
.build()
}
}
val response = client.get("http://eu.kith.com/products.json")
println(response.status)
}

Chain validation failed

I'm having the below Okhttp code:
val client = OkHttpClient()
val mediaType = MediaType.parse("application/x-www-form-urlencoded")
val body = RequestBody.create(mediaType, "tenant_id=xxxx&client_id=xxxx&client_secret=xxxx&resource=xxxx&grant_type=client_credentials")
val request = Request.Builder()
.url("https://sxxx.com/axxx/oauth2/token")
.post(body)
.addHeader("Content-Type", "application/x-www-form-urlencoded")
.build()
val response = client.newCall(request).execute()
And want to convert it usint ktor, so I wrote the below:
class Greeting {
private val httpClient = HttpClient {
}
#Throws(Exception::class)
suspend fun greeting(): String {
val response = httpClient.request {
method = HttpMethod.Post
url {
protocol = URLProtocol.HTTPS
host = "sxxx.com"
path("axxx/oauth2/token")
// encodedParameters
trailingQuery = true
parameters.append("tenant_id", "xxxx")
parameters.append("client_id", "xxxx")
parameters.append("client_secret", "xxxx")
parameters.append("resource", "xxxx")
parameters.append("grant_type", "client_credentials")
}
headers {
append(HttpHeaders.ContentType, "application/x-www-form-urlencoded")
}
}
return response.bodyAsText()
}
}
And calling my new code as:
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyApplicationTheme {
Surface(
modifier = Modifier.fillMaxSize(),
color = MaterialTheme.colors.background
) {
val scope = rememberCoroutineScope()
var text by remember {
mutableStateOf("Loading")
}
LaunchedEffect(true){
scope.launch {
text = try {
Greeting().greeting()
} catch (e: Exception) {
e.localizedMessage ?: "error"
}
}
}
Greeting(text)
}
}
}
}
}
#Composable
fun Greeting(text: String) {
Text(text = text)
}
But instead of getting the required token, I'm getting the response: Chain validation failed
Make sure that:
Your server certificate is valid.
Your android system datetime is correct.

How to output that the server has been started

I have the following code, that it going to start a http server:
class MainVerticle : CoroutineVerticle() {
override suspend fun start() {
val server = vertx.createHttpServer()
val router = Router.router(vertx)
router.route("/api/genders*")
.subRouter(GenderApi(vertx).create())
server.requestHandler(router)
.listen(8080)
.await()
}
}
Now, I would like to output, if the server has been successfully started or failed(in case the port has been already occupied).
Without the Coroutine, the codes would be:
class MainVerticle : AbstractVerticle() {
override fun start(startPromise: Promise<Void>) {
val server = vertx.createHttpServer()
val router = Router.router(vertx)
server.requestHandler(router).listen(8888) { http ->
if (http.succeeded()) {
startPromise.complete()
println("HTTP server started on port 8888")
} else {
println(http.cause())
startPromise.fail(http.cause());
}
}
}
}
Here I do output, if the server has been started success or not.
If you use coroutines, add a try/catch block:
class MainVerticle : CoroutineVerticle() {
override suspend fun start() {
val server = vertx.createHttpServer()
val router = Router.router(vertx)
router.route("/api/genders*")
.subRouter(GenderApi(vertx).create())
try {
server.requestHandler(router)
.listen(8080)
.await()
println("HTTP server started on port 8888")
} catch (e: Exception) {
println(http.cause())
throw e
}
}
}

Vertx plus Kotlin coroutines hangs forever

I am rewriting some Java Vertx asynch code using Kotlin coroutines for learning purposes. However, when I try to test a simple HTTP call, the coroutine based test hangs forever and I really don't understand where is the issue. Here a reproducer:
#RunWith(VertxUnitRunner::class)
class HelloWorldTest {
private val vertx: Vertx = Vertx.vertx()
#Before
fun setUp(context: TestContext) {
// HelloWorldVerticle is a simple http server that replies "Hello, World!" to whatever call
vertx.deployVerticle(HelloWorldVerticle::class.java!!.getName(), context.asyncAssertSuccess())
}
// ORIGINAL ASYNC TEST HERE. IT WORKS AS EXPECTED
#Test
fun testAsync(context: TestContext) {
val atc = context.async()
vertx.createHttpClient().getNow(8080, "localhost", "/") { response ->
response.handler { body ->
context.assertTrue(body.toString().equals("Hello, World!"))
atc.complete()
}
}
}
// First attempt, it hangs forever, the response is never called
#Test
fun testSync1(context: TestContext) = runBlocking<Unit> {
val atc = context.async()
val body = await<HttpClientResponse> {
vertx.createHttpClient().getNow(8080, "localhost", "/", { response -> response.handler {it}} )
}
context.assertTrue(body.toString().equals("Hello, World!"))
atc.complete()
}
// Second attempt, it hangs forever, the response is never called
#Test
fun testSync2(context: TestContext) = runBlocking<Unit> {
val atc = context.async()
val response = await<HttpClientResponse> {
vertx.createHttpClient().getNow(8080, "localhost", "/", it )
}
response.handler { body ->
context.assertTrue(body.toString().equals("Hello, World!"))
atc.complete()
}
}
suspend fun <T> await(callback: (Handler<T>) -> Unit) =
suspendCoroutine<T> { cont ->
callback(Handler { result: T ->
cont.resume(result)
})
}
}
Is everyone able to figure out the issue?
It seems to me that your code have several problems:
you may running the test before the http-server got deployed
I believe that since you execute your code inside runBlocking you are blocking the event loop from completing the request.
Finally, I will advise you to use the HttpClienctResponse::bodyHandler method instead of HttpClientResponse::handler as the handler may receive partial data.
Here is an alternative solution that works fine:
import io.vertx.core.AbstractVerticle
import io.vertx.core.Future
import io.vertx.core.Handler
import io.vertx.core.Vertx
import io.vertx.core.buffer.Buffer
import io.vertx.core.http.HttpClientResponse
import kotlin.coroutines.experimental.Continuation
import kotlin.coroutines.experimental.EmptyCoroutineContext
import kotlin.coroutines.experimental.startCoroutine
import kotlin.coroutines.experimental.suspendCoroutine
inline suspend fun <T> await(crossinline callback: (Handler<T>) -> Unit) =
suspendCoroutine<T> { cont ->
callback(Handler { result: T ->
cont.resume(result)
})
}
fun <T : Any> async(code: suspend () -> T) = Future.future<T>().apply {
code.startCoroutine(object : Continuation<T> {
override val context = EmptyCoroutineContext
override fun resume(value: T) = complete()
override fun resumeWithException(exception: Throwable) = fail(exception)
})
}
fun main(args: Array<String>) {
async {
val vertx: Vertx = Vertx.vertx()
//0. take the current context
val ctx = vertx.getOrCreateContext()
//1. deploy the http server
await<Unit> { cont ->
vertx.deployVerticle(object : AbstractVerticle() {
override fun start() {
vertx.createHttpServer()
.requestHandler { it.response().end("Hello World") }
.listen(7777) { ctx.runOnContext { cont.handle(Unit) } }
//note that it is important tp complete the handler in the correct context
}
})
}
//2. send request
val response: HttpClientResponse = await { vertx.createHttpClient().getNow(7777, "localhost", "/", it) }
//3. await response
val body = await<Buffer> { response.bodyHandler(it) }
println("received $body")
}
}