How to get Body Response when POST Multipart Request with Volley? - android-volley

I'm working with post multipart request from android. And I follow this solution to upload image and succeed perfectly but the query is when I hit my API to upload image to server it returns OK response with a string just like that
I need this body response that is mentioned above. My volley code response only header data. My code is
VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url,
new Response.Listener<NetworkResponse>() {
#Override
public void onResponse(NetworkResponse response) {
Log.wtf("result: ", String.valueOf(response));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
...
}
}) {
#Override
protected Map<String, DataPart> getByteData() {
Map<String, DataPart> params = new HashMap<>();
...
return params;
}
};
Thanks

Related

Spring WebFlux, Security and request body

I need to secure REST API implemented with Spring Boot, WebFlux and spring security using HMAC of the request body. Simplifying a bit, on a high level - request comes with the header that has hashed value of the request body, so I have to read the header, read the body, calculate hash of the body and compare with the header value.
I think I should implement ServerAuthenticationConverter but all examples I was able to find so far only looking at the request headers, not the body and I'm not sure if I could just read the body, or should I wrap/mutate the request with cached body so it could be consumed by the underlying component second time?
Is it ok to use something along the lines of:
public class HttpHmacAuthenticationConverter implements ServerAuthenticationConverter {
#Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
exchange.getRequest().getBody()
.next()
.flatMap(dataBuffer -> {
try {
return Mono.just(StreamUtils.copyToString(dataBuffer.asInputStream(), StandardCharsets.UTF_8));
} catch (IOException e) {
return Mono.error(e);
}
})
...
I'm getting a warning from the IDE on the copyToString line: Inappropriate blocking method call
Any guidelines or examples?
Thanks!
I have also tried:
#Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
return Mono.justOrEmpty(exchange.getRequest().getHeaders().toSingleValueMap())
.zipWith(exchange.getRequest().getBody().next()
.flatMap(dataBuffer -> Mono.just(dataBuffer.asByteBuffer().array()))
)
.flatMap(tuple -> create(tuple.getT1(), tuple.getT2()));
But that doesn't work - code in the create() method on the last line is never executed.
I make it work. Posting my code for the reference.
Two components are required to make it work - WebFilter that would read and cache request body so it could be consumed multiple times and the ServerAuthenticationConverter that would calculate hash on a body and validate signature.
public class HttpRequestBodyCachingFilter implements WebFilter {
private static final byte[] EMPTY_BODY = new byte[0];
#Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// GET and DELETE don't have a body
HttpMethod method = exchange.getRequest().getMethod();
if (method == null || method.matches(HttpMethod.GET.name()) || method.matches(HttpMethod.DELETE.name())) {
return chain.filter(exchange);
}
return DataBufferUtils.join(exchange.getRequest().getBody())
.map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return bytes;
})
.defaultIfEmpty(EMPTY_BODY)
.flatMap(bytes -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
#Nonnull
#Override
public Flux<DataBuffer> getBody() {
if (bytes.length > 0) {
DataBufferFactory dataBufferFactory = exchange.getResponse().bufferFactory();
return Flux.just(dataBufferFactory.wrap(bytes));
}
return Flux.empty();
}
};
return chain.filter(exchange.mutate().request(decorator).build());
});
}
}
public class HttpJwsAuthenticationConverter implements ServerAuthenticationConverter {
private static final byte[] EMPTY_BODY = new byte[0];
#Override
public Mono<Authentication> convert(ServerWebExchange exchange) {
return DataBufferUtils.join(exchange.getRequest().getBody())
.map(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
return bytes;
})
.defaultIfEmpty(EMPTY_BODY)
.flatMap(body -> create(
exchange.getRequest().getMethod(),
getFullRequestPath(exchange.getRequest()),
exchange.getRequest().getHeaders(),
body)
);
}
...
The create method in the Converter implements the logic to validate signature based on the request method, path, headers and the body. It returns an instance of the Authentication if successful or Mono.empty() if not.
The wiring up is done like this:
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
http.authorizeExchange().pathMatchers(PATH_API).authenticated()
...
.and()
.addFilterBefore(new HttpRequestBodyCachingFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
.addFilterAt(jwtAuthenticationFilter(...), SecurityWebFiltersOrder.AUTHENTICATION);
}
private AuthenticationWebFilter jwtAuthenticationFilter(ReactiveAuthenticationManager authManager) {
AuthenticationWebFilter authFilter = new AuthenticationWebFilter(authManager);
authFilter.setServerAuthenticationConverter(new HttpJwsAuthenticationConverter());
authFilter.setRequiresAuthenticationMatcher(ServerWebExchangeMatchers.pathMatchers(PATH_API));
return authFilter;
}
#Bean
public ReactiveAuthenticationManager reactiveAuthenticationManager() {
return Mono::just;
}
}

How do I resolve an "Unknown Host Exception" when using Volley to interact with BigCommerce's Orders API endpoint?

As far as I know, I am implementing Volley correctly, and I know for a fact that the API endpoint URL along with all the HTTP headers are 100% correct. Yet, when I try to GET the JSON from the endpoint, an Unknown Host Exception is thrown.
I used the BigCommerce Orders API reference and made multiple test queries, and it worked there, but there appears to be some kind of disconnect when ran on the emulator on Android studio. Is it possible that my business' WiFi and/or the emulator itself is causing this problem?
RequestQueue requestQueue = Volley.newRequestQueue(this);
requestQueue.start();
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(com.android.volley.Request.Method.GET,
URL, null, new com.android.volley.Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
parseOrders(response);
}
}, new com.android.volley.Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.d("Volley", error.getMessage());
Toast.makeText(MainActivity.this, error.getMessage(), Toast.LENGTH_SHORT).show();
}
})
{
#Override
public Map<String, String> getHeaders() {
Map<String, String> params = new HashMap<>();
params.put("accept", "application/json");
params.put("content-type", "application/json");
params.put("x-auth-token", "myToken");
params.put("x-auth-client", "myClientID");
return params;
}
#Override
public String getBodyContentType() {
return "application/json";
}
};
requestQueue.add(jsonObjectRequest);

How to identify response contenttype in Zuul filter?

I have created one filter in zuul service.
I am able to get the response status but I am not able to get the response contenttype.
Code:
public class UserEventFilter extends ZuulFilter {
#Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
HttpServletResponse response = ctx.getResponse();
System.out.println("response status:" + response.getStatus());
System.out.println("response status:" + ctx.getResponseStatusCode());
System.out.println("response content type:" + response.getContentType());
try (final InputStream responseDataStream = ctx.getResponseDataStream()) {
final String responseData = CharStreams
.toString(new InputStreamReader(responseDataStream, Constants.ENCODING_UTF_8));
ctx.setResponseBody(responseData);
System.out.println("responseData:"+responseData);
} catch (IOException exception) {
exception.printStackTrace();
}
}
}
response content type is giving null.
What I want to do is, I have to get the response body for all responses except if it is "application/octet-stream".
Try this:
RequestContext context = RequestContext.getCurrentContext();
List<Pair<String, String>> headers = context.getZuulResponseHeaders();
Than find content type there. You should override filterType method:
#Override
public String filterType() {
return POST_TYPE;
}
that is POST filter, if you want response I guess you are using post filter.

How to customize Spring boot controller API response for ZuulException

We are using Zuul, Eureka and spring boot application services for REST APIs.
Suppose my spring boot service is down and when I tried to access the API using Zuul API gateway, I am getting ZuulException and response is below :
{
"timestamp": "2018-10-12T14:29:09.632+0000",
"status": 500,
"error": "Internal Server Error",
"exception": "com.netflix.zuul.exception.ZuulException",
"message": "GENERAL"
}
I want to customize the response format like below:
{
"success": false,
"message": "Service is down. Please try later"
}
I tried to implement https://stackoverflow.com/a/39841785/5506061 but its not working for me.
Please suggest how to customize the response for ZuulException.
You can implement your own FallbackProvider and customize the response based on the cause if needed.
Something like :
#Component
public class CustomFallbackBasedOnCause implements FallbackProvider {
private static final String DEFAULT_MSG = "{\"success\": false,\"message\": \"Service is down. Please try later\"}";
#Override
public String getRoute() {
return "*"; // * = all routes
}
#Override
public ClientHttpResponse fallbackResponse(final Throwable cause) {
if (cause instanceof HystrixTimeoutException) {
return response(HttpStatus.GATEWAY_TIMEOUT);
} else {
return fallbackResponse();
}
}
#Override
public ClientHttpResponse fallbackResponse() {
return response(HttpStatus.INTERNAL_SERVER_ERROR);
}
private ClientHttpResponse response(final HttpStatus status) {
return new ClientHttpResponse() {
#Override
public HttpStatus getStatusCode() throws IOException {
return status;
}
#Override
public int getRawStatusCode() throws IOException {
return status.value();
}
#Override
public String getStatusText() throws IOException {
return status.getReasonPhrase();
}
#Override
public void close() {
}
#Override
public InputStream getBody() throws IOException {
return new ByteArrayInputStream(DEFAULT_MSG.getBytes());
}
#Override
public HttpHeaders getHeaders() {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return headers;
}
};
}
}
As you can see in the getRoute() method, you can specify if this customFallback will be used for all routes (return "*") or for a specific route.
In case you work with Registry service (e.g Eureka). You don’t specify the route URL but the service id instead. return "SERVICEID"

How to get string response from php using android volley JsonObjectRequest?

ctually when we call API and send request in JSON format we are expecting response also come into JSON format. But here back end team sending me response in String format therefore my onErrorResponse () method get called. Here my status code is 200. But due to format of response not executed onResponse () method. So will you please help me to handle this? Might be I have to use CustomRequest here. Any suggestoin will be appreciated. Thanks
public class SampleJsonObjTask {
public static ProgressDialog progress;
private static RequestQueue queue;
JSONObject main;
JsonObjectRequest req;
private MainActivity context;
private String prd,us,ver,fha,ve,ves,sz,cat,pa,h,t,en,pha,pur,dip;
public SampleJsonObjTask(MainActivity context, JSONObject main) {
progress = new ProgressDialog(context);
progress.setMessage("Loading...");
progress.setCanceledOnTouchOutside(false);
progress.setCancelable(false);
progress.show();
this.context = context;
this.main = main;
ResponseTask();
}
private void ResponseTask() {
if (queue == null) {
queue = Volley.newRequestQueue(context);
}
req = new JsonObjectRequest(Request.Method.POST, "", main,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
progress.dismiss();
Log.e("response","response--->"+response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
progress.dismiss();//error.getMessage()
/*back end team sending me response in String format therefore my onErrorResponse () method get called. Here my status code is 200.*/
}
})
{
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<String, String>();
params.put("Content-Type", "application/json");
return params;
}
};
req.setRetryPolicy(new DefaultRetryPolicy(20 * 1000, 0, 1f));
queue.add(req);
}
}
Here the Response coming like string format that is Value OK,
com.android.volley.ParseError: org.json.JSONException: Value OK of type java.lang.String cannot be converted to JSONObject
You can use StringRequest for that:
StringRequest request = new StringRequest(StringRequest.Method.POST, url, new Response.Listener<String>() {
#Override
public void onResponse(String response) { }
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}) {
#Override
public String getBodyContentType() {
return "application/json; charset=utf-8";
}
#Override
public byte[] getBody() {
try {
JSONObject jsonObject = new JSONObject();
/* fill your json here */
return jsonObject.toString().getBytes("utf-8");
} catch (Exception e) { }
return null;
}
};

Resources