I have been googling constantly and can't seem to find an answer for this. My apologies if it's a noob question as I am still extremely new to Docker.
Scenario:
I have a dockerized web app with a NodeJS backend. On the website, I need to be able to upload files and store the path to them in the database (MSSql Database container). When I upload files using multiparty on the Node end, it gives it the temp path for files. On Windows, its ...../AppData/Local/Temp/.... On Linux, it looks to be /tmp/... Then, I use this path as a link to open the file from a different page. On Windows, running the app locally (no dockerizing), I can access the file (excluding Chrome's security features that prevent the download). However, on Linux and dockerized, there is no file. I will attach my file uploading code at the bottom.
I know that docker containers do not talk to the host's file system like a normal web application. My file isn't being stored in the /tmp folder as I've already checked there. My guess is that it is somehow storing it within the container.
My confusion lies with how to store these files. Volumes seem to be for loading files into containers and storage drivers don't seem to be something you can mess with other than to configure them (I am using overlay2 if it matters). How do I store the uploaded files within my container so that I can store their path and access them again later?
var app = express();
app.post("/api/files", function(req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
var dict = files.Contents[0];
console.log(dict);
var query = "EXECUTE CTF.dbo.CTF_CreateFilesSp " + fields.ID + ", '" + dict["originalFilename"] + "', '" + dict["path"] + "'";
executeQuery(query, res);
});
});
UPDATE:
I was able to get a volume/bind mount set up for my container using:
volumes:
- /var/opt/tmp:/var/opt/tmp
and I updated my parsing method to this:
app.post("/api/files", function(req, res) {
var form = new multiparty.Form();
var target_path = '';
form.on('file', function(name, file) {
var tmp_path = file.path;
target_path = '/var/opt/tmp/' + file.originalFilename;
fs.copyFile(tmp_path, target_path, function(err) {
if (err) console.error(err.stack);
else console.log(target_path);
})
});
form.parse(req, function(err, fields, files) {
var dict = files.Contents[0];
var query = "EXECUTE CTF.dbo.CTF_CreateFilesSp " + fields.ID + ", '" + dict["originalFilename"] + "', '" + target_path + "'";
executeQuery(query, res);
});
});
When I upload the file, I do see a copy of this show up in the host's directory as expected. However, when I click the link to the file on an html page, using the full path /var/opt/tmp/FILENAME, it says cannot GET /var/opt/tmp/FILENAME.
I'm sure this has to do with incorrect permissions or href in my html, but I'm not sure. I'm very new to web development.
How do I get the link on an html page to download this file from the directory? Please let me know if this is out of the scope of the original question and I'll make a new one.
Related
I have created a REST full APi, which works as I would be expecting if I am running Postman. I run the Test from an index.js file which would have the routes saved as per below file.
const config = require('config');
const mongoose = require('mongoose');
const users = require('./routes/users');
const auth = require('./routes/auth');
const express = require('express');
const app = express();
//mongoose.set();
if (!config.get('jwtPrivateKey'))
{
console.log('Fatal ERRORR: jwtPrivateKey key is not defined')
process.exit(1);
}
mongoose.connect(uri ,{
useNewUrlParser: true,
useUnifiedTopology: true,
useCreateIndex: true
})
.then(()=>console.log('Connected to MongoDB...'))
.catch(err=> console.log('Not Connected, bad ;(', err));
app.use(express.json());
//THis is only for posting the user, e.g. Registering them
app.use('/api/users', users);
app.use('/api/auth', auth);
const port = process.env.PORT || 3000;
app.listen(port, () => console.log(`Listening on port ${port}...`));
The real code is happening here. Testing this in Postmon I could establish, that the values are saved in MongoDB.
router.post('/', async (req, res) => {
//validates the request.
const { error } = validate(req.body);
if (error) return res.status(400).send(error.details[0].message);
let user = await User.findOne({email: req.body.email});
if (user) return res.status(400).send('User Already Register, try again!');
user = new User(_.pick(req.body, ['firstName','lastName','email','password','subscription']));
const salt = await bcrypt.genSaltSync(15);
user.password = await bcrypt.hash(user.password, salt);
//Here the user is being saved in the Database.
await user.save();
//const token = user.generateAuthToken();
//const token = jwt.sign({_id: user._id}, config.get('jwtPrivateKey'));
const token = user.generateAuthToken();
//We are sending the authentication in the header, and the infromation back to client
res.header('x-auth-token',token).send( _.pick(user, ['_id','firstName','lastName','email','subscription']));
});
Now my question's are:
How can I call the second code block from a , in one particular html file. When using Action="path to the users.js", the browser opens the js file code but doesn't do anything.
Do I need to rewrite the Post block part so that it would as well include the connection details to the DB? And would this mean I would keep open the connection to MongoDB once I insert Read etc.? Wouldn't this eat a lot of resources if multiple users would e.g. log in at the same time?
Or is there a way how I can use the index.js + the users.js which is refereed in the index.js file together?
All of these are theoretical questions, as I am not quite sure how to use the created API in html, then I created as walking through a tutorial.
Do I need to change the approach here?
After some longs hours I finally understood my own issue and question.
What I wanted to achieve is from an HTML page post data in MongoDB through API (this I assume is the best way how to describe this).
In order to do this I needed to:
Start server for the API function e.g. nodemon index.js, which has the information regarding the API.
Opened VS Code opened the terminal and started the API server (if I can call it like that)
Opened CMD and startet the local host for the index.html with navigating to it's folder and then writting http-server now I could access this on http://127.0.0.1:8080.
For the register.html in the form I needed to post:
This is the part which I didn't understood, but now it makes sense. Basically I start the server API seperatly and once it is started I can use e.g. Postmon and other apps which can access this link. I somehow thought html needs some more direct calls.
So After the localhost is started then the register.html will know where to post it via API.
Now I have a JOI validate issue, though on a different more simple case this worked, so I just need to fix the code there.
Thank You For reading through and Apologize if was not clear, still learning the terminology!
I'm using the following when trying to open a local file:
some document
When I click the above in a browser, it opens Finder to the folder. But does not open the file. Should I be doing something else to have the file open in Numbers?
You cannot open local files on the client. This would be a huge security risk.
You can link to files on your server (like you did) or you can ask the client for a file using <input type="file">
You can only open some types of files in browsers, like html css js and mp4, otherwise the browser will want to download it. Also remember that browsers replace spaces with %20. I recommend right clicking the file and opening it with chrome then copy that link and using it.
You can open files that are local as long as it is a file that is on the file that is trying to open another file is local.
Your issue is likely the space in the document name. Try this instead:
some document
The %20 will be read by your browser as a space.
Update
The other answer points out something I missed. The .numbers extension will not be able to be opened directly by your browser. Additionally the other answer describes the security risk this could create.
The File API in HTML 5 now allows you to work with local files directly from JS (after basic user interaction in selecting the file(s), for security).
From the Mozilla File API docs:
"The File interface provides information about files and allows JavaScript in a web page to access their content.
File objects are generally retrieved from a FileList object returned as a result of a user selecting files using the <input> element, from a drag and drop operation's DataTransfer object, or from the mozGetAsFile() API on an HTMLCanvasElement."
For more info and code examples, see the sample demo linked from the same article.
This might not be what you're trying to do, but someone out there may find it helpful:
If you want to share a link (by email for example) to a network file you can do so like this:
file:///Volumes/SomeNetworkFolder/Path/To/file.html
This however also requires that the recipient connects to the network folder in finder --- in menu bar,
Go > Connect to Server
enter server address (e.g. file.yourdomain.com - "SomeNetworkFolder" will be inside this directory) and click Connect. Now the link above should work.
Here is the alternative way to download local file by client side and server side effort:
<a onclick='fileClick(this)' href="file://C:/path/to/file/file.html"/>
js:
function fileClick(a) {
var linkTag = a.href;
var substring = "file:///";
if (linkTag.includes(substring)) {
var url = '/v/downloadLocalfile?path=' +
encodeURIComponent(linkTag);
fileOpen(url);
}
else {
window.open(linkTag, '_blank');
}
}
function fileOpen(url) {
$.ajax({
url: url,
complete: function (jqxhr, txt_status) {
console.log("Complete: [ " + txt_status + " ] " + jqxhr);
if (txt_status == 'success') {
window.open(url, '_self');
}
else {
alert("File not found[404]!");
}
// }
}
});
}
Server side[java]:
#GetMapping("/v/downloadLocalfile")
public void downloadLocalfile(#RequestParam String path, HttpServletResponse
response) throws IOException, JRException {
try {
String nPath = path.replace("file:///", "").trim();
File file = new File(nPath);
String fileName = file.getName();
response.setHeader("Content-Disposition", "attachment;filename=" +
fileName);
if (file.exists()) {
FileInputStream in = new FileInputStream(file);
response.setStatus(200);
OutputStream out = response.getOutputStream();
byte[] buffer = new byte[1024];
int numBytesRead;
while ((numBytesRead = in.read(buffer)) > 0) {
out.write(buffer, 0, numBytesRead);
}
// out.flush();
in.close();
out.close();
}
else {
response.setStatus(404);
}
} catch (Exception ex) {
logger.error(ex.getLocalizedMessage());
}
return;
}
You can expose your entire file system in your browser by using an http server.
caddy2 server
caddy file-server --listen :2022 --browse --root /
serves the root file system at http://localhost:2022/
python3 built-in server
python3 -m http.server
serves current dir on http://localhost:8000/
python2 built-in server
python3 -m SimpleHTTPServer
serves current dir on http://localhost:8000/
This s
I want to know how to add a local file path as a link and after adding it i want to download the file while clicking the link in asp.net.
My code:
<a href="D:/Sample/test.html" runat="server">
Here i just add my local path to the server.But here nothing done while clicking the link. I want to use .zip file instead of .html file.Let me know how to upload and download by using a link.Thanks in advance
I fail to see the problem here. Just add "~/" to find file from the root of your project and add runat="server" to the anchor link:
Download Zip File
You need to resolve it from the root because while you may know that it's on the D drive on your local machine, you cannot be sure that will be the same on the server. And even if it is on the same drive on the server, what if someone migrates it later on?
As for uploading a file, simply use the Upload control?
There are lots of situation, Using this code you can do it.
File Upload Code
string FilePath = "";
string[] a = new string[1];
string fileName = "";
string FullName = "";
if (FileUploader.FileName.Length > 0)
{
a = FileUploader.FileName.Split('.');
fileName = Convert.ToString(System.DateTime.Now.Ticks) + "." + a.GetValue(1).ToString();
FilePath = Server.MapPath(#"~\SavedFolder");
Fup1.SaveAs(FilePath + #"\" + fileName);
FullName = FilePath + #"\" + fileName;
// Database Saved Code
}
File Download Code
string filename = "filename from Database";
Response.ContentType = "application/octet-stream";
Response.AppendHeader("Content-Disposition", "attachment;filename=" + filename);
string aaa = Server.MapPath("~/SavedFolder/" + filename);
Response.TransmitFile(Server.MapPath("~/SavedFolder/" + filename));
Response.End();
I am completely new to node ExpressJS and am required to rewrite a rule for my server data source (jason format).
./
../public/
/public/css
/public/js
/public/index.html
../datasource/
/datasource/carmodel.json
The default static directories are set in:
app.use(express.static(__dirname + '/../public'));
The above work and everything runs under the 3000 port fine locally.
I need to rewrite the URL for my json file (datasource/carmodel.json) by replacing datasource with car/models/. However my application is unable to find the /datasource/carmodel.json file. I have attempted to recreate this via the following:
app.use('car/models/', require('./../datasource/'));
But I still cannot find the json source URL. It does not matter if I type: http://localhost:3000/car/models/carmodel.json or http://localhost:3000/datasource/carmodel.json for that matter. Is there something I am missing?
------------------
EDITED
------------------
Please see my project structure:
./
node_modules/
public/
css/
custom.css
js/
app.js (angular)
index.html
datasource/
carmodel.json
index.js (express file)
package.json
README
Currently my static folder is running of localhost:3000/. Contents of datasource/index.js:
var express = require('express');
var app = express();
app.use(express.static('public'));
//json
app.get('/car/models/:filename', function(req, res){
var filename = req.params.filename;
var fileDir = 'server/' + filename;
res.download(fileDir);
})
app.listen(3000, function(){
console.log('App started on port 3000!');
});
check something like this:
app.get('/car/models/:filename', function(req, res){
var filename = req.params.filename;
var fileDir = __dirname + '/datasource/' + filename;
res.download(fileDir);
})
then this http://localhost:3000/car/models/carmodel.json should work. I dont test it, youst write from head, therefore there may be some typos.
My solution is not safe. You shoud validate 'filename' before production use (all data from user must be validated).
I have previously successfully managed to upload a file using the webimage helper, but i am now trying to combine that with creating a directory, and failing miserably. here is my code:
if(IsPost){
//Create Directory using PropertyID
var imageroot = Server.MapPath("~/Images/Property/");
var foldername = rPropertyId.ToString();
var path = Path.Combine(imageroot, foldername);
if(!Directory.Exists(path)){
Directory.CreateDirectory(path);
}
photo = WebImage.GetImageFromRequest();
if(photo != null){
MediumFileName = rPropertyId + "_" + gooid + "_" + "Medium";
imagePath = path + MediumFileName;
photo.Save(#"~\" + imagePath);}
}
First, i create a directory with the name of the propertyID. This works fine. I then try and upload new photo's into that path, and i get an error saying that "The given path's format is not supported".
Any ideas?
You correctly use Path.Combine() when creating the directory path, you should do the same when making the image path.
imagePath = Path.Combine(path, MediumFileName);
Other than that, the error message suggests that perhaps it is the omission of a file extension that is causing issues? Perhaps use Path.GetFileName(photo.FileName) or similar and use that as the end of your constructed pathname.