I am using the OkHttp client and when I wrote the code to consume an API, I am getting a SonarLint warning about response.body().string() could be null.
However there is a chicken and egg problem with response in that it can only be consumed once, then it is de-referenced.
Which means I have had to structure my code like so:
Check the response object is not null
Then check the response body text is not null/empty
Which results in two separate but similar if statement/catches
try (var response = okHttpClient.newCall(siteMagicLinkRequest).execute()) {
if (response.body() == null) {
throw new ApiException("Unable to generate Magic Link: Null Response Body from site");
}
var responseString = response.body().string();
if (response.body() == null || StringUtils.isEmpty(responseString)) {
throw new ApiException("Unable to generate Magic Link: Empty Response Body From site");
}
if (response.isSuccessful()) {
return responseString;
} else {
final siteApiErrorResponse errorResponse = gson.fromJson(responseString, siteApiErrorResponse.class);
throw new ApiException(response.code(), errorResponse.getMessage());
}
} catch (IOException e) {
throw new AuthorizationException("Unable to generate Magic Link: " + e.getMessage());
}
I can't use a condensed if check as shown below, as it will lose the response body.
if (response.body() == null || StringUtils.isEmpty(responseString)) {
throw new ApiException("Unable to generate Magic Link: Empty Response Body From site");
}
Is there any OkHttp API or another pattern I can use to simplify this code and remove the extra if statement/trap?
You can write
if (response.body() == null || StringUtils.isEmpty(response.body().string())) {
throw new ApiException("Unable to generate Magic Link: Empty Response Body From site");
}
If the response.body() == null check before the or-operator is true, the check after the or-operator will not be executed. Instead, it will execute the code inside the if-statement right away. The second check will only be executed if the first check returns false.
That's why you will never get a NullPointerException with this if-statement. And this is what I think you are concerned about, right?
Related
I am using the below code for sanitizing the JSON but still, I am getting the JSON injection while scanning from Fortify can you please help me out what is the problem or this is not an issue, maybe suppress. I have also looked out for the same question but those don't solve my problem . my problem is that I am sanitizing my JSON before converting it to java object but still I am getting JSON injection error in fortify
public String handleEventMessage(String jsonRequest) {
MonerisPaymentDetailsObject paymentObject = null;
if(null!=jsonRequest && jsonRequest.length()>0){
try{
paymentObject = mapper.readValue(JsonSanitizer.sanitize(jsonRequest), MonerisPaymentDetailsObject.class);
}catch(Exception ex){
logger.error("Error occured while converting MonerisPaymentDetailsObject json to Object :" , ex);
}
return "abc";
}
Fortify giving below description for this error
1. Data enters a program from an untrusted source.
In this case the data enters at readLine() in EPWFPaymentServicesServlet.java at line 49.
2. The data is written to a JSON stream.
In this case the JSON is written by readValue() in EPWFMonerisPaymentsServiceHandler.java at line 46.
EPWFPaymentServicesServlet.java code where data is entered
#Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
CodeTimer timer = new CodeTimer("EPWFPaymentServicesServlet.doPost()", true);
response.setContentType("text/xml");
BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream()));
StringBuffer requestBuffer = new StringBuffer(request.getContentLength());
String line = null;
while ((line = reader.readLine()) != null) {
requestBuffer.append(line).append('\n');
}
// read the POST request contents
String requestString = requestBuffer.toString();
if (logger.isDebugEnabled()) {
logger.debug("EPWF Payment Service POST Request: \n" + ((requestString == null) ? "Null" : requestString.substring(0, 9)));
}
PaymentServiceHandlerComposit paySvcHandler = new PaymentServiceHandlerComposit();
String responseString =paySvcHandler.handleEventMessage(requestString);//line no 49 where fortify is giving description for class where i am sanitizing the data
if (logger.isDebugEnabled()) {
logger.debug("EPWF Payment Service POST Response: \n" + ((responseString == null) ? "Null" : requestString));
}
response.getOutputStream().print(responseString);
timer.stopAndLogTiming("");
}
Given that you are using a new up-to-date version of jackson, there should be no need to pre-sanitise or alter your data at all before handing it off to jackson.
Jackson will only accept and parse valid JSON, as new exploits and vulnerabilities are discovered, the maintainers of Jackson fix and release new versions. and the best you can do is to keep up to date with these versions.
If the above conditions are met, you can safely suppress this error from fortify, the chance that there is a bug in your custom sanitizer is way higher than the chance of there being one in Jackson
I am using Rest Assured Framework for API testing(Using Java).
At line (1),I am expecting error as there is mismatch in expected JSON response and Actual JSON response
But instead my code is executing successfully.
Can someone please tell me if I am doing anything wrong in below code?
public void test123() {
try {
//Read the Curl Request Input file
String json = input.readFromTextFile(
System.getProperty("user.dir") + "\\src\\test\\resources\\inputFile\\CurlDataFile.txt");
json = json.replaceAll(" ", "");
RestAssured.baseURI = "My URL";
given().
contentType("application/json").
body(json).
when().
post("").
then().
assertThat().body(matchesJsonSchemaInClasspath("testCurlOuput1.json")); (1)
} catch (IOException e) {
e.printStackTrace();
}catch(JsonSchemaValidationException e){
e.printStackTrace();
}
}
This is not directly relevant to REST-assured, but I suggest you take a look at Karate, because IMO it may be exactly what you are looking for.
One of the core features of Karate is that you can perform a full equality match of a JSON payload in one step.
And you can easily use JSON from files, which encourages the re-use of payloads across multiple tests.
You are catching all Exceptions. When your assertThat(..) fails, it throws an Exception. Put a breakpoint on the e.printStackTrace(); run in DEBUG mode and check that your AssertionException/Error isn't being caught.
Instead of catching exceptions, just add all Checked Exceptions to your test signature. If an exception is uncaught, it will fail the test. Alternatively, but less prefered in my opinion, resolve by putting fail(); in the catch block.
Finally I choose different library i.e. jayway.restassured library and then JSON Assert library (org.skyscreamer.jsonassert.JSONAssert) which will comapre actual and expected response.
public void test123() {
String postData = input.readFromTextFile(System.getProperty("user.dir") + "\\src\\test\\resources\\inputFile\\CurlDataFile.txt");
RestAssured.baseURI = "MY URL";
Response r = (Response)given().contentType("application/json").body(postData).when().post("");
String responseBody = r.getBody().asString();
String curlResponse = //I am providing expected Curl response here
//JSON Assertion for matching Expected and Actual response
JSONAssert.assertEquals(curlResponse, responseBody, false);
}
Also sometime we may want to avoid comparing particular field from JSON like some ID field which generate dynamically which we can do using JSON comparator
I am a fan of JSONAssert as this provides easy comparing of complete JSONs.
Just use .extract().response().getBody().asString() to get the string representation of the answer.
Complete example:
#Test
public void getReturnsExpectedDataForMailExampleCom() throws JSONException {
String response = get("/users/mail#example.com")
.then()
.statusCode(200)
.extract().response().getBody().asString();
JSONAssert.assertEquals(
"{\"email\":\"mail#example.com\",\"locale\":\"de-DE\"}",
response,
false);
}
Update The drawback is that the complete JSON is not output to stdout if the assertion fails.
I have a method which uses proxies to retrieve information from a server. Sometimes due to a bad proxy I get SocketException, SSLException, SSLHandshakeException or ConnectException
I want the method to retry on the exceptions above, but on the IOException or no exception I want a string returned
Here is the method I constructed to test different scenarios
public String getTest(int i, int current, int total)
{
String text = "";
try
{
if (i == 1)
throw new IOException();
else if (i == 2)
throw new SSLException("SSLEx");
else if (i == 3)
throw new SocketException();
else
text = "EVERYTHING GOOD";
}
catch (SSLException | SocketException re)
{
if (current < total)
{
System.out.println("Recalling " + current);
getTest(1, ++current, total);
}
}
catch (IOException ioe)
{
text = "HTTP ERROR";
}
catch (Exception e)
{
e.printStackTrace();
}
return text;
}
I call my test method by
System.out.println(c.getTest(3, 0, 5));
Initially the program would catch a SocketException then retry by passing 1 so I can emulate a working proxy but a server response with IOException as i = 1 but the method never returns the text "HTTP ERROR"
What do I need to change in order for this to work as expected?
In order to return the string returned by your recursive function call, you must place return before the recursive function call like so...
return getTest(1, ++current, total);
Right now you are simply running the recursive function and discarding its return value. Your logic then returns your text string from the initial call (which in the case of an SSLException looks like an empty string).
You could also accomplish the same effect by assigning text from the recursive function...
text = getTest(1, ++current, total);
Both statements, considering the rest of your logic, are equivalent.
Am develop code for upload images. but that not work properly. in my servlet i will check contenttype if contexttype match to "image/jpeg" or "image/jpeg" the file will write other wise show an error message
Part filePart = request.getPart("pho`to");
String str = filePart.getContentType();
if (str != "image/jpeg" && str != "image/jpg") {
response.sendRedirect("uploadimage?action=errorinfiletype");
return;
}
User.updateImage(inputStream, uid);
response.sendRedirect("uploadimage?action=changed");
but the above code always shows the error message.
i think error in my if condition. anybody please help
You can do the following:
if (str==null || !str.matches("image/jp(e)?g") ) {
response.sendRedirect("uploadimage?action=errorinfiletype");
return;
}
In Java, you cannot compare strings using the == or != operator. You have to use the equals() method, i.e.
if (!"image/jpeg".equals(str) && !"image/jpg".equals(str)) {
...
}
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:");
This throws a null pointer error if the user x's out of the optionpane
Firstly, why can't response hold a null value?
secondly, how do i handle this?
full code:
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:").trim() + ".xml";
if(response != null){
File newData = new File("src\\golfdatabase\\Databases\\" + response);
try {
newData.createNewFile();
databaseComboBox.addItem(response);
} catch (IOException ex) {
Logger.getLogger(GolfDriver.class.getName()).log(Level.SEVERE, null, ex);
}
databaseComboBox.setSelectedItem(response);
disableButtonsNullList(false);
}
You have to check the return value for null and then invoke the method trim
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:");
if(response!=null)
response = response.trim()+".xml";
It gives null back when you click on "Cancel" try something like that:
String response = javax.swing.JOptionPane.showInputDialog("Enter new database name:");
if(response != null){
response = response.trim() + ".xml";
}
Take note that: String response = JOptionPane.showInputDialog(....);
Would have been enough to create the JOptionPane.
Firstly: Yes responses CAN hold a null value, but your code snippet does not show how you handle the responses so there is no way for me to tell why it is throwing them.
Secondly: That again depends on how you are handling the responses, please elaborate more on your code.
EDIT: try adding a String cast as the java tutorial suggests you do:
http://docs.oracle.com/javase/tutorial/uiswing/components/dialog.html
EDIT2: While Octopus found the problem in a piece of code (that I shamefully overlooked) please keep in mind the above points because they still hold true.