I am using the S3 REST API as I do not want to use the 100+ MB Java SDK for a simple file upload. I am having a little trouble here setting the ACL while uploading a text file. The code gives a response OK without the marked line below but that leaves the ACL to private read only. I want to make the file public by adding the marked line. But that gives me a Forbidden message. Any help here?
int BUFFER_SIZE = 4096;
String name = "file.txt";
String method = "PUT";
String bucket = "bucket";
String secretKey = "******";
String filePath = "F:\\file.txt";
SimpleDateFormat df = new SimpleDateFormat("EEE', 'dd' 'MMM' 'yyyy' 'HH:mm:ss' 'Z", Locale.US);
Date date = new Date();
String formattedDate = df.format(date);
File uploadFile = new File(filePath);
URL url = new URL("http://bucket.s3.amazonaws.com/" + name);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
String resource = "/" + bucket + "/" + name;
String contentType = "text/plain";
String signn = method + "\n\n" + contentType + "\n" + formattedDate + "\n" + resource ;
Mac hmac = Mac.getInstance("HmacSHA1");
hmac.init(new SecretKeySpec(
secretKey.getBytes("UTF-8"), "HmacSHA1"));
String signature = (new BASE64Encoder()).encode(
hmac.doFinal(signn.getBytes("UTF-8"))).replaceAll("\n", "");
String authAWS = "AWS " + "**SECRET**" + ":" + signature;
httpConn.setDoOutput(true);
httpConn.setRequestMethod(method);
httpConn.setRequestProperty("Accept", "*/*");
httpConn.setRequestProperty("Date", formattedDate);
httpConn.setRequestProperty("Content-type", contentType);
httpConn.setRequestProperty("Authorization", authAWS);
httpConn.setRequestProperty("x-amz-acl", "public-read"); // <----- THIS LINE HERE!
OutputStream outputStream = httpConn.getOutputStream();
FileInputStream inputStream = new FileInputStream(uploadFile);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
System.out.println("Response message : " + httpConn.getResponseMessage());
Related
I'm trying to download a file from an URL, but when my file is saved the name is different than it should be when it contains special characters. Here is the code I'm using
URL url = new URL(fileURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String disposition = httpConn.getHeaderField("Content-Disposition");
String contentType = httpConn.getContentType();
int contentLength = httpConn.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 10,
disposition.length() - 1);
}
} else {
// extracts file name from URL
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
fileURL.length());
}
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
// opens input stream from the HTTP connection
InputStream inputStream = httpConn.getInputStream();
String saveFilePath = saveDir + File.separator + fileName;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
System.out.println("Fichier téléchargé");
} else {
System.out.println("Pas de fichier trouvé à l'URL: " + fileURL + ".
HTTP code retourné par le serveur: " + responseCode);
}
httpConn.disconnect();
}
This is the name in the server "&éù%$£µ#çàè.png" and this is the name I get after download "&éù%$£µ#çà è.png"
What I'am getting wrong?
PS: here is an example of the output of my code
Répertoire de sauvegarde: C:\Data\downloads
Content-Type = image/png
Content-Disposition = attachment; filename="&éù%$£µ#çà è.png"
Content-Length = 2208482
Thanks in advance!
I have FileDownloader class that downloads the file from google drive and than these files can be used by other classes. I need also to extract filename somehow. The problem is that this solution below works good for direct links, but it doesn't work when links are shorten with bit.ly for example...
Could you please advise how I can change the code to get the right file name?
public class FileDownloader {
private static final int BUFFER_SIZE = 4096;
public static void downloadFile(String fileURL, String saveDir)
throws IOException {
URL url = new URL(fileURL);
HttpURLConnection httpConn = (HttpURLConnection) url.openConnection();
int responseCode = httpConn.getResponseCode();
// checking HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String disposition = httpConn.getHeaderField("Content-Disposition");
String contentType = httpConn.getContentType();
int contentLength = httpConn.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename*=UTF-8''");
if (index > 0) {
fileName = disposition.substring(index + 17,
disposition.length());
}
} else {
// extracts file name from URL
fileName = fileURL.substring(fileURL.lastIndexOf("/") + 1,
fileURL.length());
}
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
System.out.println("fileName = " + fileName);
// opens input stream from the HTTP connection
InputStream inputStream = httpConn.getInputStream();
String saveFilePath = saveDir + File.separator + fileName;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.close();
inputStream.close();
System.out.println("File downloaded");
} else {
System.out.println("No file to download. Server replied HTTP code: " + responseCode);
}
httpConn.disconnect();
}
Alternate Code to get File details from any HTTP URL using Java API:
URL url = new URL("http://www.example.com/somepath/filename.extension");
System.out.println(FilenameUtils.getBaseName(url.getPath()));
// filename
System.out.println(FilenameUtils.getName(url.getPath()));
// filename.extension
I am using java to make a REST Api call to Azure, put an object to its storage.
I did this successfully last week but now its now working for some reasons.
The error message is as below:
<?xml version="1.0" encoding="utf-8" ?>
<Error>
<Code>AuthenticationFailed</Code>
<Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:a15f2626-0001-004f-778c-f34383000000 Time:2017-07-02T23:43:20.2826278Z</Message>
<AuthenticationErrorDetail>The Date header in the request is incorrect.</AuthenticationErrorDetail>
</Error>
I don't think this is caused by the incorrect time stamp because the "Date" field and the response time are within 15 minutes. The "Date" field in the header is Sun, 2 Jul 2017 23:38:04 GMT
Here are my java code to generate the token and send the request.
public void putObject(String blobName) {
try {
URL restServiceURL = new URL(getCallAddress() + "/" + blobName);
HttpURLConnection httpConnection = (HttpURLConnection) restServiceURL.openConnection();
Calendar cd = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("EEE, d MMM yyyy HH:mm:ss 'GMT'", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = sdf.format(cd.getTime());
httpConnection.setDoInput(true);
httpConnection.setDoOutput(true);
try {
httpConnection.setRequestMethod("PUT");
} catch (ProtocolException e) {
e.printStackTrace();
}
httpConnection.setFixedLengthStreamingMode(getFile().length()); //set output size to avoid out of memory error
try {
String token = createToken(blobName, date);
httpURLConnection.setRequestProperty("Authorization", "SharedKey " + Azure_AccountName + ":" + token);
} catch (Exception e) {
log.error("Cannot get token");
e.printStackTrace();
}
httpURLConnection.setRequestProperty("Content-Length", String.valueOf(getFile().length()));
httpURLConnection.setRequestProperty("x-ms-blob-type", "BlockBlob");
httpURLConnection.setRequestProperty("x-ms-version", "2015-12-11");
httpURLConnection.setRequestProperty("x-ms-date",date);
} catch (IOException e) {
log.error(e);
e.printStackTrace();
}
FileInputStream inputStream = new FileInputStream(getFile());
try {
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
OutputStream out = httpConnection.getOutputStream();
out.write(buffer);
out.flush();
out.close();
int code = httpConnection.getResponseCode();
if (code != 201 && code != 200) {
log.error(code + httpConnection.getResponseMessage());
throw new UnsupportedOperationException("Put object failed");
}
httpConnection.disconnect();
} catch (Exception e) {
log.error(e);
e.printStackTrace();
} finally {
IOUtils.closeQuietly(inputStream);
}
}
private String createToken(String blobName, String date) throws InvalidKeyException, NoSuchAlgorithmException,
UnsupportedEncodingException {
String signature = "PUT\n\n\n" + getFile().length() + "\n\n\n\n\n\n\n\n\nx-ms-blob-type:BlockBlob\nx-ms-date:" + date +
"\nx-ms-version:2015-12-11\n" + "/" + Azure_AccountName + "/" + Azure_BucketName + "/" + blobName;
SecretKey secreteKey = new SecretKeySpec(Base64.decode(KEY), "HmacSHA256");
Mac sha256HMAC = Mac.getInstance(secreteKey.getAlgorithm());
sha256HMAC.init(secreteKey);
byte[] digest = sha256HMAC.doFinal(signature.getBytes("UTF8"));
return new String(Base64.encode(digest));
}
You could refer to the code below if you haven't solved this Authentication error:
public class PutTest {
private static final String account = <your account name>;
private static final String key = <your account key>;
public static void main(String args[]) throws Exception {
File file = new File(<your file path>);
FileInputStream inputStream = new FileInputStream(<your file path>);
String urlString = "https://" + account + ".blob.core.windows.net/<your container>/<your file name e.g:test.txt>";
HttpURLConnection connection = (HttpURLConnection) (new URL(urlString)).openConnection();
getFileRequest(connection, account, key, file.length());
// connection.connect();
connection.setDoInput(true);
connection.setDoOutput(true);
byte[] buffer = new byte[inputStream.available()];
inputStream.read(buffer);
OutputStream out = connection.getOutputStream();
out.write(buffer);
out.flush();
out.close();
System.out.println("Response message : " + connection.getResponseMessage());
System.out.println("Response code : " + connection.getResponseCode());
BufferedReader br = null;
if (connection.getResponseCode() != 200) {
br = new BufferedReader(new InputStreamReader((connection.getErrorStream())));
} else {
br = new BufferedReader(new InputStreamReader((connection.getInputStream())));
}
System.out.println("Response body : " + br.readLine());
}
public static void getFileRequest(HttpURLConnection request, String account, String key, long length)
throws Exception {
SimpleDateFormat fmt = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
String date = fmt.format(Calendar.getInstance().getTime()) + " GMT";
String stringToSign = "PUT\n" + "\n" // content encoding
+ "\n" // content language
+length+"\n"// content length
+ "\n" // content md5
+"\n" // content type
+ "\n" // date
+ "\n" // if modified since
+ "\n" // if match
+ "\n" // if none match
+ "\n" // if unmodified since
+ "\n" // range
+ "x-ms-blob-type:BlockBlob" + "\n"
+ "x-ms-date:" + date + "\n"
+ "x-ms-version:2015-02-21"+"\n" // headers
+ "/" + account + request.getURL().getPath(); // resources
System.out.println("stringToSign : " + stringToSign);
String auth = getAuthenticationString(stringToSign);
request.setRequestMethod("PUT");
request.setRequestProperty("x-ms-blob-type", "BlockBlob");
request.setRequestProperty("x-ms-date", date);
request.setRequestProperty("x-ms-version", "2015-02-21");
request.setRequestProperty("Authorization", auth);
request.setRequestProperty("Content-Length", String.valueOf(length));
}
private static String getAuthenticationString(String stringToSign) throws Exception {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(Base64.decode(key), "HmacSHA256"));
String authKey = new String(Base64.encode(mac.doFinal(stringToSign.getBytes("UTF-8"))));
String auth = "SharedKey " + account + ":" + authKey;
return auth;
}
}
Hope it helps.
I have following code, it downloads the file, but Adobe says that the file is damage. The file is 74KB big, but I can only download about 27KB. Can you tell me what's wrong. Thanks
#WebServlet("/GetData")
public class GetData extends HttpServlet {
private static final long serialVersionUID = 1L;
private static final int BUFFER_SIZE = 4096;
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
String typ = ".pdf";
int totalBytesRead = 0;
String sep = File.separator;
String saveDir = "C:" + sep + "downloads";
String link ="/g02pepe/portal?token=9059829732446568452&action_16502593.mainContent_root_cntXYZ_cntShow_actShowFirstRow::km_XXXXXXX-XXXX::=&frontletId=XXXXX";
String adress = "https://XXXXXXX.XXXX.de/g02pepe/entry?rzid=XC&rzbk=0032&trackid=piwikad277d23c35b4990";
String together = adress + link;
String username = "XXXXXXXXX";
String password = "XXXXXXXXX";
String authString = username + ":" + password;
System.out.println("Auth string: " + authString);
byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
String authStringEnc = new String(authEncBytes);
try {
URL url = new URL(adress);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.addRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:37.0) Gecko/20100101 Firefox/37.0");
connection.setRequestProperty("Authorization", "Basic " + authStringEnc);
connection.addRequestProperty("Referer", together);
System.out.println("Connected to " + together);
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.connect();
int responseCode = connection.getResponseCode();
// always check HTTP response code first
if (responseCode == HttpURLConnection.HTTP_OK) {
String fileName = "";
String disposition = connection.getHeaderField("Content-Disposition");
String contentType = connection.getContentType();
int contentLength = connection.getContentLength();
if (disposition != null) {
// extracts file name from header field
int index = disposition.indexOf("filename=");
if (index > 0) {
fileName = disposition.substring(index + 10,
disposition.length() - 1);
}
} else {
// extracts file name from URL
fileName = adress.substring(adress.lastIndexOf("/") + 1,
adress.length());
}
System.out.println("Content-Type = " + contentType);
System.out.println("Content-Disposition = " + disposition);
System.out.println("Content-Length = " + contentLength);
System.out.println("fileName = " + fileName);
InputStream in = connection.getInputStream();
String saveFilePath = saveDir + File.separator + "Entgeltinformationen" + typ;
// opens an output stream to save into file
FileOutputStream outputStream = new FileOutputStream(saveFilePath);
int bytesRead = -1;
byte[] buffer = new byte[BUFFER_SIZE];
while ((bytesRead = in.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
totalBytesRead += bytesRead;
}
System.out.println("Total Bytes read " + totalBytesRead);
outputStream.close();
in.close();
System.out.println("File downloaded");
} else {
System.out
.println("No file to download. Server replied HTTP code: "
+ responseCode);
}
connection.disconnect();
out.println("Download done!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
The file which i want to download is PDF.
How to convert AppEngineFile to an array of bytes?
I have my File created from the blobkey like this
AppEngineFile file = fileService.getBlobFile(new BlobKey("blob key"));
I already tried something like this
FileService fileService = FileServiceFactory.getFileService();
// Create a new Blob file with mime-type "text/plain"
AppEngineFile file = fileService.getBlobFile(new BlobKey(video.getBlobkey()));
BlobstoreInputStream b = new BlobstoreInputStream(new BlobKey(video.getBlobkey()));
RandomAccessFile f = new RandomAccessFile(file.getFullPath(), "r");
byte[] pixels = b.read(); //doesn't work
The idea is to send this array of bytes with a POST request.
Here is my code i have to build the request:
String attachmentName = "test";
String attachmentFileName = "test.mp4";
String crlf = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
HttpURLConnection httpUrlConnection = null;
URL url = new URL("http://example.com/server.cgi");
httpUrlConnection = (HttpURLConnection) url.openConnection();
httpUrlConnection.setUseCaches(false);
httpUrlConnection.setDoOutput(true);
DataOutputStream request = new DataOutputStream(httpUrlConnection.getOutputStream());
request.writeBytes(twoHyphens + boundary + crlf);
request.writeBytes("Content-Disposition: form-data; name=\"" + attachmentName + "\";filename=\"" + attachmentFileName + "\"" + crlf);
request.writeBytes(crlf);
// Get a file service
FileService fileService = FileServiceFactory.getFileService();
// Create a new Blob file with mime-type "text/plain"
AppEngineFile file = fileService.getBlobFile(new BlobKey(video.getBlobkey()));
BlobstoreInputStream b = new BlobstoreInputStream(new BlobKey(video.getBlobkey()));
RandomAccessFile f = new RandomAccessFile(file.getFullPath(), "r");
byte[] pixels = b.read();
request.write(pixels);
request.writeBytes(crlf);
request.writeBytes(twoHyphens + boundary + twoHyphens + crlf);
request.flush();
request.close();
InputStream responseStream = new BufferedInputStream(httpUrlConnection.getInputStream());
BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = responseStreamReader.readLine()) != null)
{
stringBuilder.append(line).append("\n");
}
responseStreamReader.close();
String response = stringBuilder.toString();
System.out.println(response);
You can simply do this:
FileReadChannel ch = fileservice.openReadChannel(file, true);
byte[] data = getBytes(Channels.newInputStream(ch));
and use this handy method (useable elsewhere):
public static byte[] getBytes(InputStream is) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
int len;
byte[] data = new byte[100000]; // adapt buffer size to your needs
while ((len = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, len);
}
buffer.flush();
return buffer.toByteArray();
}
AppEngineFile file = ...
int size = (int) fileservice.stat(file).getLength().longValue();
FileReadChannel ch = fileservice.openReadChannel(file, true);
ByteBuffer dst = ByteBuffer.allocate(size);
try {
int sum=0;
while (sum<size) {
int read = ch.read(dst);
sum+=read;
}
} finally {ch.close();}
bytes byte[] = dst.array();
(This is NOT the way of reading from a Channel in Java, but it seems there is a bug in appengine that requires you know the exact count of bytes).