I am trying to POST a file using HttpClient. However, I don't have access to the actual File but I have access to its InputStream. Is there a way I can still POST the file?
This is what I have done so far:
public void sendFile (InputStream instream) {
HttpClient client = new HttpClient();
PostMethod method = new PostMethod("http://localhost:8080/myservice/testupload");
Part[] parts = new Part[] {
//new FilePart("myFile", file.getName(), file)
};
method.setRequestEntity(
new MultipartRequestEntity(parts, method.getParams()));
client.executeMethod(method);
}
as you can see, the FilePart needs file but I have InputStream. How can I POST the input stream as a file?
Looking at the javadoc for FilePart, there is a constructor which accepts PartSource instead of File, and there is a subclass of PartSource called ByteArrayPartSource, which you can construct from byte[]; you can obtain this from the InputStream as described here.
Related
I'm using org.apache.http.* and trying to PUT a file. I can do it with the below reference to the actual file, however, I'm looking for a way to do it by passing in an InputStream
File file = new File("/mytestfile.txt")
HttpPut request = new HttpPut("http://sharepointportal/site/mytestfile.txt");
request.setEntity(new FileEntity(file));
CloseableHttpResponse response = httpclient.execute(new HttpHost("sharepointportal"), request);
FileEntity doesn't seem to have a constructor that supports InputStream.
Question
How can I setEntity for HttpPut request with an InputStream?
I want to send a file via Telegram Bot API, but I don't know how should I do that in Java (posting multipart/form-data) with provided Telegram Bot HTTP API method, sendDocument.
Here is my code:
CloseableHttpClient client = HttpClients.createDefault();
HttpPost upload = new HttpPost("https://api.telegram.org/bot"+Main.token+"/sendDocument?chat_id="+id);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
File file = new File(path);
builder.addBinaryBody(
"document",
new FileInputStream(file));
HttpEntity part = builder.build();
upload.setEntity(part);
CloseableHttpResponse response = client.execute(upload);
Here are the docs.
i hope this help you.
private void sendDocUploadingAFile(Long chatId, java.io.File save,String caption) throws TelegramApiException {
SendDocument sendDocumentRequest = new SendDocument();
sendDocumentRequest.setChatId(chatId);
sendDocumentRequest.setNewDocument(save);
sendDocumentRequest.setCaption(caption);
sendDocument(sendDocumentRequest);
}
EDIT :
this pages can help any one to start coding with telegram-bot api
Telegram FAQ
a good tutorial
Is it possible to embed a file attachment in a JSON Object. I have a HTML Form, which has several text field inputs and a file attachment. I want to send a JSON Object wrapping all these form data (including the file attachment) to the server.
Are there any particular libraries in Java available to do that? Can you give possible solution for this.
Thanks
If you want to send the actual data of the file, you'd probably want to encode it as a base64 string and send that in your JSON - see fiddle for example of encoding it in javascript:
http://jsfiddle.net/eliseosoto/JHQnk/
Then you could do the opposite on your server-side using whatever language and/or libraries are appropriate.
Use MultipartEntity, someone else posted a similar question: How to send file in JSON on android?
You could also consider saving the files on the server and sending a path/url to the file location where the other server can access them.
public String SendToServer(String aUrl,File Filename)
{
HttpClient httpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(filename);
try
{
MultipartEntity entity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
entity.addPart("file", new FileBody(Filename));
entity.addPart("video-title", new StringBody("Video"));
entity.addPart("video-type", new StringBody("1"));
httpPost.setEntity(entity);
HttpContext context = new BasicHttpContext();
// Bind custom cookie store to the local context
context.setAttribute(ClientContext.COOKIE_STORE, Globals.sessionCookie);
HttpResponse response = httpClient.execute(httpPost, context);
HttpEntity resEntity = response.getEntity();
String Response = "";
if (response != null)
{
Response = EntityUtils.toString(resEntity);
}
return Response;
}
catch (IOException e)
{
e.printStackTrace();
}
return "Exception";
}
I need to send a tar.gzip file from one java app (via a Servlet) to another - I'm using HTTP client with a MultipartEntity to achieve this.
During the file transfer, the file seems to double in size - as if it's being decompressed - and it's no longer recognizable as either a tar.gz or tar file.
Here's the send method:
HttpClient http = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
MultipartEntity multipart = new MultipartEntity();
ContentBody fileContent = new FileBody(file, "application/octet-stream");
ContentBody pathContent = new StringBody(file.getAbsolutePath());
multipart.addPart("package", fileContent);
multipart.addPart("path", pathContent);
post.setEntity(multipart);
HttpResponse response = null;
try {
response = http.execute(post);
StringWriter sw = new StringWriter();
IOUtils.copy(response.getEntity().getContent(), sw);
} catch (Exception ex){
log.error("Unable to POST to ["+url+"].",ex);
}
return result;
Here is the servlet method the above code is POSTing to:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
log.info("File transfer request received, collecting file information and saving to server.");
Part filePart = req.getPart("package");
Part filePathPart = req.getPart("path");
StringWriter sw = new StringWriter();
IOUtils.copy(filePathPart.getInputStream(), sw);
String path = sw.getBuffer().toString();
File outputFile = new File(path);
FileWriter out = new FileWriter(outputFile);
IOUtils.copy(filePart.getInputStream(), out);
log.info("File ["+path+"] has been saved to the server.");
out.close();
sw.close();
}
I'm no expert on this stuff - and there doesn't appear to be much help via Google... Any help would be great.
Thanks,
Pete
Your concrete problem is caused because you're converting the incoming bytes to characters by using FileWriter instead of FileOutputStream here:
FileWriter out = new FileWriter(outputFile);
ZIP files are binary files, represented by a specific sequence of bytes, not character files like text, HTML, XML, etc. With converting bytes to characters this way, you're only malforming the original binary content which causes that the file is not recognizeable as a ZIP file anymore. You end up with a corrupted file.
If you use FileOutputStream instead, then your problem will be solved. There's absolutely no need to replace this all with Commons FileUpload.
See also:
How to upload files to server using JSP/Servlet?
Unrelated to the concrete problem, reusing a client side specific absolute path in the server side is not a good idea for security reasons, but you'll find out that sooner or later. Rather reuse at highest the filename, preferably in combination with File#createTempFile() to autogenerate an unique filename suffix.
I made this work by using Apache commons File Upload:
Send code:
HttpClient http = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
post.addHeader("path", file.getAbsolutePath());
MultipartEntity multipart = new MultipartEntity();
ContentBody fileContent = new FileBody(file); //For tar.gz: "application/x-gzip"
multipart.addPart("package", fileContent);
post.setEntity(multipart);
Receive code:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
log.info("File transfer request received, collecting file information and saving to server.");
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
try {
List fileItems = upload.parseRequest(req);
Iterator iterator = fileItems.iterator();
if (iterator.hasNext()){
FileItem fileItem = (FileItem) iterator.next();
File file = new File(req.getHeader("path"));
fileItem.write(file);
log.info("File ["+fileItem.getName()+"] has been saved to the server.");
}
} catch (Exception ex) {
log.error("Unable to retrieve or write file set...",ex);
}
}
How do I get an OutputStream using org.apache.http.impl.client.DefaultHttpClient?
I'm looking to write a long string to an output stream.
Using HttpURLConnection you would implement it like so:
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
OutputStream out = connection.getOutputStream();
Writer wout = new OutputStreamWriter(out);
writeXml(wout);
Is there a method using DefaultHttpClient similar to what I have above? How would I write to an OutputStream using DefaultHttpClient instead of HttpURLConnection?
e.g
DefaultHttpClient client = new DefaultHttpClient();
OutputStream outstream = (get OutputStream somehow)
Writer wout = new OutputStreamWriter(out);
I know that another answer has already been accepted, just for the record this is how one can write content out with HttpClient without intermediate buffering in memory.
AbstractHttpEntity entity = new AbstractHttpEntity() {
public boolean isRepeatable() {
return false;
}
public long getContentLength() {
return -1;
}
public boolean isStreaming() {
return false;
}
public InputStream getContent() throws IOException {
// Should be implemented as well but is irrelevant for this case
throw new UnsupportedOperationException();
}
public void writeTo(final OutputStream outstream) throws IOException {
Writer writer = new OutputStreamWriter(outstream, "UTF-8");
writeXml(writer);
writer.flush();
}
};
HttpPost request = new HttpPost(uri);
request.setEntity(entity);
You can't get an OutputStream from BasicHttpClient directly. You have to create an HttpUriRequest object and give it an HttpEntity that encapsulates the content you want to sent. For instance, if your output is small enough to fit in memory, you might do the following:
// Produce the output
ByteArrayOutputStream out = new ByteArrayOutputStream();
Writer writer = new OutputStreamWriter(out, "UTF-8");
writeXml(writer);
// Create the request
HttpPost request = new HttpPost(uri);
request.setEntity(new ByteArrayEntity(out.toByteArray()));
// Send the request
DefaultHttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(request);
If the data is large enough that you need to stream it, it becomes more difficult because there's no HttpEntity implementation that accepts an OutputStream. You'd need to write to a temp file and use FileEntity or possibly set up a pipe and use InputStreamEntity
EDIT See oleg's answer for sample code that demonstrates how to stream the content - you don't need a temp file or pipe after all.
This worked well on android. It should also work for large files, as no buffering is needed.
PipedOutputStream out = new PipedOutputStream();
PipedInputStream in = new PipedInputStream();
out.connect(in);
new Thread() {
#Override
public void run() {
//create your http request
InputStreamEntity entity = new InputStreamEntity(in, -1);
request.setEntity(entity);
client.execute(request,...);
//When this line is reached your data is actually written
}
}.start();
//do whatever you like with your outputstream.
out.write("Hallo".getBytes());
out.flush();
//close your streams
I wrote an inversion of Apache's HTTP Client API [PipedApacheClientOutputStream] which provides an OutputStream interface for HTTP POST using Apache Commons HTTP Client 4.3.4.
Calling-code looks like this:
// Calling-code manages thread-pool
ExecutorService es = Executors.newCachedThreadPool(
new ThreadFactoryBuilder()
.setNameFormat("apache-client-executor-thread-%d")
.build());
// Build configuration
PipedApacheClientOutputStreamConfig config = new
PipedApacheClientOutputStreamConfig();
config.setUrl("http://localhost:3000");
config.setPipeBufferSizeBytes(1024);
config.setThreadPool(es);
config.setHttpClient(HttpClientBuilder.create().build());
// Instantiate OutputStream
PipedApacheClientOutputStream os = new
PipedApacheClientOutputStream(config);
// Write to OutputStream
os.write(...);
try {
os.close();
} catch (IOException e) {
logger.error(e.getLocalizedMessage(), e);
}
// Do stuff with HTTP response
...
// Close the HTTP response
os.getResponse().close();
// Finally, shut down thread pool
// This must occur after retrieving response (after is) if interested
// in POST result
es.shutdown();
Note - In practice the same client, executor service, and config will likely be reused throughout the life of the application, so the outer prep and close code in the above example will likely live in bootstrap/init and finalization code rather than directly inline with the OutputStream instantiation.