I am trying to upload an image file to a web storage server using zero copy post.
The implementation comes from the example in the Apache website. I've changed some parts from the example so that the response is not downloaded in a file.
Here's the source code that I have changed.
private void upload() throws Exception {
CloseableHttpAsyncClient httpclient = HttpAsyncClients.createDefault();
try {
httpclient.start();
File upload = new File("C:\\Users\\Jee\\profile.png");
ZeroCopyPost httpost = new ZeroCopyPost(requestURL+upload.getName(), upload,
ContentType.create("image/png"));
HttpAsyncResponseConsumer consumer = new BasicAsyncResponseConsumer();
Future<File> future = httpclient.execute(httpost, consumer, null);
File result = future.get();
System.out.println("Response file length: " + result.length());
System.out.println("Shutting down");
} finally {
httpclient.close();
}
System.out.println("Done");
}
I need to add headers to this POST request. How is it done?
ZeroCopyPost zeroCopyPost = new ZeroCopyPost(
URI.create("/"),
new File("stuff"),
ContentType.DEFAULT_BINARY) {
#Override
protected HttpEntityEnclosingRequest createRequest(
final URI requestURI, final HttpEntity entity) {
HttpEntityEnclosingRequest request = super.createRequest(requestURI, entity);
request.setHeader("my-header", "whatever");
return request;
}
};
Overriding ZeroCopyPost#createRequest is the recommended way. Overriding #generateRequest per #Robert Rowntree recommendation would work as well.
Related
I am using Zuul post filter to intercept the response. My requirement is to add one new field to response json. I'm able to intercept the response and edit it. But, unable to set the updated response to RequestContext.How it is possible to read a response body ,edit and update it back to RequestContext while using Zuul as a proxy in post filter?
Please find the below code i am using.
private void updateResponseBody(RequestContext ctx) throws IOException, JSONException {
final InputStream responseDataStream = ctx.getResponseDataStream();
String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
JSONObject jsonObj = new JSONObject(responseData);
JSONArray groupsArray = jsonObj.getJSONArray("list");
for (int i = 0; i < groupsArray.length(); i++) {
JSONObject groupId = groupsArray.getJSONObject(i);
groupId.accumulate("new_json_field_name", "new_json_field_value");
}
String updatedResponse = jsonObj.toString();
// ctx.setResponseBody(body); // also not working
ctx.setResponseDataStream(org.apache.commons.io.IOUtils.toInputStream(updatedResponse, "UTF-8"));
}
Error I am getting is :
Error while sending response to client: java.io.IOException: An existing connection was forcibly closed by the remote host.
Can anyone please help me on this.
I had the same error and got crazy modifying the code described in How to get response body in Zuul post filter? trying different possibilities. Finally I found the solution in this post by writing the answer in the OutputStream from servletResponse.getOutputStream() instead of ctx.setResponseDataStream():
HttpServletResponse servletResponse = ctx.getResponse();
...
String updatedResponse = jsonObj.toString();
try {
OutputStream outStream = servletResponse.getOutputStream();
outStream.write(updatedResponse.getBytes(), 0, updatedResponse.length());
outStream.flush();
outStream.close();
} catch (IOException e) {
log.warn("Error reading body", e);
}
I had a similar task and tried to do it by writing to the OutputStream. This worked, but had a strange side effect that it made the HttpHeaders in the response to be deleted or corrupted. This made the call produce CORS errors in production even though it ran fine locally through Postman.
I wrote the following method that I call from the run() method of my Post Zuul Filter to add a single node/value to the return Json.
private void addJsonNode(RequestContext requestContext,String name, String id) {
HttpServletResponse servletResponse = requestContext.getResponse();
try {
final InputStream responseDataStream = requestContext.getResponseDataStream();
String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
JSONObject jsonObject = new JSONObject(responseData);
jsonObject.put(name, id);
String updatedResponse = jsonObject.toString(4);
requestContext.setResponseBody(updatedResponse);
} catch (IOException e) {
log.warn("Error reading body", e);
} catch (JSONException e) {
log.warn("Error reading body", e);
}
}
I am writing Java code where i am downloading the file from a server and i have to copy the file in my local system when the file download is complete.
I am using the below code:-
OkHttpClient.Builder builder = new OkHttpClient.Builder();
OkHttpClient client = builder.readTimeout(600, TimeUnit.SECONDS).writeTimeout(600, TimeUnit.SECONDS)
.connectTimeout(600, TimeUnit.SECONDS).build();
Request downloadRequest = new Request.Builder().url(url + fileName).addHeader("cache-control", "no-cache")
.addHeader("Authorization", token).build();
try {
Response downloadResponse = client.newCall(downloadRequest).execute();
System.out.println(downloadResponse.message());
System.out.println("got response from blob " + downloadResponse.isSuccessful() + " " + fileName);
return downloadResponse;
} catch (IOException e1) {
e1.printStackTrace();
}
return null;
}
But the request is made asynchronously and before the request is completed then response is returned which is incomplete. Can anyone please help me how can i make a request and wait till the response is completed.
Any help is highly appreciated!
Looks like you're returning the response object (not the response body content).
try something like:
return downloadedResponse.body().string()
My experience with HttpClient is such that the headers return first. The content doesn't necessarily come across the wire unless/until you consume it.
To make a synchronous GET request we need to build a Request object based on a URL and make a Call. After its execution we get back an instance of Response:
#Test
public void whenGetRequest_thenCorrect() throws IOException {
Request request = new Request.Builder()
.url(BASE_URL + "/date")
.build();
Call call = client.newCall(request);
Response response = call.execute();
assertThat(response.code(), equalTo(200));
}
You are already using synchronous method calling.
client.newCall(downloadRequest).execute();
This is a synchronous way of requesting URL. If you want to do the aysynchronous call you need to use enqueue method of Call class.
call.enqueue(new Callback() {
public void onResponse(Call call, Response response)
throws IOException {
// ...
}
public void onFailure(Call call, IOException e) {
fail();
}
});
I think problem is somewhere else. Kindly give more details why you are suspecting the current one as an asynchronous call so that we can do RCA.
I tried to upload a image to the server, it throws me the Error 405 : Method not found, but from that same Url i can able to Download any files.. following is the code i tried.
private void uploadFileToServer(ActionEvent event) throws IOException
{
try{
InfiniteProgress ip = new InfiniteProgress();
Dialog dlg = ip.showInifiniteBlocking();
dlg.show();
MultipartRequest request = new MultipartRequest();
FileSystemStorage fs = FileSystemStorage.getInstance();
String fileUri = fs.getAppHomePath() + "654319032015150536IR.png";
request.setUrl("http://192.XX.XX.58:XX/HttpFolder/");
request.setPost(true);
InputStream is = FileSystemStorage.getInstance().openInputStream(fileUri);
request.addData("file", is, FileSystemStorage.getInstance().getLength(fileUri), "image/png");
request.setFilename("file", fileUri);
request.setPriority(ConnectionRequest.PRIORITY_CRITICAL);
NetworkManager.getInstance().addToQueue(request);
dlg.dispose();
if (event instanceof NetworkEvent) {
NetworkEvent ne = (NetworkEvent)event;
Dialog.show("Result:", ne.getMetaData().toString(), "","");
}
}
catch(Exception e){
Dialog.show("ERROR", e.getMessage(), "OK",null);
}
}
You can't upload to an arbitrary URL, you need to have a servlet that handles multipart on the POST http method.
We have a demo that includes the server side code here: http://codenameone.com/blog/build-mobile-ios-apps-in-java-using-codename-one-on-youtube.html
Notice that you also did some other "problematic" things in the code such as using PRIORITY_CRITICAL and using the InputStream API rather than just giving the file URL (which is more efficient).
I'm trying to post the following data to my rails App. It's expecting the format to be as follows:
Parameters: {
"utf8"=>"✓",
"authenticity_token"=>"oSJ2ut0T1HGJ+KcBAPPP4lwn8Hc4Xwkn8emVujXy9xQ=",
"wine"=>{"name"=>"nice wine", "vintage"=>"1923", "price"=>"412.2", "photo"=>#<ActionDispatch::Http::UploadedFile:0x007f9c86243d38 #tempfile=#<Tempfile:/var/folders/z9/r6hjby6x2cvfrlldtv7djz8c0000gn/T/RackMultipart20140825-4734-em8b0l>, #original_filename="timtams.jpeg",
#content_type="image/jpeg",
#headers="Content-Disposition: form-data; name=\"wine[photo]\"; filename=\"timtams.jpeg\"\r\nContent-Type: image/jpeg\r\n">}, "commit"=>"Create Wine"}
However, I'm getting this now from my android app:
Parameters: {
"photo"=>#<ActionDispatch::Http::UploadedFile:0x007f8b69bd2968 #tempfile=#<Tempfile:/var/folders/z9/r6hjby6x2cvfrlldtv7djz8c0000gn/T/RackMultipart20140827-3309-f5b613>, #original_filename="20140608_172146-3-1.jpg", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"photo\"; filename=\"20140608_172146-3-1.jpg\"\r\nContent-Type: application/octet-stream\r\n">,
"name"=>"test1",
"vintage"=>"1927",
"price"=>"19.27"}
Is there a way to define "wine" in front of the parameters?
The following are my current codes:
/**
* Created by zhongqinng on 26/8/14.
*/
public class UploadAsync extends AsyncTask {
private String TAG = "UploadAsync";
#Override
protected Object doInBackground(Object[] params) {
postMyWine2();
return null;
}
public void postMyWine2(){
Log.i(TAG, "postMyWine2 start");
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(WineStoryHTTPClient.BASE_URL + "/wines");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
File photofile = new File("/storage/sdcard0/Download/20140608_172146-3-1.jpg");
builder.addPart("photo", new FileBody(photofile));
builder.addTextBody("name", "test1");
builder.addTextBody("vintage", "1927");
builder.addTextBody("price", "19.27");
post.setEntity(builder.build());
Log.i(TAG,"postMyWine2 post.getParams() = "+post.getParams());
try {
Log.i(TAG,"postMyWine2 posting");
HttpResponse response = client.execute(post);
} catch (Exception e) {
Log.i(TAG,"postMyWine2 post Exception");
e.printStackTrace();
}
// HttpEntity entity = response.getEntity();
}
}
Managed to solve the issue by implementing a workaround at server side:
changed the format which server side expects.
however i'm still interested to find out how to format the post params from client side.
def create
# #wine = Wine.new(wine_params)
#wine = Wine.new( :name => params[:name], :vintage => params[:vintage], :price => params[:price] ,:photo => params[:photo])
respond_to do |format|
if #wine.save
format.html { redirect_to #wine, notice: 'Wine was successfully created.' }
format.json { render :show, status: :created, location: #wine }
else
format.html { render :new }
format.json { render json: #wine.errors, status: :unprocessable_entity }
end
end
end
I need to log the full http request and response in a JAX-WS WebService call. For the request I need the request headers and the body and for the response, response headers and body.
After some researching, I've found that I can get this information with the property:
-Dcom.sun.xml.ws.transport.http.client.HttpTransportPipe.dump=true
and show the information that I need but it dumps it to the console and I need to store it in the database with an internal request id.
I've tried to implement a handler:
public class LoggingHandler implements SOAPHandler<SOAPMessageContext> {
#Override
public boolean handleMessage(SOAPMessageContext context) {
Boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
System.out.println("SOAP outbound!!!!!");
Map<String, List<String>> responseHeaders = (Map<String, List<String>>) context
.get(SOAPMessageContext.HTTP_RESPONSE_HEADERS);
try {
String headers = getHeaders(responseHeaders);
System.out.println(headers);
String body = getBody(context.getMessage());
System.out.println(body);
} catch (Exception ex) {
// TODO: What do I have to do in this case?
}
} else {
System.out.println("SOAP inbound!!!!!");
Map<String, List<String>> requestHeaders = (Map<String, List<String>>) context
.get(SOAPMessageContext.HTTP_REQUEST_HEADERS);
try {
String headers = getHeaders(requestHeaders);
System.out.println(headers);
String body = getBody(context.getMessage());
System.out.println(body);
} catch (Exception ex) {
// TODO: What do I have to do in this case?
}
}
return true;
}
private String getBody(SOAPMessage message) throws SOAPException, IOException {
OutputStream stream = new ByteArrayOutputStream();
message.writeTo(stream);
return stream.toString();
}
public String getFullHttpRequest(HttpServletRequest request) throws IOException {
InputStream in = request.getInputStream();
String encoding = request.getCharacterEncoding();
encoding = encoding == null ? "UTF-8" : encoding;
String body = IOUtils.toString(in, encoding);
return body;
}
private String getHeaders(Map<String, List<String>> headers) throws IOException {
StringBuffer result = new StringBuffer();
if (headers != null) {
for (Entry<String, List<String>> header : headers.entrySet()) {
if (header.getValue().isEmpty()) {
// I don't think this is legal, but let's just dump it,
// as the point of the dump is to uncover problems.
result.append(header.getValue());
} else {
for (String value : header.getValue()) {
result.append(header.getKey() + ": " + value);
}
}
result.append("\n");
}
}
return result.toString();
}
}
but in this case, I can get the http request headers and body but in the response, I only get the body, http response headers are always empty.
Any idea on how to archieve this? The objective is to be able to store the full http request and response in a database.
Thanks!!
You could also try
-Dcom.sun.xml.ws.transport.http.HttpAdapter.dump=true
I'm assuming you're providing your web service from within a Java EE application server of some sort (and not from a standalone client). You cannot have access to Java EE infrastructure like HttpServletRequest and HttpServletResponse outside of the context of a web/Java EE container.
You could try to get your hands on the actual servlet response object (within a web context) with
HttpServletResponse response = (HttpServletResponse) messageContext.get(SOAPMessageContext.SERVLET_RESPONSE); //messageContext is the SOAPMessageContext
List<String> responseHeaderNames = (List<String>)response.getHeaderNames();
for(String headerName : responseHeaderNames){
//Do whatever you want with it.
}
I seriously doubt that you'll be able to get your hands on the full response headers within a handler though. Your question really intrigued me and I've spent quite some time researching that part. In all the code samples I've seen, Not even the example on the metro site attempt to implement this functionality and I think the reason is simple. As at the point where a handler is invoked, the container may not have enough definitive information to stamp an http header on the outbound message. You might be able to add stuff but that's doubtful as well.