1

I have a code in java that sends byte[] to CQ servlet using POST. The code for sending is :

        URL url = new URL("http://localhost:4503/bin/services/updateslafile");   
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();                    
        String authStr = "admin:admin";
        // encode data on your side using BASE64
        byte[] bytesEncoded = Base64.encodeBase64(authStr.getBytes());
        String authEncoded = new String(bytesEncoded);                                                                          
        connection.setRequestProperty("Authorization", "Basic "+authEncoded);
        connection.setDoOutput(true);      
        connection.setRequestMethod("POST");   
        connection.setRequestProperty("fileName", "test.docx");
            byte[] input;//assume input initialized with some .docx file content as byte[]
        OutputStream outs = connection.getOutputStream();
        outs.write(input);
        outs.flush();   
        outs.close();

        //for response reading
        StringBuffer strBuffer = new StringBuffer();
        InputStream inputStream = connection.getInputStream();
        byte[] b = new byte[1024];
        while ( is.read(b) != -1)
            strBuffer.append(new String(b));
        System.out.println("strbuffer : "+strBuffer.toString());

The code in the servlet(extends SlingAllMethodsServlet) for reading the byte[] is like below :

            String fileName = request.getHeader("fileName");
            // opens input stream of the request for reading data

           InputStream inputStream = request.getInputStream();// This line giving error
            String filePath = "/home/usr/documents/"+fileName;
            // opens an output stream for writing file
            FileOutputStream fileOuputStream = new FileOutputStream(filePath); 

            byte[] buffer = new byte[BUFFER_SIZE];
            int bytesRead = -1;
            LOGGER.info("Receiving data...");
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                     fileOuputStream.write(buffer, 0, bytesRead);
            }
            LOGGER.info("Data received.");
            fileOuputStream.close();
            inputStream.close();

Now when I run the code in the error log I am getting some error

08.03.2016 15:19:37.162 ERROR [127.0.0.1 [1457430567960] POST /bin/services/updateslafile HTTP/1.1] org.apache.sling.engine.impl.SlingRequestProcessorImpl service: Uncaught Throwable java.lang.IllegalStateException: Request Data has already been read

Apart from this error I am also getting below error but I think this isn't relevant.

08.03.2016 15:17:31.092 ERROR [qtp87442412-7274] org.apache.sling.engine.impl.parameters.ParameterSupport getRequestParameterMapInternal: Error parsing request java.lang.IllegalArgumentException: Bad escape sequence: %ۑ

I know request.getInputStream() is giving some issue but not sure how to fix it

samir
  • 339
  • 6
  • 19

4 Answers4

4

When receiving a multipart message, the servlet implementation behind Sling and HTTPServletRequest will parse the multipart parameters out of the input stream for you, but will read the stream in doing so. This makes the request.getInputStream(); unusable, but the multipart objects will be parsed and available through request.getRequestParameterMap(). A helpful link on handling multipart file uploads is available here: (EDIT - new link: Handling File Upload in CQ)

GuillaumeCleme
  • 317
  • 1
  • 2
  • 10
0

I think this is because you are missing multipart information, take a look at Sending files using POST with HttpURLConnection and update your code, It should probably resolve the issue.

Community
  • 1
  • 1
apurvc
  • 740
  • 4
  • 12
  • Actually I am not sending the file as attachment so even if I am specifying multipart its not working. This is typical CQ problem, not related with normal java servlet but specific to CQ5 servlet. The data I am sending is sequence of byte[]. – samir Mar 09 '16 at 07:00
0

ok I got it working by handling it in another way. Now I am sending the byte[] as a string to servlet in parameter as below :

connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("fileName", filename);
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream());
writer.write("inputstream=" + Arrays.toString(input));
writer.close();

And then in the servlet reading the parameter as below :

String encodingScheme = "UTF-8";
request.setCharacterEncoding(encodingScheme);
String requestStr = request.getParameter("inputstream");
byte[] rawRequestMsg = requestStr.getBytes();

Like this I am getting the byte[] in servlet but the issue here is that when I write this byte[] sequence to a file, instead of writing content only bytes are written so I see only numbers inside the file. Code for writing in the file which I used is below :

FileOutputStream fileOuputStream = new FileOutputStream(uploadedFileLocation);
fileOuputStream.write(byteArray); // byteArray is byte[]  
fileOuputStream.close();
samir
  • 339
  • 6
  • 19
0

Not an answer to this exact problem, but Similar exception is also triggered when sending json data from JS Ajax as a POST call to AEM servlet API.

Example: Sending a simple form data as JSON to your AEM Servlet API.

When we try to use request.getInputStream(), we get the same exception: Uncaught Throwable java.lang.IllegalStateException: Request Data has already been read.

Just make sure that in your ajax call in JS, you send dataType: "json", contentType: "application/json",

Example:

$.ajax({
   type: "POST",
   url: "/content/myproject/api/form-submit",
   data : JSON.stringify(objData),
   dataType: "json",
   contentType: "application/json",
   success: function (response) {
   sucessHandler();
   }

if these attributes are not present, sling servlet handles the raw data in a different way, and this also sometimes triggers the same exception.