why readLine() works, and readUTF() always throws IOException - java

I send a post request to an address, and this address will return a xml format data back.
I can print out the data byreadLine(), but when i use readUTF(), it always throws IOException. below is the code
DataInputStream input = new DataInputStream(urlCon.getInputStream());
String inputLine = "";
if((inputLine = input.readUTF()) != null) {
System.out.println(inputLine.toString());
}
input.close();
why readUTF() does not work? is it because the data is xml format?

If you're reading lines, use readLine(). Data to be read with readUTF() must have been written with writeUTF(). See the Javadoc.
NB readUTF() doesn't return null, so testing for it is futile.

Related

Server cannot read entire content

I have a servlet which receives via POST method a large JSON string (> 10,000 characters).
If i read the content of the request like this:
try(Reader reader = new InputStreamReader(new BufferedInputStream(request.getInputStream()), StandardCharsets.UTF_8))
{
char[] buffer = new char[request.getContentLength()];
reader.read(buffer);
System.out.println(new String(buffer));
}
i donĀ“t get the entire content! The buffer size is correct. But the length of the created string is not.
But if i do it like this:
try(BufferedInputStream input = new BufferedInputStream(request.getInputStream()))
{
byte[] buffer = new byte[request.getContentLength()];
input.read(buffer);
System.out.println(new String(buffer, StandardCharsets.UTF_8));
}
it works perfectly.
So where am i wrong in the first case?
The way you are using InputStreamReader is not really the intended way. A call to read is not guaranteed to read any specific number of bytes (it depends on the stream you are reading from), which is why the return value of this method is the number of bytes that were read. You would need to keep reading from the stream and buffering until it indicates it has reached the end (it will return -1 as the number of bytes that were read). Some good examples of how to do this can be found here: Convert InputStream to byte array in Java
But since you want this as character data, you should probably use request.getReader() instead. A good example of how to do this can be found here: Retrieving JSON Object Literal from HttpServletRequest

Why output is incomplete using OutputStreamWriter with GZIPOutputStream?

I'm hoping someone can shed light on a problem I'm having with the code below.
private static String encode(String data) throws IOException {
try (
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream is = new ByteArrayInputStream(data.getBytes());
BufferedReader br = new BufferedReader(new InputStreamReader(is));
OutputStreamWriter writer = new OutputStreamWriter(new GZIPOutputStream(out));
) {
char[] charBuffer = new char[data.length()];
while (br.read(charBuffer) != -1) {
writer.write(charBuffer);
}
// writer.close();
return new String(Base64.encodeBase64(out.toByteArray()));
}
}
My test value is
This is some text that I can test some base64 encoding with.
I am getting a strange problem with the encoded value
when writer.close is commented out, my output is
H4sIAAAAAAAAAA==
When it's not commented, my output is
H4sIAAAAAAAAACWMzQ2DMBSD70jdwRP0VLED9y7wACuJRJKKZ37GJxTJF/uz/Y3J0eQ1E+IpKJowYLLSvOshozn7D1imOqcScCTF96sbYBmB0p0ZXKuVQPzWOi7M/1b747PjjN2WjRd08DfZcwAAAA==
This second output is the correct value and can be decoded back into the original value.
It is my understanding that the process is as follows:
Try code is executed
Return value is evaluated and stored
Resources are all closed
The return value is returned.
Why then does the writer need to be closed for the output to be correct?
A GZIP output stream has to be told when to finish the compression and write the result to the underlying stream. close() implicitely flushes the writer and calls finish() on the GZIP stream.
So, call at least flush() on the writer and finish() or close() of the GZIP stream, or close the writer, which will do all that and won't hurt anyway.
Its because when we close the writer it flushes the stream. When you dont close the writer it does not get flushed (Buffer is flushed automatically only when it gets full or it is closed). So u can do it explicitly by writing
writer.flush()

Saving incoming HTTP Post request content [duplicate]

I'm trying to get the post data in Java. Seems like it should be one of the simplest things to do right? I mean, HttpServletRequest.getParameter has to do it right? So how can you get the raw post data?
I found HttpServletRequest get JSON POST data and used Kdeveloper's code to pull the post data from a request. It works, but theres a catch: I can only get that post data once.
Heres the method I made from Kdeveloper's code:
public static String getPostData(HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader = req.getReader();
reader.mark(10000);
String line;
do {
line = reader.readLine();
sb.append(line).append("\n");
} while (line != null);
reader.reset();
// do NOT close the reader here, or you won't be able to get the post data twice
} catch(IOException e) {
logger.warn("getPostData couldn't.. get the post data", e); // This has happened if the request's reader is closed
}
return sb.toString();
}
Previously I had closed the reader at the end of this method, but that caused exceptions when the method ran more than once on the same request. Without closing it, no exceptions happen, but the method returns an empty string.
Honestly, there should just be an exposed req.getPostData() method - did no one think that would be useful?
So how can I write this method such that it always returns the correct post data?
The request body is available as byte stream by HttpServletRequest#getInputStream():
InputStream body = request.getInputStream();
// ...
Or as character stream by HttpServletRequest#getReader():
Reader body = request.getReader();
// ...
Note that you can read it only once. The client ain't going to resend the same request multiple times. Calling getParameter() and so on will implicitly also read it. If you need to break down parameters later on, you've got to store the body somewhere and process yourself.
We had a situation where IE forced us to post as text/plain, so we had to manually parse the parameters using getReader. The servlet was being used for long polling, so when AsyncContext::dispatch was executed after a delay, it was literally reposting the request empty handed.
So I just stored the post in the request when it first appeared by using HttpServletRequest::setAttribute. The getReader method empties the buffer, where getParameter empties the buffer too but stores the parameters automagically.
String input = null;
// we have to store the string, which can only be read one time, because when the
// servlet awakens an AsyncContext, it reposts the request and returns here empty handed
if ((input = (String) request.getAttribute("com.xp.input")) == null) {
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while((line = reader.readLine()) != null){
buffer.append(line);
}
// reqBytes = buffer.toString().getBytes();
input = buffer.toString();
request.setAttribute("com.xp.input", input);
}
if (input == null) {
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.print("{\"act\":\"fail\",\"msg\":\"invalid\"}");
}
This worked for me: (notice that java 8 is required)
String requestData = request.getReader().lines().collect(Collectors.joining());
UserJsonParser u = gson.fromJson(requestData, UserJsonParser.class);
UserJsonParse is a class that shows gson how to parse the json formant.
class is like that:
public class UserJsonParser {
private String username;
private String name;
private String lastname;
private String mail;
private String pass1;
//then put setters and getters
}
the json string that is parsed is like that:
$jsonData: { "username": "testuser", "pass1": "clave1234" }
The rest of values (mail, lastname, name) are set to null

Compare PHP hash_file with Java output

I have the output of UTF-8 hash_file that I need to calculate and check on my java client. Based on the hash_file manual I'm extracting the contents of the file and create the MD5 hash hex on Java, but I can't make them match. I tried suggestions on [this question] without success2.
Here's how I do it on Java:
public static String calculateStringHash(String text, String encoding)
throws NoSuchAlgorithmException, UnsupportedEncodingException{
MessageDigest md = MessageDigest.getInstance("MD5");
return getHex(md.digest(text.getBytes(encoding)));
}
My results match the ones from this page.
For example:
String jake: 1200cf8ad328a60559cf5e7c5f46ee6d
From my Java code: 1200CF8AD328A60559CF5E7C5F46EE6D
But when trying on files it doesn't work. Here's the code for the file function:
public static String calculateHash(File file) throws NoSuchAlgorithmException,
FileNotFoundException, IOException {
BufferedReader br = null;
StringBuilder sb = new StringBuilder();
try {
String sCurrentLine;
br = new BufferedReader(new FileReader(file));
while ((sCurrentLine = br.readLine()) != null) {
sb.append(sCurrentLine);
}
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
} finally {
try {
if (br != null) {
br.close();
}
} catch (IOException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
return calculateStringHash(sb.toString(),"UTF-8");
}
I verified that on the PHP side hash_file is used and UTF-8 is the encryption. Any ideas?
Your reading method removes all the end of lines from the file. readLine() returns a line, without its line terminator. Print the contents of the StringBuilder, and you'll understand the problem.
Moreover, a hashing algorithm is a binary operation. It operates on bytes, and returns bytes. Why are you transforming the bytes in the file into a String, to later transform the String back to an array of bytes in order to hash it. Just read the file as a byte array, using an InputStream, instead of reading it as a String. Then hash this byte array. This will also avoid using the wrong file encoding (your code uses the platform default encoding, which might not be the encding used to create the file).
I guess you are missing out on the new line characters from the file since you call br.readLine().
It is better to read the file into byte array, and pass that onto md.digest(...).

How to retrieve raw post data from HttpServletRequest in java

I'm trying to get the post data in Java. Seems like it should be one of the simplest things to do right? I mean, HttpServletRequest.getParameter has to do it right? So how can you get the raw post data?
I found HttpServletRequest get JSON POST data and used Kdeveloper's code to pull the post data from a request. It works, but theres a catch: I can only get that post data once.
Heres the method I made from Kdeveloper's code:
public static String getPostData(HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
try {
BufferedReader reader = req.getReader();
reader.mark(10000);
String line;
do {
line = reader.readLine();
sb.append(line).append("\n");
} while (line != null);
reader.reset();
// do NOT close the reader here, or you won't be able to get the post data twice
} catch(IOException e) {
logger.warn("getPostData couldn't.. get the post data", e); // This has happened if the request's reader is closed
}
return sb.toString();
}
Previously I had closed the reader at the end of this method, but that caused exceptions when the method ran more than once on the same request. Without closing it, no exceptions happen, but the method returns an empty string.
Honestly, there should just be an exposed req.getPostData() method - did no one think that would be useful?
So how can I write this method such that it always returns the correct post data?
The request body is available as byte stream by HttpServletRequest#getInputStream():
InputStream body = request.getInputStream();
// ...
Or as character stream by HttpServletRequest#getReader():
Reader body = request.getReader();
// ...
Note that you can read it only once. The client ain't going to resend the same request multiple times. Calling getParameter() and so on will implicitly also read it. If you need to break down parameters later on, you've got to store the body somewhere and process yourself.
We had a situation where IE forced us to post as text/plain, so we had to manually parse the parameters using getReader. The servlet was being used for long polling, so when AsyncContext::dispatch was executed after a delay, it was literally reposting the request empty handed.
So I just stored the post in the request when it first appeared by using HttpServletRequest::setAttribute. The getReader method empties the buffer, where getParameter empties the buffer too but stores the parameters automagically.
String input = null;
// we have to store the string, which can only be read one time, because when the
// servlet awakens an AsyncContext, it reposts the request and returns here empty handed
if ((input = (String) request.getAttribute("com.xp.input")) == null) {
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while((line = reader.readLine()) != null){
buffer.append(line);
}
// reqBytes = buffer.toString().getBytes();
input = buffer.toString();
request.setAttribute("com.xp.input", input);
}
if (input == null) {
response.setContentType("text/plain");
PrintWriter out = response.getWriter();
out.print("{\"act\":\"fail\",\"msg\":\"invalid\"}");
}
This worked for me: (notice that java 8 is required)
String requestData = request.getReader().lines().collect(Collectors.joining());
UserJsonParser u = gson.fromJson(requestData, UserJsonParser.class);
UserJsonParse is a class that shows gson how to parse the json formant.
class is like that:
public class UserJsonParser {
private String username;
private String name;
private String lastname;
private String mail;
private String pass1;
//then put setters and getters
}
the json string that is parsed is like that:
$jsonData: { "username": "testuser", "pass1": "clave1234" }
The rest of values (mail, lastname, name) are set to null

Categories