Bug? Issues with B4A/B4J HttpJob.Response.ContentLength

OliverA

Expert
Licensed User
Longtime User
In B4J and B4A, HttpJob.Response.ContentLength seems to always return 0 when using HttpJob.Head. In iOS, the same method returns the requested information.
(This issue was discovered by @oleg_ : https://www.b4x.com/android/forum/t...t-okhttputils2-response-contentlength.160216/)

This is the code snippet:
B4X:
    Dim filename As String = "https://b4x-4c17.kxcdn.com/android/forum/data/avatars/m/86/86664.jpg?1520274433"
    Dim j As HttpJob
    j.Initialize("", Me)
    j.head(filename)
    Wait For (j) JobDone(j As HttpJob)
    If j.Success Then
        Log("ContentLength = " & j.Response.ContentLength)
        Log(j.Response.GetHeaders)
        Log(j.Response.GetHeaders.GetDefault("content-length", "NADA"))
    Else
        Log(j.ErrorMessage)
    End If
    j.Release
(Test project is attached)

These are the various platforms/results:

B4J 10.00
JDK 14.0.1
OkHttpUtils2 3.02
Output:
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
ContentLength = 0
(MyMap) {accept-ranges=[bytes], access-control-allow-origin=[*], age=[26], cache-control=[max-age=604800], cf-bgj=[h2pri], cf-cache-status=[HIT], cf-ray=[86d43f8e9f547b95-ATL], content-length=[15804], content-type=[image/jpeg], date=[Mon, 01 Apr 2024 01:43:29 GMT], etag=["1f0632-3dbc-5ac58f6caa728"], expires=[Mon, 08 Apr 2024 01:43:29 GMT], last-modified=[Sat, 08 Aug 2020 07:49:41 GMT], link=[<https://www.b4x.com/android/forum/data/avatars/m/86/86664.jpg?1520274433>; rel="canonical"], nel=[{"success_fraction":0,"report_to":"cf-nel","max_age":604800}], report-to=[{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=TZtt2om19e6C%2BFaRywA49pyfCLFXA9f%2BpYBi6Q4fFdZvJBFdpSb99WLUAuQO7%2FzeirSfzlxLLaSOpYU8KUuBK7Lq1WPYIt00K8r3rOIQuyTqFxQ5jeGDWIHDOIEM"}],"group":"cf-nel","max_age":604800}], server=[keycdn], vary=[Accept-Encoding], x-cache=[HIT], x-edge-location=[usat]}
[15804]

B4A 12.80
JDK 14.0.1
OkHttpUtils2 3.04
Output:
Logger connected to: ******************
--------- beginning of system
--------- beginning of main
*** Service (starter) Create ***
** Service (starter) Start **
** Activity (main) Create (first time) **
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
ContentLength = 0
(MyMap) {accept-ranges=[bytes], access-control-allow-origin=[*], age=[26], cache-control=[max-age=604800], cf-bgj=[h2pri], cf-cache-status=[HIT], cf-ray=[86d43f8e9f547b95-ATL], content-length=[15804], content-type=[image/jpeg], date=[Mon, 01 Apr 2024 01:46:49 GMT], etag=["1f0632-3dbc-5ac58f6caa728"], expires=[Mon, 08 Apr 2024 01:46:49 GMT], last-modified=[Sat, 08 Aug 2020 07:49:41 GMT], link=[<https://www.b4x.com/android/forum/data/avatars/m/86/86664.jpg?1520274433>; rel="canonical"], nel=[{"success_fraction":0,"report_to":"cf-nel","max_age":604800}], report-to=[{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=TZtt2om19e6C%2BFaRywA49pyfCLFXA9f%2BpYBi6Q4fFdZvJBFdpSb99WLUAuQO7%2FzeirSfzlxLLaSOpYU8KUuBK7Lq1WPYIt00K8r3rOIQuyTqFxQ5jeGDWIHDOIEM"}],"group":"cf-nel","max_age":604800}], server=[keycdn], vary=[Accept-Encoding], x-cache=[HIT], x-edge-location=[usat]}
[15804]

B4i 8.51
iHttpUtils2 3.04
Output:
Application_Start
Call B4XPages.GetManager.LogEvents = True to enable logging B4XPages events.
Application_Active
ContentLength = 15804
(read only map) <CFBasicHash 0x2823f8740 [0x1f4f96468]>{type = immutable dict, count = 20,
entries =>
3 : Server = keycdn
4 : Link = <CFString 0x281ddc690 [0x1f4f96468]>{contents = "<https://www.b4x.com/android/forum/data/avatars/m/86/86664.jpg?1520274433>; rel="canonical""}
5 : x-edge-location = usat
6 : Cache-Control = <CFString 0x2836de4a0 [0x1f4f96468]>{contents = "max-age=604800"}
8 : Accept-Ranges = bytes
12 : Access-Control-Allow-Origin = *
16 : report-to = <CFString 0x280adc800 [0x1f4f96468]>{contents = "{"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v4?s=TZtt2om19e6C%2BFaRywA49pyfCLFXA9f%2BpYBi6Q4fFdZvJBFdpSb99WLUAuQO7%2FzeirSfzlxLLaSOpYU8KUuBK7Lq1WPYIt00K8r3rOIQuyTqFxQ5jeGDWIHDOIEM"}],"group":"cf-nel","max_age":604800}"}
21 : Content-Length = 15804
22 : cf-bgj = h2pri
23 : Vary = <CFString 0x2838dd8f0 [0x1f4f96468]>{contents = "Accept-Encoding"}
24 : Date = <CFString 0x2838dd9e0 [0x1f4f96468]>{contents = "Mon, 01 Apr 2024 01:41:24 GMT"}
29 : Expires = <CFString 0x2838dd920 [0x1f4f96468]>{contents = "Mon, 08 Apr 2024 01:41:24 GMT"}
33 : Age = 26
34 : nel = <CFString 0x2815dd6d0 [0x1f4f96468]>{contents = "{"success_fraction":0,"report_to":"cf-nel","max_age":604800}"}
35 : x-cache = HIT
36 : Content-Type = <CFString 0x2836dd660 [0x1f4f96468]>{contents = "image/jpeg"}
37 : Etag = <CFString 0x2838dc780 [0x1f4f96468]>{contents = ""1f0632-3dbc-5ac58f6caa728""}
38 : cf-cache-status = HIT
39 : cf-ray = <CFString 0x2838dc5d0 [0x1f4f96468]>{contents = "86d43f8e9f547b95-ATL"}
40 : Last-Modified = <CFString 0x2838dd980 [0x1f4f96468]>{contents = "Sat, 08 Aug 2020 07:49:41 GMT"}
}
15804
Class (b4i_httpjob) instance released.

For some reason, on B4A/B4J, the content length values are enclosed in [ and ] (all header values seem to be enclosed in such a way). IDK if that interferes with the proper conversion to the value, since when pulling the header value directly (via Response.GetHeaders.GetDefault("content-length", "NADA")) the brackets are still there.
 

Attachments

  • HeaderTestCLv2.zip
    21.7 KB · Views: 119

Erel

B4X founder
Staff member
Licensed User
Longtime User
This is the behavior of the underlying OkHttp SDK.

I've used this code in the very useful RangeDownloader module, to get headers values:
B4X:
Private Sub GetCaseInsensitiveHeaderValue (job As HttpJob, Key As String, DefaultValue As String) As String
    Dim headers As Map = job.Response.GetHeaders
    For Each k As String In headers.Keys
        If K.EqualsIgnoreCase(Key) Then
            Return headers.Get(k).As(String).Replace("[", "").Replace("]", "").Trim
        End If
    Next
    Return DefaultValue
End Sub
 

OliverA

Expert
Licensed User
Longtime User

oleg_

Member
Licensed User
I prefer not to change the existing behavior as theoretically it is only in the rare HEAD request where there is a difference, and the workaround is simple.
Perhaps this post
should be edited? In this form, it misleads beginners. Response.ContentLength there will always be equal to zero, and this leads to the erroneous idea that all sites prohibit reading the HEAD separately from the content.
 
Top