Read http request without losing data in it - java

Is there any way to read inputStream of a request without losing the data in it.
I am trying to take a raw copy of my request into string before processing it. But once I read the inputstream from request, the inputstream is changing to null so, I can't get Parameter from my request later. I tried using CustomHttpServletRequestWrapper but it did not work. Below is the snippet of my code.
The InboundHandler is my handler class which has the processRequest(HttpServletRequest request, HttpServletResponse response) method that is invoked from my servlet class.
public class InboundHandler {
protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
CustomHttpServletRequestWrapper requestWrapper = new CustomHttpServletRequestWrapper(request);
String body = getRequestBody(requestWrapper.getInputStream());
String from = request.getParameter("from"); //which I'm getting null here
// I also tried using
// String from = requestWrapper.getParameter("from"); // Even this did not work
} catch (Exception e) {
e.printStackTrace();
}
}
private String getRequestBody(InputStream inputStream) {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) != -1) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
} catch (IOException ex) {
ex.printStackTrace();
//throw new AuthenticationException("Error reading the request payload", ex);
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException iox) {
// ignore
}
}
}
return stringBuilder.toString();
}
public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public CustomHttpServletRequestWrapper(HttpServletRequest request) {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
ex.printStackTrace();
//log.error("Error reading the request body...");
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
ex.printStackTrace();
//log("Error closing bufferedReader...");
}
}
}
body = stringBuilder.toString();
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(body.getBytes());
ServletInputStream inputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return inputStream;
}
}
}

Q: Is there any way to read inputStream of a request without losing the data in it?
A: Yes - simply "save" what you "read"!
As Perdomoff correctly said, "Requests aren't meant to be reused". You can't put the water back in the hose once you've watered your garden :)
You can save the data. Perdomoff suggested using a session variable.
Another alternative might be to use a Servlet Filter. Here is a good tutorial:
http://www.journaldev.com/1933/java-servlet-filter-example-tutorial

Related

Read non english UTF-8 content from HTTP request

I have below code.
Content is coming in request which is non english and UTF-8 encoded. How to read it ? Currently i am doing this but looks like it is not correct.
private String readContent(HttpServletRequest request) throws IOException {
String body = null;
BufferedReader reader = null;
if (logger.isDebugEnabled()) {
logger.debug("Inside readContent() ...");
}
try {
// Read from request
StringBuilder buffer = new StringBuilder();
reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line + "\n");
}
// if (body != null) {
body = buffer.toString();
body.trim();
// }
} catch (IOException ex) {
throw ex;
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException ex) {
throw ex;
}
}
}
if (logger.isDebugEnabled()) {
logger.debug("Leaving readContent() ..." + body);
}
return body;
}
I would do something like this and use Apache Commons IOUtils. You just need to specify your encoding.
InputStream inputStream = request.getInputStream();
String contentAsString = IOUtils.toString(inputStream, "UTF-8");
You can use a try /catch block to handle with the IOException that can be thrown. Or let your method throw an Exception that will be catched/handled somewhere else.

Read a file from a FTP server but InputStream is always null

I want read files in a directory. I want add in:
List<String> nomi = new ArrayList<String>();
the linestring of file Nomi.txt.
With debug i view correctly the files in links(001.jpg 002.jpg 003.jpg) and ft(Nomi.txt), but in stream i have always null;
InputStream stream = f.retrieveFileStream(/*url_ftp + "/photo/"+ft*/ft);
my complete code is this:
private static abstract class GetLinksTask extends AsyncTask<String, Void, List<String>> {
protected List<String> doInBackground(String... urls) {
List<String> links = new ArrayList<String>();
String ft=null;
BufferedReader reader = null;
List<String> nomi = new ArrayList<String>();
FTPClient f = new FTPClient();
try {
int reply;
f.connect(url_ftp);
f.login(username,password );
reply = f.getReplyCode();
if (!FTPReply.isPositiveCompletion(reply)) {
f.disconnect();
System.err.println("FTP server refused connection.");
}
FTPListParseEngine engine = f.initiateListParsing("photo");
while (engine.hasNext()) {
FTPFile[] files = engine.getNext(25); // "page size" you want
//FTPFile[] files = engine.getFiles(filter);
for (FTPFile file : files) {
if(file.getName().substring(file.getName().length()-3,file.getName().length()).equals("jpg")){
System.out.println(file.getName());
links.add(file.getName());
}else{
ft=file.getName();
InputStream stream = f.retrieveFileStream(/*url_ftp + "/photo/"+ft*/ft);
reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
//nomi.add(reader.readLine());
}
System.out.println(file.getName());
}
//names=nomi;
}
}catch (IOException e) {
e.printStackTrace();
}finally {
if (reader != null)
try {
reader.close();
}catch (IOException logOrIgnore) {
}
}
return links;
}
protected abstract void postExecute(List<String> links);
protected void onPostExecute(List<String> lists) {
postExecute(lists);
}
}
Some tips?
thanks
It is not enough to create a Reader
reader = new BufferedReader(new InputStreamReader(stream, "UTF-8"));
and to close it:
reader.close();
Somewhere, in between, you'll actually have to read the data:
String line;
while( (line = reader.readLine()) != null ){
nomi.add( line );
}
I am explaining the full code of getting inputStream from FTP server and then how to read data from that inputstream. I am assuming, you are using TLS/SSL security layer.
public FTPSClient makeFTPConnection(String vserver, int vport, String vuser, String vpassword) {
LOGGER.debug("ENTRY");
try {
ftpClient = new FTPSClient();
} catch (NoSuchAlgorithmException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
try {
ftpClient.connect(vserver, vport);
ftpClient.login(vuser, vpassword);
ftpClient.execPBSZ(0);
ftpClient.execPROT("P");
ftpClient.changeWorkingDirectory("/");
ftpClient.changeWorkingDirectory("/feeds");
ftpClient.enterLocalPassiveMode();
ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
} catch (Exception e) {
LOGGER.error(e.getMessage());
}
/* // int reply=ftpClient.getReply();
String replyStr=ftpClient.getReplyString();
ftpClient.getAuthValue();*/
LOGGER.debug("EXIT");
return ftpClient;
}
Then after making the connection, we will check weather file exist at ftp or not.
public InputStream checkWOFileExistAtFTP(FTPSClient ftpClient, String host,String user, String filePath) throws IOException {
int returnCode;
// filePath="ftp://"+user+"#"+host+"/"+filePath;
InputStream inputStream = ftpClient.retrieveFileStream(filePath);
String dd=ftpClient.getReplyString();
returnCode = ftpClient.getReplyCode();
if (inputStream == null || returnCode == 550) {
return null;
}
return inputStream;
}
Now we already got the inputStream in above method now its time to read data from it.
BufferedReader br = new BufferedReader(new InputStreamReader(inputStream));
System.out.println("Reading file start.");
char[] charBuffer = new char[8 * 1024];
StringBuilder builder = new StringBuilder();
int numCharsRead;
while ((numCharsRead = br.read(charBuffer, 0, charBuffer.length)) != -1) {
builder.append(charBuffer, 0, numCharsRead);
}
//will print all data
system.out.println(builder.toString());

Validate empty body request of PUT, POST method in JAX-RS

I'm curious if there is an annotation/filter/interceptor capability in JAX-RS to detect if PUT or POST method contains an empty body.
Currently I have method that, if request has empty body, possibly throws NPE.
#PUT
#Produces("application/json")
#Consumes("application/json")
#Path("/update/{id}")
public Response updateCustomer(#PathParam("id") final String customerIdStr, final CustomerJson customer) {
// if request body is empty -> customer == null
return Response.ok().build();
}
I can check customer for null . But since I have plenty of such methods, it's better to have filter to do such validation.
Please!
Did you try to use Bean Validation, using an #NotNull annotation on your CustomerJson method parameter ?
Interceptors read the HTTP body and I dont find a way to send the body for further processing. But you can do this by Servlet Filter and HTTP servlet request wrapper,
public class EmptyCheckFilter implements javax.servlet.Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
if (req.getMethod().equals("POST") || req.getMethod().equals("PUT")) {
boolean dirty = false;
HttpRequestWrapper wrapper = new MyHTTPRequestWrapper(req);
try {
// check body is empty by wrapper.getBody() and set dirty = true;
} catch (Exception e) {
}
if (dirty) {
res.sendError(400, "Invalid input");
} else
chain.doFilter(wrapper, response);
} else
chain.doFilter(request, response);
}
#Override
public void destroy() {
}
#Override
public void init(FilterConfig arg0) throws ServletException {
}
}
public class MyHTTPRequestWrapper extends HttpServletRequestWrapper {
private final String body;
public MyHTTPRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
if (request.getCharacterEncoding() != null)
bufferedReader = new BufferedReader(new InputStreamReader(inputStream, request.getCharacterEncoding()));
else
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
}
#Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(
body.getBytes());
ServletInputStream servletInputStream = new ServletInputStream() {
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
return servletInputStream;
}
#Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}
public String getBody() {
return this.body;
}
}

Java- Servlet - redirecting request with a new body

I'm writing a Servlet in Java, that basically, gets a request with a XML in the Requests body, and then changes a few things in the XML and redirect/foreword the request with The new XML to a different Servlet that's on the same server, but its on a different web app.
I'm using doPost.
How do i do that? can i find code example any where?
Plus, whats the correct method to use:?
request.getRequestDispatcher().include /request.getRequestDispatcher().foreword / response.sendRedirect() or do i need to use the: HttpServletRequestWrapper?
this is what i have so far:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String body = getBody(request);
MapXml mapXml = new MapXml(body, "C:\\Projects\\XmlMapper\\output.xml","C:\\Projects\\XmlMapper\\output\\");
String outputXml = mapXml.getOutputXml();
}
public static String getBody(HttpServletRequest request) throws IOException {
String body = null;
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
return body;
}
And i have no idea how to continue on from here. I'm new to the servlet world..
Thanks!!!
Cheers:)

Parsing Binary Data from HttpServletRequest

What is the general approach to retrieve binary data that is posted to a Java Servlet? A byte[] is being posted to this servlet and I think I have to somehow parse the HttpServletRequest.getInputStream() and pull out the byte[] contents. Any ideas on how to change the below code to accomplish this?
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(
inputStream));
char[] charBuffer = new char[128];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
String body = stringBuilder.toString();
System.out.println(body);
}
Don't wrap your inputstream in any "Reader"s, as they convert from bytes to characters, and you want the bytes.
yes. ditch all the Readers and use the InputStream you were handed on the 3rd line. if you don't understand the relationship between byte[] and InputStream, i would suggest reading the API docs and some good java tutorials.

Categories