How to access HTTP request's body with RESTEasy - java

I'm looking for a way to directly access the body of the HTTP request. In fact, in my code I receive different parameters in the body and I don't know in advance exactly what I will receive. Moreover I want to be as flexible as possible: I'm dealing with different requests that can vary and I want to handle them in a single method for each type of request (GET, POST, ... ).
Is there a way to handle this level of flexibility with RESTEasy? Should I switch to something else?

As per the code given in this answer you can access the HTTPServletRequest Object.
Once you have HTTPServletRequest object you should be able access the request body as usual. One example can be:
String requestBody = "";
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;
}
}
}
requestBody = stringBuilder.toString();

Related

Retrieve HTTP Body in NanoHTTPD

How can I retrieve the HTTP POST request body when implementing NanoHTTPDs serve method?
I've tried to use the getInputStream() method of IHTTPSession already, but I always get an SocketTimeoutException when using it inside of the serve method.
In the serve method you first have to call session.parseBody(files), where files is a Map<String, String>, and then session.getQueryParameterString() will return the POST request's body.
I found an example in the source code. Here is the relevant code:
public Response serve(IHTTPSession session) {
Map<String, String> files = new HashMap<String, String>();
Method method = session.getMethod();
if (Method.PUT.equals(method) || Method.POST.equals(method)) {
try {
session.parseBody(files);
} catch (IOException ioe) {
return new Response(Response.Status.INTERNAL_ERROR, MIME_PLAINTEXT, "SERVER INTERNAL ERROR: IOException: " + ioe.getMessage());
} catch (ResponseException re) {
return new Response(re.getStatus(), MIME_PLAINTEXT, re.getMessage());
}
}
// get the POST body
String postBody = session.getQueryParameterString();
// or you can access the POST request's parameters
String postParameter = session.getParms().get("parameter");
return new Response(postBody); // Or postParameter.
}
On a IHTTPSession instance you can call the .parseBody(Map<String, String>) method which will then fill the map you provided with some values.
Afterwards your map may contain a value under the key postBody.
final HashMap<String, String> map = new HashMap<String, String>();
session.parseBody(map);
final String json = map.get("postData");
This value will then hold your posts body.
Code that does this, can be found here.
I think session.getQueryParameterString(); not work in this case.
If you using POST, PUT, you should want to try this code:
Integer contentLength = Integer.parseInt(session.getHeaders().get("content-length"));
byte[] buffer = new byte[contentLength];
session.getInputStream().read(buffer, 0, contentLength);
Log.d("RequestBody: " + new String(buffer));
In fact, I tried IOUtils.toString(inputstream, encoding) but it cause Timeout exception!
This is how I am getting my post response body with NanoHttp, and it works for me. Very important to note that if you are handling your own error response codes and want to send a body use the error input stream instead of the conn.getInputStream() This will avoid the file not found exception or broken pipe exception if close the connection before the server sent the body.
public HashMap<String, Object> getResponse(HttpURLConnection conn) throws IOException {
Log.i("STATUS", String.valueOf(conn.getResponseCode()));
Log.i("MSG", conn.getResponseMessage());
StringBuilder response = new StringBuilder();
String line;
BufferedReader br;
if (conn.getResponseCode() == HttpsURLConnection.HTTP_OK)
br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
else
br = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
while ((line = br.readLine()) != null)
response.append(line);
conn.disconnect();
return new Gson().fromJson(response.toString(), HashMap.class);

How to get VIEWSTATE before posting using HttpURLConnection (android/java)?

I am writing an Android application, and have been looking for a way to get the _VIEWSTATE from the server I want to post to so I can put it in my Http post content. A few people recommended regex, but then some other pros were strongly opposed to parsing HTML with regex. So, how to parse the _VIEWSTATE ? I am using HttpURLConnection/HttpsURLConnection in an AsyncTask. Also, don't I need to put the InputStream reader first, to get the _VIEWSTATE first? All the android examples put the input stream after the output stream. Here is what my code looks like so far (posting to one site that has three pages that have to be "clicked through"):
In my Activity, I call the Async task like this:
//execute AsyncTask for all three reports
submit_report.execute(report1, report2, report3);
My Async task doInBackground method:
class UploadReportTask extends AsyncTask<HashMap<String,String>, ProgressBar, Void> {
//this is called on task.execute
protected Void doInBackground(HashMap<String,String>...maps) {
System.out.println("Report is being uploaded");
URL url = null;
try {
url = new URL(getString(R.string.url_dnc));
} catch (MalformedURLException e) {
e.printStackTrace();
}
HttpURLConnection urlConnection = null;
try {
urlConnection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
try {
urlConnection.setDoOutput(true);
urlConnection.setRequestProperty("Accept-Charset", utf);
urlConnection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + utf);
urlConnection.setChunkedStreamingMode(0);
//For each map in maps, encode the map,
//get the headers, add the headers to the map, convert to bytes,
//then post the bytes,
//get response.
for (HashMap<String,String> map : maps){
byte[] payload = makePayload(map);
OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream());
//urlConn.connect //I think this happens here
out.write(payload);
InputStream in = new BufferedInputStream(urlConnection.getInputStream());
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
int length = in.read();
String result, line = reader.readLine();
result = line;
while (length != -1){
result+=line;
}
System.out.println(result);
out.flush();
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
finally{
urlConnection.disconnect();
}
return null;
}
protected String parseViewstate(String response){
int i = 0;
String viewstate = "";
while (true){
int found = response.indexOf("\"__VIEWSTATE\"", i);
if (found == -1) break;
int start = found + 38; //check numbers from start of "__V"
int end = (response.indexOf("/>", start)) -2;
viewstate = response.substring(start, end);
i = end + 1;
}return viewstate;
}

Grabbing JSON works from one link, not from another

I'm doing a simple JSON grab from two links with the same code. I'm doing it two separate times, so the cause of my issue isn't because they're running into each other or something.
Here is my code:
#Override
protected String doInBackground(Object... params) {
try {
URL weatherUrl = new URL("my url goes here");
HttpURLConnection connection = (HttpURLConnection) weatherUrl
.openConnection();
connection.connect();
responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
InputStream inputStream = connection.getInputStream();
Reader reader = new InputStreamReader(inputStream);
int contentLength = connection.getContentLength();
char[] charArray = new char[contentLength];
reader.read(charArray);
String responseData = new String(charArray);
Log.v("test", responseData);
When I try this with:
http://www.google.com/calendar/feeds/developer-calendar#google.com/public/full?alt=json
I get an error of having an array lenth of -1
For this link:
http://api.openweathermap.org/data/2.5/weather?id=5815135
It returns fine and I get a log of all of the JSON. Does anyone have any idea why?
Note: I tried stepping through my code in debug mode, but I couldn't catch anything. I also downloaded a Google chrome extension for parsing json in the browser and both urls look completely valid. I'm out of ideas.
Log this: int contentLength = connection.getContentLength();
I don't see the google url returning a content-length header.
If you just want String output from a url, you can use Scanner and URL like so:
Scanner s = new Scanner(new URL("http://www.google.com").openStream(), "UTF-8").useDelimiter("\\A");
out = s.next();
s.close();
(don't forget try/finally block and exception handling)
The longer way (which allows for progress reporting and such):
String convertStreamToString(InputStream is) throws UnsupportedEncodingException {
BufferedReader reader = new BufferedReader(new
InputStreamReader(is, "UTF-8"));
StringBuilder sb = new StringBuilder();
String line = null;
try {
while ((line = reader.readLine()) != null)
sb.append(line + "\n");
} catch (IOException e) {
// Handle exception
} finally {
try {
is.close();
} catch (IOException e) {
// Handle exception
}
}
return sb.toString();
}
}
and then call String response = convertStreamToString( inputStream );

Getting request payload from POST request in Java servlet

I have a javascript library that is sending a POST request to my Java servlet, but in the doPost method, I can't seem to get the contents of the request payload. In chrome Developer Tools, all the content is in the Request Payload section in the headers tab, and the content is there, and I know that the POST is being received by the doPost method, but it just comes up blank.
For the HttpServletRequest
object, what way can I get the data in the request payload?
Doing request.getParameter() or request.getAttributes()
both end up with no data
Simple answer:
Use getReader() to read the body of the request
More info:
There are two methods for reading the data in the body:
getReader() returns a BufferedReader that will allow you to read the body of the request.
getInputStream() returns a ServletInputStream if you need to read binary data.
Note from the docs: "[Either method] may be called to read the body, not both."
String payloadRequest = getBody(request);
Using this method
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;
}
You can use Buffer Reader from request to read
// Read from request
StringBuilder buffer = new StringBuilder();
BufferedReader reader = request.getReader();
String line;
while ((line = reader.readLine()) != null) {
buffer.append(line);
buffer.append(System.lineSeparator());
}
String data = buffer.toString()
Java 8 streams
String body = request.getReader().lines()
.reduce("", (accumulator, actual) -> accumulator + actual);
With Apache Commons IO you can do this in one line.
IOUtils.toString(request.getReader())
If the contents of the body are a string in Java 8 you can do:
String body = request.getReader().lines().collect(Collectors.joining());
If you are able to send the payload in JSON, this is a most convenient way to read the playload:
Example data class:
public class Person {
String firstName;
String lastName;
// Getters and setters ...
}
Example payload (request body):
{ "firstName" : "John", "lastName" : "Doe" }
Code to read payload in servlet (requires com.google.gson.*):
Person person = new Gson().fromJson(request.getReader(), Person.class);
That's all. Nice, easy and clean. Don't forget to set the content-type header to application/json.
Using Java 8 try with resources:
StringBuilder stringBuilder = new StringBuilder();
try(BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(request.getInputStream()))) {
char[] charBuffer = new char[1024];
int bytesRead;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
}
You only need
request.getParameterMap()
for getting the POST and GET - Parameters.
The Method returns a Map<String,String[]>.
You can read the parameters in the Map by
Map<String, String[]> map = request.getParameterMap();
//Reading the Map
//Works for GET && POST Method
for(String paramName:map.keySet()) {
String[] paramValues = map.get(paramName);
//Get Values of Param Name
for(String valueOfParam:paramValues) {
//Output the Values
System.out.println("Value of Param with Name "+paramName+": "+valueOfParam);
}
}

How to get the URL connection result in a string?

I'm working on Yahoo boss API. The URL supposed to return JSON, I need to store it in a string then parse it. http://developer.yahoo.com/java/howto-parseRestJava.html
My question: How can I save URL response in a string ??
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpPostRequest);//send a request and receive a response
System.out.println("HTTPResponse received in [" + (System.currentTimeMillis()-t) + "ms]");
HttpEntity entity = response.getEntity();
if (entity != null) {
// Read the content stream
InputStream instream = entity.getContent();
// convert content stream to a String
String resultString= convertStreamToString(instream);
instream.close();
resultString = resultString.substring(1,resultString.length()-1); // remove wrapping "[" and "]"
and here is the function convertStreamToString
private static String convertStreamToString(InputStream is) {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
StringBuilder sb = new StringBuilder();
try {
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
Technically, you want to wrap an appropriately configured InputStreamReader around the URL InputStream and copy the Reader to a StringWriter (apache commons IO has a "copy Reader to String" utility method). However, in order to determine the correct character set for the InputStreamReader, you need to parse the ContentType header. In which case you might be better off working with a higher level library like apache commons HttpClient.
Or, you could wrap a JSONTokener around the URL InputStream and parse the JSONObject directly from the JSONTokener (although i'm not entirely sure how the tokener determines the correct character set, so you might be safer using something like HttpClient).

Categories