Contents and format of URI when uploading or downloading file - java

I have an application which is an API on a server (say 192.168.0.2), to which files (of any format) can be uploaded or from which they can be downloaded.
If an application on another machine on the network (say 192.196.0.3) wants to upload a file to the API, it passes the information in a JSON Object e.g. { "FILE_LOCATION":"file:/192.168.0.3/c:/testDocs/testFile.docx" }
The code in the api goes roughly:
private static void doPost (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
String errorMessage = "";
try
{
String src = request.getParameter ("src");
Object obj = jsonParser.parse (src);
JSONObject jsonObj = (JSONObject) obj;
String fileLocation = (String) jsonObj.get ("FILE_LOCATION");
URI uri = new URI (fileLocation);
URL url = uri.toURL (); // get URL from your uri object
URLConnection urlConnection = url.openConnection ();
InputStream is = urlConnection.getInputStream ();
System.out.println ("InputStream = " + is);
if (is != null)
{
// create output file, output stream etc
}
}
catch (Exception e)
{
errorMessage = e.getMessage ();
System.out.println (e.getClass().getName () + " : " + errorMessage);
}
PrintWriter pw = response.getWriter ();
pw.append (errorMessage);
}
The system log invariably shows something like:
"java.io.FileNotFoundException : 192.168.0.3/c:/testDocs/testFile.docx (No such file or directory)"
What am I doing wrong? I am convinced that the fault lies in the way I have constructed the String which will be used to create the URI.

That does not look like a valid file: URL. On Windows you could try to check if a file is accessible from a remote server if dir works in CMD.EXE. For example, try UNC pathname:
dir \\IP_OR_HOSTNAME\NAMEOFSHARE\path\etc\filename.xyz
If that works - and that rather depends on whether the remote server is serving that filesystem as NAMEOFSHARE - then the equivalent file: encoding of above would be:
String u = new File("\\\\IP_OR_HOSTNAME\\NAMEOFSHARE\\path\\etc\\filename.xyz").toURL().toString();
==> "file://IP_OR_HOSTNAME/NAMEOFSHARE/path/etc/filename.xyz"

Related

Files remain open/locked in Azure Function - unable to delete

My program makes use of a library to upload a file located in an Azure File Share to Sharepoint, after which the file is deleted from Azure File Share. Below is a small (the relevant) part of my code; when I run it the file is uploaded correctly, but isn't removed afterwards isn't removed because it is still in use by an SMB client (it's "marked for deletion", but is only deleted once the Azure Function is disabled).
My guess was that since an InputStream is opened in the wrapper.uploadFile, but not closed that might be it, but resource.isOpen() always returns false
main.class
File file = new File (filepath);
Resource resource = new FileSystemResource(filepath);
PLGSharepointClient wrapper = new PLGSharepointClient(user, passwd, domain, spSiteUrl);
JSONObject jsonMetadata = new JSONObject();
wrapper.uploadFile(spFolder, resource, jsonMetadata);
resource.getInputStream().close();
System.out.println(resource.isOpen());
file.delete();
wrapper.uploadFile
public JSONObject uploadFile(String folder, Resource resource, JSONObject jsonMetadata) throws Exception {
LOG.debug("Uploading file {} to folder {}", resource.getFilename(), folder);
JSONObject submeta = new JSONObject();
submeta.put("type", "SP.ListItem");
jsonMetadata.put("__metadata", submeta);
headers = headerHelper.getPostHeaders("");
headers.remove("Content-Length");
byte[] resBytes = IOUtils.readFully(resource.getInputStream(), (int) resource.contentLength());
RequestEntity<byte[]> requestEntity = new RequestEntity<>(resBytes,
headers, HttpMethod.POST,
this.tokenHelper.getSharepointSiteUrl(
"/_api/web/GetFolderByServerRelativeUrl('" + UriUtils.encodeQuery(folder, StandardCharsets.UTF_8) +"')/Files/add(url='"
+ UriUtils.encodeQuery(resource.getFilename(), StandardCharsets.UTF_8) + "',overwrite=true)"
)
);
ResponseEntity<String> responseEntity =
restTemplate.exchange(requestEntity, String.class);
String fileInfoStr = responseEntity.getBody();
LOG.debug("Retrieved response from server with json");
JSONObject jsonFileInfo = new JSONObject(fileInfoStr);
String serverRelFileUrl = jsonFileInfo.getJSONObject("d").getString("ServerRelativeUrl");
LOG.debug("File uploaded to URI", serverRelFileUrl);
String metadata = jsonMetadata.toString();
headers = headerHelper.getUpdateHeaders(metadata);
LOG.debug("Updating file adding metadata {}", jsonMetadata);
RequestEntity<String> requestEntity1 = new RequestEntity<>(metadata,
headers, HttpMethod.POST,
this.tokenHelper.getSharepointSiteUrl("/_api/web/GetFileByServerRelativeUrl('" + UriUtils.encodeQuery(serverRelFileUrl, StandardCharsets.UTF_8) + "')/listitemallfields")
);
ResponseEntity<String> responseEntity1 =
restTemplate.exchange(requestEntity1, String.class);
LOG.debug("Updated file metadata Status {}", responseEntity1.getStatusCode());
return jsonFileInfo;
}
In your wrapper.upload file, add resource.getInputStream().close() and check if this works.

Java Azure Function - upload file in BLOB Container

I'm trying to make an Azure Function in Java. I need to make an excel file and upload it in BLOB container.
When I build the project and the tests start, then it works without problems and it uploads the file in the container, when instead I debug the project or I deploy it on Azure and I run it via internet (calling the service), it doesn't upload it. It blocks when it tries to upload the file.
Can you help me please? I'm on this problem since a few days.
Thank you.
I attach the method where it uploads the file:
#FunctionName("FunctionTest")
public HttpResponseMessage run(
#HttpTrigger(
name = "req",
methods = {HttpMethod.GET, HttpMethod.POST},
authLevel = AuthorizationLevel.ANONYMOUS)
HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
final String queryAccountName = request.getQueryParameters().get("AccountName");
String accountName = request.getBody().orElse(queryAccountName);
final String queryAccountKey = request.getQueryParameters().get("AccountKey");
String accountKey = request.getBody().orElse(queryAccountKey);
context.getLogger().info("Azure Blob storage v12 - Java quickstart sample\n");
// Retrieve the connection string for use with the application. The storage
// connection string is stored in an environment variable on the machine
// running the application called AZURE_STORAGE_CONNECTION_STRING. If the environment variable
// is created after the application is launched in a console or with
// Visual Studio, the shell or application needs to be closed and reloaded
// to take the environment variable into account.
// String connectStr = System.getenv("AZURE_STORAGE_CONNECTION_STRING");
//String connectStr = "DefaultEndpointsProtocol=https;AccountName="+accountName+";AccountKey="+accountKey+";EndpointSuffix=core.windows.net";
// Create a BlobServiceClient object which will be used to create a container client
//BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().connectionString(connectStr).buildClient();
StorageSharedKeyCredential credential = new StorageSharedKeyCredential(accountName, accountKey);
String endpoint = String.format(Locale.ROOT, "https://%s.blob.core.windows.net", accountName);
BlobServiceClient blobServiceClient = new BlobServiceClientBuilder().endpoint(endpoint).credential(credential).buildClient();
//Create a unique name for the container
String containerName = "container-name";
// Create the container and return a container client object
//BlobContainerClient containerClient = blobServiceClient.createBlobContainer(containerName);
BlobContainerClient containerClient = blobServiceClient.getBlobContainerClient(containerName);
// Create a local file in the ./data/ directory for uploading and downloading
/*String pathFile = "./data/";
String fileName = "quickstart" + java.util.UUID.randomUUID() + ".txt";
File localFile = new File(pathFile + fileName);
// Write text to the file
FileWriter writer;
try {
writer = new FileWriter(pathFile + fileName, true);
writer.write("Hello, World!");
writer.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}*/
// Get a reference to a blob
// Upload the blob
String pathFile = System.getenv("TEMP") + "\\";
String fileName = creaReport(context)+".xlsx"; // creating file Excel - IT DOESN'T EVEN WORK WITH TXT FILE
BlobClient blobClient = containerClient.getBlobClient(fileName);
System.out.println("\nUploading to Blob storage as blob:\n\t" + blobClient.getBlobUrl());
blobClient.uploadFromFile(pathFile + fileName, true); // IT BLOCKS HERE
System.out.println("\nListing blobs...");
// List the blob(s) in the container.
for (BlobItem blobItem : containerClient.listBlobs()) {
System.out.println("\t" + blobItem.getName());
}
// Download the blob to a local file
// Append the string "DOWNLOAD" before the .txt extension so that you can see both files.
//String downloadFileName = fileName.replace(".txt", "DOWNLOAD.txt");
String downloadFileName = fileName.replace(".xlsx", "DOWNLOAD.xlsx");
File downloadedFile = new File(pathFile + downloadFileName);
System.out.println("\nDownloading blob to\n\t " + pathFile + downloadFileName);
blobClient.downloadToFile(pathFile + downloadFileName, true);
// Clean up
System.out.println("\nPress the Enter key to begin clean up");
System.console().readLine();
/*System.out.println("Deleting blob container...");
containerClient.delete();*/
System.out.println("Deleting the local source and downloaded files...");
localFile.delete();
downloadedFile.delete();
System.out.println("Done");
return request.createResponseBuilder(HttpStatus.OK).body("Blob uploaded").build();
}
For this problem, I test it in my side and summarize the point as below:
The reason for this problem is the files in local/temp are not shared among site instances. You can refer to this page.
So I met the same problem as you, I deploy my java function to azure and add a file under local/temp path manually. Then run the function, it can't access the data of the file.
After that, I edit my function code. Create a txt file by the code below in my function:
String filePath="d:\\local\\Temp\\test1.txt";
File file = new File(filePath);
try {
FileWriter writer = new FileWriter(file);
writer.write("Test data");
writer.close();
} catch (IOException e1) {
context.getLogger().info(e1.getMessage());
e1.printStackTrace();
}
And then read the file in the same function by the code below:
InputStream is = null;
int i;
char c;
try {
is = new FileInputStream(filePath);
while ((i = is.read()) != -1) {
c = (char) i;
context.getLogger().info("===inputstream==" + c);
}
} catch (Exception e) {
context.getLogger().info("===try catch error");
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
context.getLogger().info("===finally error");
e.printStackTrace();
}
}
}
Deploy the code to azure, the function app run in a consumption plan(so it will just use one instance if I just run it once). Running it, I read the data of the file success.
According to the test above, I suggest you do not create the file in local/temp. You'd better create the file in d:\home\site\wwwroot, you can create a folder under wwwroot and create the files in the folder. I test it works fine.
Hope it helps~

Spring Controller download file from file system restriction

I have a Spring controller with /file mapping that gets a file name from user and stream file content to user
#RequestMapping(value = "/file" , method = RequestMethod.GET)
#ResponseBody
public void getFile(#RequestParam(value = "name", required = true) String fileName,
HttpServletResponse response)
{
String fileExtension = "";
int i = fileName.lastIndexOf('.');
if (i > 0) {
fileExtension = fileName.substring(i+1);
}
// file extension for requested file must be xls
if(!fileExtension.equals("xls"))
{
response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
return;
}
try {
Path path = Paths.get("/tmp/" + fileName);
byte[] data = Files.readAllBytes(path);
response.setHeader("Content-Disposition", "inline; filename=" + fileName);
response.setContentType("application/vnd.ms-excel");
response.setContentLength(data.length);
try {
ServletOutputStream outputStream = response.getOutputStream();
outputStream.write(data);
outputStream.flush();
} catch (Exception e) {
}
} catch (Exception e) {
}
}
User only can download file with .xls extension in tmp folder. the problem with this code is that user can change directory and download other .xls files in other directories. for example if there is a file in this path /tmp/tmp2/ab.xls user can download the file with calling this url http://myserver.mydomain:myport/mycontext/file?name=tmp2/ab.xls that is a security hole. what is the best way for checking name that I give from user is a file name? (not directory/filename or ../filename or another dangerous path )
Path tmpPath = Paths.get("/tmp/"); //valid directory
String fileName = "foo/bar.xls"; //supplied fileName
Path filePath = tmpPath.resolve(fileName); //add fileName to path
Path fileParent = filePath.getParent(); //get parent directory
System.out.println(fileParent);
System.out.println(tmpPath.equals(fileParent)); //false because fileParent is '/tmp/foo'
'tmpPath' will be equals 'fileParent' if you supply a valid fileName like 'bar.xls'.
I think you can also simplify the extension checking: filePath.endsWith(".xls"); should be enough. And don't concatenate file paths ("/tmp/" + fileName). Paths.get("/tmp", fileName) will do that for you.

perl filehandle doesn't read file with space in its name

I have a java program that call my Perl script to upload a file. It has a file parameter to the Perl script that contain the location of file to upload.
public static void legacyPerlInspectionUpload(String creator, String artifactId, java.io.File uploadedFile, String description ) {
PostMethod mPost = new PostMethod(getProperty(Constants.PERL_FILE_URL) + "inspectionUpload.pl");
try {
String upsSessionId = getUpsSessionCookie();
//When passing multiple cookies as a String, seperate each cookie with a semi-colon and space
String cookies = "UPS_SESSION=" + upsSessionId;
log.debug(getCurrentUser() + " Inspection File Upload Cookies " + cookies);
Part[] parts = {
new StringPart("creator", creator),
new StringPart("artifactId", artifactId),
new StringPart("fileName", uploadedFile.getName()),
new StringPart("description", description),
new FilePart("fileContent", uploadedFile) };
mPost.setRequestEntity(new MultipartRequestEntity(parts, mPost.getParams()));
mPost.setRequestHeader("Cookie",cookies);
HttpClient httpClient = new HttpClient();
int status = httpClient.executeMethod(mPost);
if (status == HttpStatus.SC_OK) {
String tmpRetVal = mPost.getResponseBodyAsString();
log.info(getCurrentUser() + ":Inspection Upload complete, response=" + tmpRetVal);
} else {
log.info(getCurrentUser() + ":Inspection Upload failed, response=" + HttpStatus.getStatusText(status));
}
} catch (Exception ex) {
log.error(getCurrentUser() + ": Error in Inspection upload reason:" + ex.getMessage());
ex.printStackTrace();
} finally {
mPost.releaseConnection();
}
}
In this part of my Perl script, it get the information about the file, read from it and write the content to a blink file in my server.
#
# Time to upload the file onto the server in an appropropriate path.
#
$fileHandle=$obj->param('fileContent');
writeLog("fileHandle:$fileHandle");
open(OUTFILE,">$AttachFile");
while ($bytesread=read($fileHandle,$buffer,1024)) {
print OUTFILE $buffer;
}
close(OUTFILE);
writeLog("Download file, checking stats.");
#
# Find out if the file was correctly uploaded. If it was not the file size will be 0.
#
($size) = (stat($AttachFile))[7];
Right now the problem is this only work for file with no space in its name, otherwise $size is 0. I was reading online and it seems both Java file and Perl filehandle work with space, so what am I doing wrong?
Your poor variable naming has tripped you up:
open(OUTFILE,">$AttachFile");
^^^^^^^---this is your filehandle
while ($bytesread=read($fileHandle,$buffer,1024)) {
^^^^^^^^^^^--- this is just a string
You're trying to read from something that's NOT a filehandle, it's just a variable whose name happens to be "filehandle". You never opened up the specified file for reading. e.g. you're missing
open(INFILE, "<$fileHandle");
read(INFILE, $buffer, 1024);

Reading directly from Google Drive in Java

Please I need to read the content of a file stored in Google Drive programmatically. I'm looking forward to some sort of
InputStream is = <drive_stuff>.read(fileID);
Any help?
I'll also appreciate if I can write back to a file using some sort of
OutputStream dos = new DriveOutputStream(driveFileID);
dos.write(data);
If this sort of convenient approach is too much for what Drive can offer, please I'll like to have suggestions on how I can read/write to Drive directly from java.io.InputStream / OutputStream / Reader / Writer without creating temporary local file copies of the data I want to ship to drive. Thanks!
// Build a new authorized API client service.
Drive service = getDriveService();
// Print the names and IDs for up to 10 files.
FileList result = service.files().list()
.setPageSize(10)
.setFields("nextPageToken, files(id, name)")
.execute();
List<File> files = result.getFiles();
if (files == null || files.size() == 0) {
System.out.println("No files found.");
} else {
System.out.println("Files:");
for (File file : files) {
System.out.printf("%s (%s)\n", file.getName(), file.getId());
String fileId = file.getId();
Export s=service.files().export(fileId, "text/plain");
InputStream in=s.executeMediaAsInputStream();
InputStreamReader isr=new InputStreamReader(in);
BufferedReader br = new BufferedReader(isr);
String line = null;
StringBuilder responseData = new StringBuilder();
while((line = br.readLine()) != null) {
responseData.append(line);
}
System.out.println(responseData);
}
}
}
Please take a look at the DrEdit Java sample that is available on the Google Drive SDK documentation.
This example shows how to authorize and build requests to read metadata, file's data and upload content to Google Drive.
Here is a code snippet showing how to use the ByteArrayContent to upload media to Google Drive stored in a byte array:
/**
* Create a new file given a JSON representation, and return the JSON
* representation of the created file.
*/
#Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
Drive service = getDriveService(req, resp);
ClientFile clientFile = new ClientFile(req.getReader());
File file = clientFile.toFile();
if (!clientFile.content.equals("")) {
file = service.files().insert(file,
ByteArrayContent.fromString(clientFile.mimeType, clientFile.content))
.execute();
} else {
file = service.files().insert(file).execute();
}
resp.setContentType(JSON_MIMETYPE);
resp.getWriter().print(new Gson().toJson(file.getId()).toString());
}
Here's a (incomplete) snippet from my app which might help.
URL url = new URL(urlParam);
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("GET");
connection
.setRequestProperty("Authorization",
"OAuth "+accessToken);
String docText = convertStreamToString(connection.getInputStream());
Using google-api-services-drive-v3-rev24-java-1.22.0:
To read the contents of a file, make sure you set DriveScopes.DRIVE_READONLY when you do GoogleAuthorizationCodeFlow.Builder(...) in your credential authorizing method/code.
You'll need the fileId of the file you want to read. You can do something like this:
FileList result = driveService.files().list().execute();
You can then iterate the result for the file and fileId you want to read.
Once you have done that, reading the contents would be something like this:
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
driveService.files().get(fileId).executeMediaAndDownloadTo(outputStream);
InputStream in = new ByteArrayInputStream(outputStream.toByteArray());

Categories

Resources