The log shows my REST reader getting an IllegalStateException when trying to read from an HTTP connection that has been closed (not by me). I think it should throw an IOException instead. This is with the okhttp 2.0 master branch.
java.lang.IllegalStateException: closed
at okio.RealBufferedSink.flush(SourceFile:152)
at com.squareup.okhttp.internal.http.HttpEngine.readResponse(SourceFile:570)
at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.execute(SourceFile:384)
at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getResponse(SourceFile:331)
at com.squareup.okhttp.internal.http.HttpURLConnectionImpl.getHeaderFields(SourceFile:178)
at com.squareup.okhttp.internal.http.DelegatingHttpsURLConnection.getHeaderFields(SourceFile:178)
at com.squareup.okhttp.internal.http.HttpsURLConnectionImpl.getHeaderFields(SourceFile:1)
at com.levelup.touiteur.DBCookieMaster.setCookieResponse(SourceFile:460)
at com.levelup.http.AbstractHttpRequest.setResponse(SourceFile:159)
at com.levelup.http.twitter.HttpTwitterPost.setResponse(SourceFile:66)
at com.levelup.http.HttpClient.getQueryResponse(SourceFile:165)
at com.levelup.http.HttpClient.getInputStream(SourceFile:187)
at com.levelup.http.HttpClient.parseRequest(SourceFile:274)
at com.levelup.http.HttpClient.getStringResponse(SourceFile:312)
at com.levelup.http.twitter.TwitterOAuth.getRequestTokener(SourceFile:165)
at com.levelup.http.twitter.TwitterOAuth.queryJSONObject(SourceFile:72)
at com.levelup.http.twitter.TwitterOAuth.queryJSONObjectOnly(SourceFile:68)
at com.plume.twitter.TwitterClient.queryJSONObjectOnly(SourceFile:641)
at com.plume.twitter.TwitterClient$ProfileUpdateBuilder.updateProfile(SourceFile:1070)
at com.levelup.touiteur.ProfileTwitter$2$1.execute(SourceFile:554)
at com.levelup.touiteur.ActivityTouiteur$BusyWorkingThread.run(SourceFile:595)```
This stacktrace suggests that you're closing the response stream. You can fix this either by upgrading to the latest 2.0 snapshot, or avoid closing the stream.
Please let me know if that fixes it!
OK I'll try that. Here's the Crashlytics log corresponding to the issue. It's not related to a particular device or Android version: http://crashes.to/s/bdabd1d8d45
I think this one might be related, but maybe not. Crashlytics trace
java.lang.IllegalStateException: state: 6
at com.squareup.okhttp.internal.http.HttpConnection$AbstractSource.endOfInput(SourceFile:391)
at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSource.read(SourceFile:455)
at okio.RealBufferedSource$1.read(SourceFile:168)
at java.io.InputStream.read(InputStream.java:157)
at com.levelup.picturecache.internal.PictureJobList.downloadInTempFile(SourceFile:407)
at com.levelup.picturecache.internal.PictureJobList.run(SourceFile:143)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
at java.lang.Thread.run(Thread.java:1019)
I just checked and my snapshot has only one difference with the current okhttp 2.0 master, the MediaType dangling semicolon. So I don't think it will make much difference.
Got it. I'll study your code to see what the heck could be the difference. The one that really confuses me is the IllegalStateException on a closed sink. That should only happen if you close() 2x.
This is still happening in 2.0.0 RC1. I get this exception (generated because I already caught an IllegalStateException). At that stage I haven't closed/disconnected the HttpUrlConnection yet.
java.lang.IllegalStateException: closed
at okio.RealBufferedSink.flush(SourceFile:169)
at com.squareup.okhttp.internal.http.HttpEngine.readResponse(SourceFile:660)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.execute(SourceFile:385)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponse(SourceFile:330)
at com.squareup.okhttp.internal.huc.HttpURLConnectionImpl.getResponseCode(SourceFile:425)
at com.squareup.okhttp.internal.huc.DelegatingHttpsURLConnection.getResponseCode(SourceFile:105)
at com.squareup.okhttp.internal.huc.HttpsURLConnectionImpl.getResponseCode(SourceFile:25)
at com.levelup.http.HttpException$Builder.setHTTPResponse(SourceFile:276)
at com.levelup.http.HttpException$Builder.(SourceFile:191)
at com.levelup.http.signpost.HttpExceptionSigned$Builder.(SourceFile:25)
at com.levelup.http.twitter.TwitterException$Builder.(SourceFile:58)
at com.levelup.http.twitter.HttpTwitterPost.newException(SourceFile:48)
at com.levelup.http.HttpClient.getQueryResponse(SourceFile:193)
at com.levelup.http.HttpClient.getInputStream(SourceFile:219)
at com.levelup.http.HttpClient.parseRequest(SourceFile:312)
at com.levelup.http.HttpClient.getStringResponse(SourceFile:374)
at com.levelup.http.twitter.TwitterOAuth.getRequestTokener(SourceFile:71)
at com.levelup.http.twitter.TwitterOAuth.queryJSONObject(SourceFile:27)
at com.levelup.http.twitter.TwitterOAuth.queryJSONObjectOnly(SourceFile:23)
at com.plume.twitter.TwitterClient.queryJSONObjectOnly(SourceFile:700)
at com.plume.twitter.TwitterClient.access$400(SourceFile:68)
at com.plume.twitter.TwitterClient$StatusUpdateBuilder.sendUpdate(SourceFile:1312)
at com.levelup.touiteur.outbox.OutemTwitterSendStatus.send(SourceFile:224)
at com.levelup.touiteur.outbox.Outem.run(SourceFile:88)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
at java.lang.Thread.run(Thread.java:841)
@robUx4 thanks for your patience. Who is closing the request body?
No idea, the call to getResponseCode() is done in a finally {} block, there might have been an exception before that. At that stage the output stream is either not opened or already closed, in another finally {} block.
Please reopen this if it's still a problem.
Hello,
OkHttp 2.2.0
When i use
System.out.println(response.body().string());
String ceyson = response.body().string();
there is exception like this (for String ceyson = response.body().string(); )
W/System.err﹕ java.lang.IllegalStateException: closed
W/System.err﹕ at com.squareup.okhttp.internal.http.HttpConnection$FixedLengthSource.read(HttpConnection.java:405)
W/System.err﹕ at okio.Buffer.writeAll(Buffer.java:705)
W/System.err﹕ at okio.RealBufferedSource.readByteArray(RealBufferedSource.java:92)
W/System.err﹕ at com.squareup.okhttp.ResponseBody.bytes(ResponseBody.java:57)
W/System.err﹕ at com.squareup.okhttp.ResponseBody.string(ResponseBody.java:83)
But when i use only String ceyson = response.body().string(); it is ok
Same here for com.squareup.okhttp:okhttp:2.2.0, reading the body twice with bytes() throws this exception.
From ResponseBody.bytes():
try {
bytes = source.readByteArray();
} finally {
Util.closeQuietly(source);
}
Perhaps cache the bytes for later use after closing the source?
We aren't going to cache the bytes. That could waste a serious amount of memory. If you need to read the response body multiple times, you need to do your own buffering.
That's what I did. It might be good to add to documentation though that you cannot read the body twice. Took me some time to figure out.
@antonj which documentation did you read before you ran into the problem?
@swankjesse I looked for documentation in ResponseBody and the string() and bytes() methods. My use case for reading twice was that I was passing around a Response instance through some RxJava flatMap functions to do some extra checks for a specific API.
Thanks for a great lib btw.
//return String or null
public static void doGetRequest(String url, final File destFile, final GSResponseListener responseListener) {
getInstance().getOkHttpClient().newCall(new Request.Builder().url(url).get().build()).enqueue(new Callback() {
@Override
public void onFailure(Request request, IOException e) {
if (responseListener != null)
responseListener.process(null);
}
@Override
public void onResponse(final Response response) throws IOException {
if (response != null && response.isSuccessful()) {
String content = response.body().string();
if (destFile != null)
writeTextToFile(content, destFile);
if (responseListener != null)
responseListener.process(content);
} else if (responseListener != null)
responseListener.process(null);
}
});
}
//return String or null
public static void doGetRequest(String url, final GSResponseListener responseListener) {
doGetRequest(url, null, responseListener);
}
public static final String ENCODING_UTF8 = "UTF-8";
public static boolean writeTextToFile(String content, File file) {
return writeTextToFile(content, null, file);
}
public static boolean writeTextToFile(String content, Throwable throwable, File file) {
boolean isAppendSuccess = false;
try {
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(new FileOutputStream(file, false), ENCODING_UTF8);
PrintWriter printWriter = new PrintWriter(outputStreamWriter, true);
printWriter.print(content);
if (throwable != null)
throwable.printStackTrace(printWriter);
printWriter.flush();
printWriter.close();
isAppendSuccess = true;
} catch (Exception e) {
e.printStackTrace();
}
return isAppendSuccess;
}
I have an issue on this.Cannot read the body twice.
I'm getting this error from Crashlytics on Android and I have no idea how to solve it. Not much information. I think the only dependency I am using that uses okhttp is picasso
Most helpful comment
Hello,
OkHttp 2.2.0
When i use
there is exception like this (for
String ceyson = response.body().string();)But when i use only
String ceyson = response.body().string();it is ok