Android Question [SOLVED] Identical http request - different responses (B4A - B4J)

mc73

Well-Known Member
Licensed User
Longtime User
I'm sending a post request after an initial get, using okHttpUtils2 to a server both by B4A and B4J.
Coding is identical and I'm using the latest versions of both B4A and B4J.
However, the return is different, in fact in B4J I'm getting the expected response url, while in Β4A I get another one (I can see that this means something goes wrong with the redirects).
Attached you may find both examples.
Any help will be greatly appreciated.
 

Attachments

  • b4aTestRequest.zip
    8.5 KB · Views: 163
  • b4jTestRequest.zip
    1.2 KB · Views: 142

OliverA

Expert
Licensed User
Longtime User
Here is a clue. If, in B4J you take out the first download, you'll end up with the same result as the B4A app. Even the map logged via Log(j1.Response.GetHeaders) is the same. So B4A is handling the first to second call differently then B4J. I know this is not a solution, but it may hint towards one.
B4X:
Sub test
'    Private mainUrl As String=$"https://www1.gsis.gr/taxisnet/mytaxisnet"$
'    Private j0 As HttpJob
'    j0.Initialize("",Me)
'    j0.Download(mainUrl)
'    wait for (j0) jobDone (j0 As HttpJob)
'    If j0.Success Then
        Private j1 As HttpJob
        j1.Initialize("",Me)
        Private postUrl As String="https://mygovlogin.gsis.gr/oam/server/auth_cred_submit"
        Private postData As String
        j1.PostString(postUrl,postData)
        wait for (j1) jobDone (j1 As HttpJob)
        If j1.Success Then
            Dim jo As JavaObject = j1.response
            Dim url As String = jo.GetFieldJO("response").RunMethodJO("request", Null).RunMethod("url", Null)
            Log(j1.Response.StatusCode)
            Log(j1.Response.GetHeaders)
            txt.Text="Response url: "&url 
        Else
            Log(j1.ErrorMessage)
        End If
        j1.Release
'    Else
'        Log(j0.ErrorMessage)
'    End If
'    j0.Release
End Sub
 
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
Here is a clue. If, in B4J you take out the first download, you'll end up with the same result as the B4A app. Even the map logged via Log(j1.Response.GetHeaders) is the same. So B4A is handling the first to second call differently then B4J. I know this is not a solution, but it may hint towards one.
B4X:
Sub test
'    Private mainUrl As String=$"https://www1.gsis.gr/taxisnet/mytaxisnet"$
'    Private j0 As HttpJob
'    j0.Initialize("",Me)
'    j0.Download(mainUrl)
'    wait for (j0) jobDone (j0 As HttpJob)
'    If j0.Success Then
        Private j1 As HttpJob
        j1.Initialize("",Me)
        Private postUrl As String="https://mygovlogin.gsis.gr/oam/server/auth_cred_submit"
        Private postData As String
        j1.PostString(postUrl,postData)
        wait for (j1) jobDone (j1 As HttpJob)
        If j1.Success Then
            Dim jo As JavaObject = j1.response
            Dim url As String = jo.GetFieldJO("response").RunMethodJO("request", Null).RunMethod("url", Null)
            Log(j1.Response.StatusCode)
            Log(j1.Response.GetHeaders)
            txt.Text="Response url: "&url
        Else
            Log(j1.ErrorMessage)
        End If
        j1.Release
'    Else
'        Log(j0.ErrorMessage)
'    End If
'    j0.Release
End Sub
True Oliver!
However turned out that the problem is that server errors, then okhttp repeats the request, and server correctly then responds with an error page. Probably in Java, such bad server behavior is fixed, but not in the android version unfortunately. I will try to see if I can replicate this on my own server and see if I can workaround it, but I'm not very optimistic. Thank you for your time :)
 
Last edited:
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
Finally got a fix to this problem.

I engaged a no-auto-redirect, and the fix was that I cleared cookies before the final post, and re-set them based on cookies received earlier.

That is:
B4X:
Pseudo code
getRequest1->Redirect->getRequest2->and so on until
finalResponse (final redirection)
ClearCookiesFromStore:' If I don't clear the cookie store, I get the same wrong response as in my original auto-redirect post.
ResetCookiesAsReceivedInAMap:'resetting all cookies received by previous requests, gets the job done. Seems like my final post as performed in my original auto-redirect post, misses some cookies.
PostRequest
Success

However, I would like to avoid this messy coding, and keep the nice okHttpUtils2, as apart from this connection, runs great everywhere. And I know I can set its cookieStore and proceed from there, but still it would be great if not performing all these manual redirects.

Any hints on what can be a workaround or final solution to this, by using strictly okHttpUtils2?

And the real code, by the way is:
B4X:
Sub Process_Globals
    Type responseLocationAndCookie(location As String,cookie As String)
End Sub

Sub Globals
    Public hc As OkHttpClient
    Private strUtils As StringUtils
    Private tempFolder As String
    Private myCookiesMap As Map
End Sub

Sub Activity_Create(FirstTime As Boolean)
    tempFolder=File.DirInternalCache
    connectHttp
End Sub

Sub Activity_Resume

End Sub

Sub Activity_Pause (UserClosed As Boolean)

End Sub

Sub connectHttp
    Log(DateTime.Now)
    If myCookiesMap.IsInitialized=False Then
        myCookiesMap.Initialize
    End If
    myCookiesMap.Clear
   
    Dim jo As JavaObject = hc
    Dim builder As JavaObject = jo.RunMethod("sharedInit", Array("hc"))
    builder.RunMethod("followRedirects", Array(False))
    builder.RunMethod("followSslRedirects",Array(False))
    jo.SetField("client", builder.RunMethod("build", Null))
   
    Private req1 As OkHttpRequest
    req1.InitializeGet("https://www1.gsis.gr/taxisnet/mytaxisnet/protected/home.htm")
    hc.Execute(req1,0)
   
End Sub

Sub hc_ResponseSuccess (Response As OkHttpResponse, TaskId As Int)
    Private temptype As responseLocationAndCookie=getLocationAndCookieFromResponse(Response)
    Response.GetAsynchronously("response",File.OpenOutput(tempFolder,TaskId,False),True,TaskId)
End Sub



Sub hc_ResponseError (Response As OkHttpResponse, Reason As String, StatusCode As Int, TaskId As Int)
    If Floor(StatusCode / 100) = 3 Then
        If Response <> Null Then
            Private temptype As responseLocationAndCookie=getLocationAndCookieFromResponse(Response)
            If temptype.location.Length>0 Then
                TaskId=TaskId+1
                Private req As OkHttpRequest
                req.InitializeGet(temptype.location)
                Private tempcookie As String=prepairCookie
                req.SetHeader("Cookie",tempcookie)
                hc.Execute(req,TaskId)
            Else
                Log("error: no location for redirect set")
            End If
        Else
            Log("error: response null")
        End If
    Else
        Log("error: "&Reason&","&StatusCode)
    End If
End Sub


Sub response_StreamFinish (Success As Boolean, TaskId As Int)
    Select  True
        Case TaskId>0
            Private token As String
            Private html0 As String=decompressToString(File.OpenInput(tempFolder,TaskId),"UTF8",getString(TaskId))
            Private searchToken As String=$"request_id" value=""$
            Private startIndexToken As Int=html0.IndexOf(searchToken)
            If startIndexToken>-1 Then
                startIndexToken=startIndexToken+searchToken.Length
                Private endIndexToken As Int=html0.IndexOf2($"""$,startIndexToken)
                If endIndexToken>startIndexToken Then
                    token=html0.SubString2(startIndexToken,endIndexToken)
                    token=strUtils.EncodeUrl(token.Replace("&#45;","-"),"UTF8")
                End If
            End If
            Private username As String="ausername"
            Private userpass As String="apassword"
            username=strUtils.EncodeUrl(username,"UTF8")
            userpass=strUtils.EncodeUrl(userpass,"UTF8")
            token=strUtils.EncodeUrl(token,"UTF8")
            Private postData As String=$"username=${username}&password=${userpass}&request_id=${token}&btn_login="$
            '----------
            clearHttp: 'if I don't clear cookies I get the same error as in my original code
            '----------
            Private req2 As OkHttpRequest
            Private tempBytes() As Byte=postData.GetBytes("UTF8")
            req2.InitializePost2("https://mygovlogin.gsis.gr/oam/server/auth_cred_submit",tempBytes)
            Private tempcookie As String=prepairCookie
            req2.SetHeader("Cookie",tempcookie)
            hc.Execute(req2,-1)
        Case Else
            Log(DateTime.Now)
            Private html1 As String=decompressToString(File.OpenInput(tempFolder,TaskId),"UTF8",getString(TaskId))
            Log(html1)
    End Select
   
End Sub




Sub getLocationAndCookieFromResponse(response As OkHttpResponse) As responseLocationAndCookie
    Private tempType As responseLocationAndCookie
    tempType.Initialize
    Private map0 As Map=response.GetHeaders
    Private locations As List=map0.Get("location")
    Private location As String
    If locations.IsInitialized Then
        location=locations.Get(0)
    End If
    tempType.location=location
    For Each key As String In map0.Keys
        Private tempVal As List=map0.Get(key)
        For Each st As String In tempVal
            If key.ToLowerCase.StartsWith("set-cookie") Then
                Private tempValStart As Int=st.IndexOf("=")
                Private tempCookieKey As String=st.SubString2(0,tempValStart)
                tempValStart=tempValStart+1
                Private tempCookieVal As String=st.SubString2(tempValStart,st.IndexOf2(";",tempValStart))
                If tempCookieVal.Length>0 Then
                    myCookiesMap.Put(tempCookieKey,tempCookieVal)
                End If
            End If
        Next
    Next
    Return tempType
End Sub



Sub prepairCookie As String
    Private newCookie As String
    For Each cookieName As String In myCookiesMap.Keys
        Private cookieVal As String=myCookiesMap.Get(cookieName)
        newCookie=newCookie&cookieName&"="&cookieVal&";"
    Next
    Return newCookie
End Sub

       
Sub clearHttp
    Dim jo As JavaObject =hc
    jo = jo.GetFieldJO("client").RunMethod("cookieJar", Null)
    Dim r As Reflector
    r.Target = jo
    Dim CookieManager As JavaObject = r.GetField("cookieHandler")
    CookieManager.RunMethodJO("getCookieStore", Null).RunMethod("removeAll", Null)
End Sub


Sub getString(taskID As Int) As String
    Dim tr As TextReader
    tr.Initialize(File.OpenInput(tempFolder, taskID))
    Dim res As String = tr.ReadAll
    tr.Close
    Return res
End Sub


Sub decompressToString(tempInputStream As InputStream,encoding As String,defaultString As String) As String
    Dim OS As OutputStream
    OS.InitializeToBytesArray(1000)
    File.Copy2(tempInputStream, OS)
    Dim Buffer() As Byte
    Buffer = OS.ToBytesArray
    Dim compress As CompressedStreams
    Dim decompressed() As Byte
    Dim DecompressedString As String
    Try
        decompressed = compress.DecompressBytes(Buffer, "gzip")
        DecompressedString=BytesToString(decompressed, 0, decompressed.Length, encoding)
    Catch
        DecompressedString=defaultString
    End Try
    Return DecompressedString
End Sub
 
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
Upvote 0

mc73

Well-Known Member
Licensed User
Longtime User
After carefully logging cookies of the response of request1, I found that cookie store held duplicate entries of some cookies!

To me, this is weird, and I finally got the fix by resetting cookie by deleting previous (duplicate entries).

I think this behavior has to be examined, since it appears that in b4j it's just not happening, so I have to guess that something goes wrong in Android OS (?).

Anyway. the following code shows a workaround, so I have to mark this thread solved, even if it the existence of duplicate cookie keys bothers me and there has to be a fix to this internally (I guess but not sure).

B4X:
.....
Private newCookie as string=getCookiesFromCookieStore
clearHttp
Private j1 As HttpJob
 j1.Initialize("",Me)
 Private postUrl As String="myFinalURL"
Private postData as string="myFinalPostData"
 j1.PostString(postUrl,postData)
j1.getRequest.setHeader("Cookie",newCookie)
.....

Sub getCookiesFromCookieStore As String
    Private finalCookie As String
    Private newCookiesMap As Map
    newCookiesMap.Initialize
    Dim jo As JavaObject =HttpUtils2Service.hc
    jo = jo.GetFieldJO("client").RunMethod("cookieJar", Null)
    Dim r As Reflector
    r.Target = jo
    Dim CookieManager As JavaObject = r.GetField("cookieHandler")
    Private cookieStore As JavaObject=CookieManager.RunMethodJO("getCookieStore", Null)
    Private cookieLstObject As List=cookieStore.RunMethod("getCookies",Null)
    If cookieLstObject.IsInitialized Then
        If cookieLstObject.Size>0 Then
            For Each tempCookie As String In cookieLstObject
                Private cookieName As String=tempCookie.SubString2(0,tempCookie.IndexOf("="))
                Private tempCookieVal As String=tempCookie.SubString(tempCookie.IndexOf("=")+1)
                newCookiesMap.Put(cookieName,tempCookieVal):' replacing a cookie if found
            Next
        End If
    End If
    For Each key As String In newCookiesMap.Keys
        finalCookie=finalCookie&key&"="&newCookiesMap.Get(key)&";"
    Next
    Return finalCookie
End Sub

        
Sub clearHttp
    If HttpUtils2Service.hc.IsInitialized Then
        Dim jo As JavaObject = HttpUtils2Service.hc
        jo = jo.GetFieldJO("client").RunMethod("cookieJar", Null)
        Dim r As Reflector
        r.Target = jo
        Dim CookieManager As JavaObject = r.GetField("cookieHandler")
        CookieManager.RunMethodJO("getCookieStore", Null).RunMethod("removeAll", Null)
    End If
End Sub
 
Last edited:
Upvote 0
Top