Reading http request from socket with null check java - java

I'm reading HTTP request from socket input stream
StringBuilder request = new StringBuilder();
String inputLine;
while (!(inputLine = in.readLine()).equals("")) {
request.append(inputLine + "\r\n");
}
It's working but findbugs gives the following bug: Dereference of the result of readLine() without nullcheck. Request ends with "" not eof. So how can I check null value here?

Like that:
while ((inputLine = in.readLine()) != null) {
But I assume that you don't want a blank string, use apache commons:
while(StringUtils.isNotBlank(inputLine = in.readLine())) {
Edit:
Also +1 for sodium's comment. However in my opinion this:
("").equals(in.readLine())
is a bit unreadable.

Related

BufferedReader does not work well

Loading following URL with BufferedReader, but content is not delivered. Even though a plain browser can show content. So str will remain nil. Any idea why?
URL url = new URL("http://www.omdbapi.com/?t=zorr&y=&plot=short&r=json");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
while ((str = in.readLine()) != null) {}
Log.d("alma", str);
You are ignoring all of the lines that you are reading. You then exit the loop when str becomes null. So, your Log.d() call will always show null.
If you want to use the lines that you are reading, use str inside` your currently empty block:
while ((str = in.readLine()) != null) {
// do something with str
}
You might also wish to consider using a third-party library that offers a simpler API. OkHttp3, for example, makes getting a string response from a URL fairly easy.
try this:
URL url = new URL("http://www.omdbapi.com/?t=zorr&y=&plot=short&r=json");
BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
String str;
while ((str = in.readLine()) != null) {
Log.d("alma", str); // this should be here
}

Findbugs - handling null check and encoding in reading input stream

I added Findbugs plugin to my project and I suddenly started getting the following bug: Dereference of the result of readLine() without nullcheck
I have the following code which reads the http request line by line:
InputStream input = clientSocket.getInputStream();
String line;
while (!(line = in.readLine()).equals("")) {
...
}
I tried rewriting this into some other for with nullcheck:
String line = "";
while (line != null) {
line = in.readLine();
if (line.equals("")) return;
}
But this gets stuck forever (so it is not rewritten correctly). I am sorry for such a basic question but I can't seem to get it right...
Another thing that is marked as bug is Found reliance on default encoding in ..InputStream...
How can I specify encoding in InputStreamReader?
The fixed loop looks like so:
InputStream input = clientSocket.getInputStream();
String line;
while (null != (line = in.readLine())) {
if("".equals(line)) break;
...
}
Why? First of all, of the remote side (the client) closes the connection, readLine() will return null. That what the outer check guards against.
readLine() won't return at all if the client just stops sending data. So as long as the client keeps the connection open, your "fixed" loop hangs.
When comparing string literals, I always put them first:
"".equals(line))
never fails, even when line is null. It's also often more readable since you often want to know what you're comparing against; the variable which you want to check is less "informative".
Apparently readLine can return null, so you have to check it after the line = in.readLine();
Your updated code could still throw a NullPointerException, if readLine returned null.
I doubt that your change will work, since the check is being made on the previous value of line, thus, if your previous line was valid (but you where reading the last line) any subsequent calls can potentially yield a NullPointerException.
The go around this, usually the following pattern is applied:
InputStream input = clientSocket.getInputStream();
String line = "";
while ((line = in.readLine()) != null) {
...
}

get empty notification in production server

I develop a google glass app using mirror api. during development I used "Introspected tunnels to localhost" to receive the notification.
Now I uploaded my app on production server. So now I configure my callback URL as my domain name like https://www.mydomain.com:8443/notify. But I get empty notification.
in notify servlet:
BufferedReader notificationReader = new BufferedReader(
new InputStreamReader(request.getInputStream()));
String notificationString = "";
int lines = 0;
while (notificationReader.ready()) {
notificationString += notificationReader.readLine();
lines++;
if (lines > 1000) {
throw new IOException(
"Attempted to parse notification payload that was unexpectedly long.");
}
}
LOG.info("\ngot raw notification : " + notificationString);
in catalina.out
Feb 13, 2014 12:51:48 PM com.google.glassware.NotifyServlet doPost
INFO: got raw notification :
How can I solve it?
StringBuffer stringBuffer = new StringBuffer();
String line = "";
BufferedReader bufferReader = new BufferedReader(
new InputStreamReader(request.getInputStream()));
while ((line = bufferReader.readLine()) != null) {
stringBuffer.append(line);
}
notificationString = stringBuffer.toString();
Hope it will works.
I think you should use readLine() method.One of the answer from stack overflow suggest not using ready() for such requirements.
The ready method tells us if the Stream is ready to be read.
Imagine your stream is reading data from a network socket. In this
case, the stream may not have ended, because the socket has not been
closed, yet it may not be ready for the next chunk of data, because
the other end of the socket has not pushed any more data.
In the above scenario, we cannot read any more data until the remote
end pushes it, so we have to wait for the data to become available, or
for the socket to be closed. The ready() method tells us when the data
is available.
I had this same problem and I changed the code to look like this:
StringBuffer jb = new StringBuffer();
String notificationString = "";
String line = "";
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
jb.append(line);
}
notificationString = jb.toString();
Try This One:
while(notificationReader.ready()) {
notificationString = notificationString.concat(notificationReader.readLine());
lines++;
}

bufferedreader - read into stringbuffer and not string

I have the following code. What I would like to do is read each line from the BufferedReader directly into a StringBuffer to reduce memory overhead. Once it gets to the end of the data stream I would like it to exit the while loop.
StringBuffer line = new StringBuffer();
URL url = new URL("a url");
BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream()));
int count = 0;
while(line.append(reader.readLine()) != null){
System.out.println(line.toString());
line.delete(0,line.length());
}
It reads the stream fine but when I get to the end of the stream it returns null and keeps printing null without exiting the loop. Any
This while(line.append(reader.readLine()) != null) is basically the same as saying while(line.append(reader.readLine()).toString() != null) which is never likely to happen.
The other problem you might have, is null is actually being translated to a literal String of "null". That's why it's printing "null", the value isn't actually null - confused yet...
Instead, try something like...
String text = null;
while((text = reader.readLine()) != null){
line.append(text)
System.out.println(line.toString());
line.delete(0,line.length());
}
Updated
While I'm here, I might suggest that you are actually not saving your self anything.
readLine will create String object, which you're putting into a StringBuffer. You're not actually saving any memory, but rather complicating the process.
If you're really worried about creating lots of String objects in memory, then use BufferedReader#read(char[]) instead. Append the resulting character array to the StringBuffer.
Also, unless you need synchronized access to the StringBuffer, use StringBuilder instead, it's faster.
This works perfectly. You just have to catch the NUllPointerException
while(line.append(reader.readLine().toString()) != null){
You could try the same with this for-loop:
for (String line; (line = reader.readLine()) != null;) {
System.out.println(line); // Or whatever
}

BufferedReader not stating 'ready' when it should

I am trying to read text from a web document using a BufferedReader over an InputStreamReader on an URL (to the file on some Apache server).
String result = "";
URL url = new URL("http://someserver.domain/somefile");
BufferedReader in = null;
in = new BufferedReader(new InputStreamReader(url.openStream(), "iso-8859-1"));
result += in.readLine();
Now this works just fine. But Obviously I'd like the reader not to just read one line, but as many as there are in the file.
Looking at the BufferedReader API the following code should do just that:
while (in.ready()) {
result += in.readLine();
}
I.e. read all lines while there are more lines, stop when no more lines are there. This code does not work however - the reader just never reports ready() = true!
I can even print the ready() value right before reading a line (which reads the correct string from the file) but the reader will report 'false'.
Am I doing something wrong? Why does the BufferedReader return 'false' on ready when there is actually stuff to read?
ready() != has more
ready() does not indicate that there is more data to be read. It only shows if a read will could block the thread. It is likely that it will return false before you read all data.
To find out if there is no more data check if readLine() returns null.
String line = in.readLine();
while(line != null){
...
line = in.readLine();
}
Another way you can do this that bypasses the in.ready() is something like:
while ((nextLine = in.readLine()) != null) {
result += nextLine;
}
You will just continue reading until you are done. This way you do not need to worry about the problem with in.ready().
I think the standard way to write this is to just attempt to read the line and verify that it returned sometime. Something like this:
while ((String nextLine = in.readLine()) != null) {
//System.out.println(nextLine);
result += nextLine;
}
So you just continue to go until you get null returned from the stream. See here for extra information:
http://download.oracle.com/javase/1.5.0/docs/api/java/io/BufferedReader.html#readLine()
The BufferedReader.ready() method is behaving as specified:
The Reader.ready() javadoc says the following:
[Returns] true if the next read() is guaranteed not to block for input, false otherwise. Note that returning false does not guarantee that the next read will block.
Then the BufferedReader.ready() javadoc says the following:
Tells whether this stream is ready to be read. A buffered character stream is ready if the buffer is not empty, or if the underlying character stream is ready.
If you put these two together, it is clear that BufferedReader.ready() can return false in situations where are characters available. In short, you shouldn't rely on ready() to test for logical end-of-file or end-of-stream.
This is what we have been using consistently for years - not sure if it is the "standard" method. I'd like to hear comments about the pros and cons of using URL.openURLStream() directly, and if that is causing the OP's problems. This code works for both HTTP and HTTPS connections.
URL getURL = new URL (servletURL.toString() + identifier+"?"+key+"="+value);
URLConnection uConn = getURL.openConnection();
BufferedReader br = new BufferedReader (new
InputStreamReader (uConn.getInputStream()));
for (String s = br.readLine() ; s != null ; s = br.readLine()) {
System.out.println ("[ServletOut] " + s);
// do stuff with s
}
br.close();
Basically the BufferedReader.ready() method can be used for checking whether the underlying stream is ready for providing data to the method caller.... else we can wait the thread for some time till it becomes ready.
But the real problem is that after we completely read the data stream, it will throw false..
so we didn't know whether the stream is fully read OR underlying stream is busy....
If you want to use in.ready(), the following worked for me well:
for (int i = 0; i < 10; i++) {
System.out.println("is InputStreamReader ready: " + in.ready());
if (!in.ready()) {
Thread.sleep(1000);
} else {
break;
}
}

Categories

Resources