Groovy HTTP Builder: Empty POST response causes SAXParseException - java

I am implementing REST client for YouTrack API. I am getting an exception whenever my POST requests return empty response (there's just a valid header). The HTTP status code is 200.
That's the stacktrace:
[Fatal Error] :-1:-1: Premature end of file.
gru 03, 2013 10:34:49 AM groovyx.net.http.HTTPBuilder doRequest
WARNING: Error parsing 'application/xml; charset=UTF-8' response
org.xml.sax.SAXParseException; Premature end of file.
at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:181)
at groovy.util.XmlSlurper.parse(XmlSlurper.java:234)
at groovyx.net.http.ParserRegistry.parseXML(ParserRegistry.java:267)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:233)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1085)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:952)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:909)
at groovy.lang.Closure.call(Closure.java:423)
at groovy.lang.Closure.call(Closure.java:439)
at groovyx.net.http.HTTPBuilder.parseResponse(HTTPBuilder.java:561)
at groovyx.net.http.HTTPBuilder.doRequest(HTTPBuilder.java:494)
at groovyx.net.http.RESTClient.post(RESTClient.java:140)
at groovyx.net.http.RESTClient$post.callCurrent(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallCurrent(CallSiteArray.java:49)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:133)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callCurrent(AbstractCallSite.java:141)
at groovy.YouTrackRest.releaseVersion(YouTrackRest.groovy:66)
at groovy.YouTrackRest$releaseVersion$0.call(Unknown Source)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:108)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:116)
at YouTrack.run(YouTrack.groovy:13)
[...]
I have debugged and found out what's the direct cause for that. I noticed that in groovyx.net.http.HTTPBuilder:492 before parsing it is checked whether response is empty but in my case the call entity.getContentLength() returns -1. After Apache documentation for HttpEntity
the number of bytes of the content, or a negative number if unknown
My client implementation is very plain. I have worked the problem around by catching the HttpResponseException and asserting statusCode 200. I am still getting the stacktrace in my console, but that's probably just the logger setting.
My implementation:
import groovyx.net.http.RESTClient
class YouTrackRest extends RESTClient {
[...]
def activateVersion(versionNumber) {
try {
post(
path: getVersionPath(versionNumber),
body: [
colorIndex: ACTIVE_COLOR_INDEX,
released: false,
releaseDate: null,
archived: false,
newName: versionNumber
]
)
} catch (HttpResponseException ex) {
assert ex.response.status == 200
}
}
EDIT:
These are the response headers
Server: nginx
Date: Fri, 06 Dec 2013 10:36:10 GMT
Content-Type: application/xml; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Accept-Encoding
Set-Cookie: JSESSIONID=ny2s3cxwsvveya6vgwj2fmig;Path=/youtrack
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Cache-Control: no-cache, no-store, no-transform, must-revalidate
Present Transfer-Encoding: chunked header explains missing 'Content-Length' header. That has to be the reason for unknown Content Length.
Now, according to Wikipedia The data transfer is terminated by a final chunk of length zero. So maybe is this case the first chunk is also the last one?
Both, the Web Server and the Http client library are third party for me. I would like to raise an issue by whoever misbehaves:
either YouTrack REST WS promisses XML and returns nothing
or groovyx.net.http.HTTPBuilder fails to process chunked encoded responses.
I will be very helpful for some expertise to help me understand the problem.

I just ran into this same problem using httpbuilder. I was able to work around it with:
def service = new HTTPBuilder(...)
service.request(Method.POST, ContentType.JSON) {
uri.path = ...
body = ...
response.'200' = { resp ->
logInfo resp.statusLine
}
response.success = { resp, result ->
logInfo resp.statusLine
}
response.failure = { resp ->
logError resp.statusLine
}
}
Essentially do not try to parse the body, if response is 200.

Apparently the problem was caused by non-standard WS response: HTTP status 200 and empty response body. Either HTTP status 204 is expected, or valid XML body and status 200.
I have reported an issue at WS providers. Hopefully it will get resolved. I am marking the question as answered
Thanks #tim_yates and #Ian Roberts for your helpful comments.

Related

Failed to pass the challenge for domain

Using certbot fails to generate certificate with this error:
org.shredzone.acme4j.exception.AcmeException: Failed to pass the challenge for domain www.
mysampledomain123.com, ... Giving up.
I manually checked the challenge file and got
http://www.mysampledomain123.com/.well-known/acme-challenge/jU--PkDrn5tDZw2RN6NNJHbPD00ovHFkLFvN3mJdeQX
Inside the file:
jU--PkDrn5tDZw2RN6NNJHbPD00ovHFkLFvN3mJdeQX.tuMr-UijwpsJ1KVZkdWTYgodWZ2SxxKdB7_CMAAEfpg
And here's the complete HTTP response header:
Accept-Ranges: bytes
Connection: keep-alive
Content-Encoding: gzip
Content-Type: text/plain;charset=iso-8859-1
Date: Sun, 16 Feb 2020 14:15:22 GMT
Server: nginx/1.14.0 (Ubuntu)
Transfer-Encoding: chunked
Vary: Accept-Charset, Accept-Encoding, Accept-Language, Accept
X-Powered-By: MyServer
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 0
I'm wondering whether the problem is with the HTTP response headers or the content itself.
Any ideas would be appreciated.

Retrofit client and response with Transfer-Encoding: chunked

I'm working on a Android sample app that get film list from http://www.omdbapi.com/.
The REST service is:
http://www.omdbapi.com/?s=star&apikey=d497e644
I'm using Retrofit to write the client.
public interface OmdbApi {
#Streaming
#GET("./")
#Headers({"Cache-control: no-cache"})
Call<Search> search(#Query("s") String search, #Query("apikey") String apiKey);
#Streaming
#GET("./")
#Headers({"Cache-control: no-cache"})
Call<FilmDetail> getFilm(#Query("i") String uid, #Query("apikey") String apiKey);
}
The complete source code is available here.
When I run the application, I obtain the following response (taken from logcat):
OK http://www.omdbapi.com/?s=star&apikey=d497e644 (108ms)
Content-Type: application/json; charset=utf-8
Transfer-Encoding: chunked
Cache-Control: public, max-age=86400
Expires: Sat, 26 May 2018 14:28:18 GMT
Last-Modified: Fri, 25 May 2018 05:39:04 GMT
Vary: *, Accept-Encoding
X-AspNet-Version: 4.0.30319
X-Powered-By: ASP.NET
Access-Control-Allow-Origin: *
CF-Cache-Status: HIT
Server: cloudflare
CF-RAY: 4208b00c817b3db9-MXP
Connection: Keep-Alive
And the following error:
java.net.ProtocolException: unexpected end of stream
at okhttp3.internal.http1.Http1Codec$ChunkedSource.read(Http1Codec.java:455)
at okio.RealBufferedSource.read(RealBufferedSource.java:47)
okio.RealBufferedSource.exhausted(RealBufferedSource.java:57)
okio.InflaterSource.refill(InflaterSource.java:102)
okio.InflaterSource.read(InflaterSource.java:62)
okio.GzipSource.read(GzipSource.java:80)
okhttp3.logging.HttpLoggingInterceptor.intercept(HttpLoggingInterceptor.java:237)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:147)
okhttp3.internal.http.RealInterceptorChain.proceed(RealInterceptorChain.java:121)
okhttp3.RealCall.getResponseWithInterceptorChain(RealCall.java:200)
at okhttp3.RealCall.execute(RealCall.java:77)
at retrofit2.OkHttpCall.execute(OkHttpCall.java:180)
retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall.execute(ExecutorCallAdapterFactory.java:91)
com.abubusoft.filmfinder.service.repository.FilmRepository.lambda$findFilm$0$FilmRepository(FilmRepository.java:18)
com.abubusoft.filmfinder.service.repository.FilmRepository$$Lambda$0.run(Unknown Source:20)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1162)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:636)
at java.lang.Thread.run(Thread.java:764)
After a bit of investigation, I found that the problem is that the response has Transfer-Encoding: chunked. How can I resolve this problem?
Thank you.
After more investigation:
I remove the #Streaming annotations.. they aren't useful.
Tests that I did was on an emulator on a PC behind a firewall.
OkHttp had some problem about it many years ago, but now chunked transfer is completely managed.
On the same machine, invoking the same URL in a browser does not present any problems
I finally try on another machine, with a JUnit test and in Android emulator and I had no problem.
At last, I'm sure that code works, so is the environment that I used to develop the app has some problem with transfer-encoding chunked.
Complete source code is available here:
android app
junit test
I have to find exactly what is the problem, I'm sure now that it not Retrofit or my client definition or OkHttp.
I hope my experience can help other developers.
Byez

Google Drive API responds with 416 HTTP code

For some reason the previously working code stopped working and server started to respond with 416.
Here are the logs of HTTP client during failing interaction:
-------------- REQUEST --------------
GET https://www.googleapis.com/drive/v3/files/0B02Nopv3SQOvOVNKaDIwTEZ3MHd?alt=media
Accept-Encoding: gzip
Authorization: <Not Logged>
Range: bytes=0-33554431
User-Agent: My app Google-API-Java-Client Google-HTTP-Java-Client/1.22.0 (gzip)
-------------- RESPONSE --------------
HTTP/1.1 416 Requested range not satisfiable
Alt-Svc: quic=":443"; ma=2592000; v="39,38,37,35"
Server: UploadServer
Cache-Control: private, max-age=0
Content-Range: bytes */0
X-GUploader-UploadID: AEnB2UqBx9B09Lnr8tG761gdoz3DkhHSNO_OzHh1LkU6B2908v17rnBGQZSNW4ZVTjbRdFtvPWWIqZGdtSrTo6ZWN7YW9nxf6d
Vary: X-Origin
Vary: Origin
Expires: Mon, 11 Sep 2017 15:23:20 GMT
Content-Length: 225
Date: Mon, 11 Sep 2017 15:23:20 GMT
Content-Type: application/json; charset=UTF-8
I was trying to download a file which is around 200000 bytes, so I thought meaning of "chuck size" changed somewhere, so it could not give 33554431 bytes of a 282177 byte file. Tried changing that to a smaller value, but no success.
Drive.Files.Get get = drive.files().get(file.getId())
MediaHttpDownloader downloader = get.getMediaHttpDownloader()
downloader.directDownloadEnabled = false
localFile.newOutputStream()
get.executeMediaAndDownloadTo(stream)
Direct download does not work either, it just downloads "0" bytes.
Does anyone know how to overcome this issue?
416 Range Not
Satisfiable
error means the server is not able to serve the requested ranges. The
most likely reason is that the document doesn't contain such ranges,
or that the Range header value, though syntactically correct, doesn't
make sense.
One of the resolutions that may provide from this forum is to:
Add "Accept-Ranges: none" to our response headers.
It appeared to be a web interface when using Firefox. It uploaded "empty" files in certain cases.
https://productforums.google.com/forum/#!topic/drive/S03wEknc75g;context-place=forum/drive

Rest : Response message is null

I have a rest API which I am testing using Jmeter. The response message assertion for message "OK" is failing.
Following are the response headers I see
HTTP/1.1 200
Set-Cookie: JSESSIONID=BE7C763B232F61E6DCECFSDEDEDB;path=/test-service;HttpOnly
X-Application-Context: test-service:DEFAULT,dev:8098
Link:
X-Content-Type-Options: nosniff
X-XSS-Protection: 1; mode=block
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Pragma: no-cache
Expires: 0
X-Frame-Options: DENY
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 15 Feb 2017 09:14:30 GMT
Sampler Result
Sample Start: 2017-02-15 14:44:26 IST
Load time: 4422
Latency: 4418
Size in bytes: 4368
Headers size in bytes: 500
Body size in bytes: 3868
Sample Count: 1
Error Count: 1
Response code: 200
Response message:
When I test it through postman I get proper result
Can someone tell why this might be happening?
Note :
My Application is a spring boot app.
update :
this is not happening only in jmeter. I tried using Advance rest client
Got only the status code
If your response assertion is configured like the one given below, it shouldn't be failing. In case, if you are looking for the entire text "HTTP/1.1 200", ensure that "Response Headers" radio button is checked along with "Contains" in the pattern matching rules with text as "HTTP/1.1 200"
This is actually not jmeter issue.
HTTP/2 does not define a way to carry the version or reason phrase that is included in an HTTP/1.1 status line.
https://github.com/spring-projects/spring-boot/issues/6548
This is actually a Tomcat 8.5 issue as it starts to support HTTP/2 specifications.
To quote the comment in the relevant part of the Tomcat "Clients should ignore it (RFC 7230) and it just wastes bytes."

Payeezy api integration - check events

I am trying to check my payeezy events online using follwoing url and api
https://developer.payeezy.com/payeezy-api/apis/get/events
I have set apikey and token and generated HMAC key for each time I generate request.
But getting following error response
Connection:
keep-alive
Content-Length:
206
Content-Type:
application/json
Date:
Fri, 27 May 2016 03:56:13 GMT
Server:
Apigee Router
{
"fault": {
"faultstring": "Execution of Hmac-authentication failed with error: Exception thrown from JavaScript : HMACERROR (hmac_helper#196)",
"detail": {
"errorcode": "steps.javascript.ScriptExecutionFailed"
}
}
}
Can anyone suggest why this happening with me :(

Categories