Solved

Reading client-posted data via Tomcat servlet

Posted on 2003-11-03
18
2,076 Views
Last Modified: 2013-11-24
Hi,

I'm doing some simple client/servlet communication using Tomcat, using POST's via an HttpURLConnection.

I'm seeing my data at the servlet side via getInputStream(), but I can't decode it to a String, even by using InputStreamReader (which is supposed to do that). If I send a 5 character String, at the servlet I see "^@^@^@^@^@". I've tried constructing a String from a byte[], but it doesn't decode, either.

I've tried writing the data as text with PrintWriter on the client side, and then reading text on the servlet side with getReader(), but getReader() returns null, even though a call to HttpServletRequest's getContentLength() returns non-zero (and shows the correct number of characters and/or bytes).

Reading the docs and api's leads me to believe this should be very straightforward, but it's just not working.  I'm beginning to wonder if the problem is within Tomcat itself.

Any thoughts would be greatly appreciated!!!

Thanks in advance!

- Dean

0
Comment
Question by:dzarras
  • 8
  • 4
  • 3
  • +1
18 Comments
 
LVL 86

Expert Comment

by:CEHJ
ID: 9672396
Please post the shortest extracts you can from both ends
0
 

Author Comment

by:dzarras
ID: 9672681
Client side:

 URL location = null;
        URLConnection con = null;
        try{

            System.err.println("URL is [" + url + "]");
            location = new URL(url);

            con = location.openConnection();

            if (con instanceof HttpURLConnection){
                HttpURLConnection httpCon = (HttpURLConnection) con;
                httpCon.setRequestMethod("POST");

            }

            con.setUseCaches(false);
            con.setDoInput(true);
            con.setDoOutput(true);
            con.connect();

            DataOutputStream out = new DataOutputStream(con.getOutputStream());

        System.err.println("POST is [" + content + "]");
        out.writeBytes(content);
        out.flush();
        out.close();


Server side:

(From within the service method, where I have an HttpServletRequest instance 'request', I call this method using request.getContentLength() and request.getInputStream())


 private String readStringFromDataOutputStream(int length,
                                                  ServletInputStream instream) throws IOException
    {

        DataInputStream dis = new DataInputStream(instream);

        byte[] raw = new byte[length];

        dis.read(raw,0,length);
     
        String body = new String(raw);

       return body;
}


In the case of sending a simple string to the servlet "ABCDE", the method above returns the string "^@^@^@^@^@".

My real intention is to send a very large string to the servlet.

Thanks for your interest -- I look forward to further feedback.

Regards,

- Dean
0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9672734
You need to do this as well:

con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");

and

>>out.writeBytes(content);

should be

String encoded = URLEncoder.encode(content, "UTF8");
out.writeBytes(encoded);

You need to decode it on the other side too.

There is no apparent need to use DataXStream if you're just writing Strings

0
 

Author Comment

by:dzarras
ID: 9673606

I tried the above but it made no difference.

The contentType (as returned by request.getContentType() was already returning the value you show above anyway, but setting it in the Connection from the client side did not make a difference.    

Also, I agree that I shouldn't have to use DataInput/Output/Stream, which would obviate the need to call writeBytes(), as you suggest above.

My test string "ABCDE" doesn't encode to anything different (unlike a string with spaces or '&', etc), so the encoding shouldn't (and doesn't) make a difference in this case.



0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9673632
>>My test string "ABCDE" doesn't encode to anything different

No - it won't. But you might need to encode it later.

Can you post your new code altered to get rid of DataXStreams. Also use Readers for Strings
0
 

Author Comment

by:dzarras
ID: 9673722
Writer:

private void writeStringAsText(OutputStream outputStream, String content) throws UnsupportedEncodingException
    {
        PrintWriter printer = new PrintWriter(outputStream);

        String encoded = URLEncoder.encode(content,"UTF-8");

        System.err.println("Cotent is [" + content + "], encoded = [" + encoded + "]");

        printer.print(encoded);
        printer.flush();
        printer.close();
    }

Here's the reader, trying to get Strings one line at a time:

private String readStringFromReader(BufferedReader reader)
    {
       int computedLen = 0;
       int linesRead = 0;

        StringBuffer sBuf = new StringBuffer();
        try{
            String inputStr = reader.readLine();
            if (inputStr != null){
                String line = URLDecoder.decode(inputStr,"UTF-8");
                toLog(LOG_LEVEL_MANDATORY,"First line is [" + line + "]");

                while (line != null){
                    sBuf.append(line);
                    toLog(LOG_LEVEL_MANDATORY,line);
                    computedLen += line.length();
                    inputStr = reader.readLine();
                    if (inputStr != null){
                        line = URLDecoder.decode(inputStr,"UTF-8");
                    }
                    else{
                        line = null;
                    }
                    linesRead++;
                }
            }
            else{
                toLog(LOG_LEVEL_MANDATORY,"Never got first string");
            }
        }
        catch (Exception e){
            e.printStackTrace();
        }

        String theString = sBuf.toString();
        String results = "sBuf = [" + theString + "] linesRead = " + linesRead + " computed = " + computedLen;

        toLog(LOG_LEVEL_MANDATORY,results);

        return theString;
    }

The above method never gets a String from the reader, (ie, linesRead is 0).

The reader, btw, is simply HttpServletRequest's getReader().


0
 
LVL 86

Expert Comment

by:CEHJ
ID: 9673870
How do you get the reader in the first place?
0
 

Author Comment

by:dzarras
ID: 9673930
From the implementation of HttpServlet's doPost method, which is called by the container upon receiving a POST:
 

protected void doPost(HttpServletRequest httpServletRequest,
                          HttpServletResponse httpServletResponse)
            throws ServletException, IOException
    {

       BufferedReader reader = httpServletRequest.getReader();

0
DevOps Toolchain Recommendations

Read this Gartner Research Note and discover how your IT organization can automate and optimize DevOps processes using a toolchain architecture.

 
LVL 92

Expert Comment

by:objects
ID: 9674375
I don't see any need to encode/decode the string.

Use println instead of print on the server.
0
 
LVL 92

Expert Comment

by:objects
ID: 9674407
I'm assuming you are reading multiple lines because the source string may contain eol chars. The code to read the string can be simplified as follows.

                while ((line = reader.readLine()) != null){
                    sBuf.append(line);
                    toLog(LOG_LEVEL_MANDATORY,line);
                    computedLen += line.length();
                    linesRead++;
                }
0
 

Author Comment

by:dzarras
ID: 9687501
Strange news...

Yesterday the "problem" disappeared, and making the suggested changes above did not cause the problem to disppear, or reappear if I removed them.     In other words, using the very straightforward approach of writing un-encoded text to the servlet, and reading it via getReader(), worked perfectly.

However today, it is failing again.   Clearly something's going on at Tomcat's level (this is version 4.1.18 -- I plan on upgrading to 4.1.29 today).

What I have learned is that the java.io.BufferedReader returned by HttpServletRequest's getReader() method is returning false when I call ready().   The reader's ready() should return true if the reader is capable of returning anything.

I'm exploring the above further.
0
 

Author Comment

by:dzarras
ID: 9687769
So what this boils down to so far, is

request.getContentLength() returns non-zero (indicating content has been received by the servlet), but request.getReader().ready() returns false and therefore, no data is returned from the reader.
0
 

Author Comment

by:dzarras
ID: 9689771
SOLVED

Encoding makes no difference.

Write the data out as text via a PrinterWriter, and in the URLConnection:

set

con.setRequestProperty("Content-Type", "text/html");

And, regardless, request.getReader().ready() always returns false, even if there is data there.

Hope this saves someone some grief.
0
 
LVL 92

Expert Comment

by:objects
ID: 9690618
> Encoding makes no difference.

told you :)
0
 

Author Comment

by:dzarras
ID: 11425354
"Abandoned" is fine, considering I basically solved the problem on my own.    I wasn't sure how to deal with such a situation (where it's solved but with no one earning any points).   I hope the answer is still helpful to someone else, however.
0
 

Accepted Solution

by:
modulo earned 0 total points
ID: 11537525
PAQed, with points refunded (500)

modulo
Community Support Moderator
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
json example 39 132
topping3 challenge 14 70
eclipse shortcuts 9 45
servlet example issue 6 31
I had a project requirement for a displaying a user workbench .This workbench would consist multiple data grids .In each grid the user will be able to see a large number of data. These data grids should allow the user to 1. Sort 2. Export the …
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
Viewers learn about the “for” loop and how it works in Java. By comparing it to the while loop learned before, viewers can make the transition easily. You will learn about the formatting of the for loop as we write a program that prints even numbers…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…

896 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now