Catching errors on ColdFusion 9 forced download page - exception

I'm creating an application for our office that allows authenticated users in the office to upload files for clients, creates a list of links to download the files and emails the client with the list of links.
When a user in the office logs in they're assigned a UUID in their session scope. That UUID becomes the directory name that the uploaded files are stored in.
Occasionally I'll need to clear out old files and delete the directories, but when that happens there's a chance a client may try to re-download a file from an old link.
In ColdFusion 9 how would I catch this and send them to an error page? I'm also hoping to use similar code to redirect a user once the download starts so they're not just sitting on a blank page during the download process.
Here's my force download page that takes a folder name variable and a filename variable to serve up the files.
<cfset folder = #URL.folder#>
<cfset FileDownload = #URL.file#>
<cfset exten = ListLast(FileDownload, ".")>
<cfswitch expression="#exten#">
<cfcase value="zip"><cfset content_type = "application/zip, application/x-zip, application/x-zip-compressed, application/octet-stream, application/x-compress, application/x-compressed, multipart/x-zip"></cfcase>
<cfcase value="ai"><cfset content_type = "application/illustrator"></cfcase>
<cfcase value="eps"><cfset content_type = "application/illustrator, application/octect-stream"></cfcase>
<cfcase value="pdf"><cfset content_type = "application/pdf, application/x-pdf, application/acrobat, applications/vnd.pdf, text/pdf, text/x-pdf"></cfcase>
<cfcase value="psd"><cfset content_type = "image/photoshop, image/x-photoshop, image/psd, application/photoshop"></cfcase>
<cfcase value="jpg"><cfset content_type = "image/jpeg"></cfcase>
<cfcase value="png"><cfset content_type = "image/png"></cfcase>
<cfcase value="tif"><cfset content_type = "image/tiff"></cfcase>
<cfdefaultcase><cfset content_type = "image/jpeg"></cfdefaultcase>
</cfswitch>
<cfset fileToGetSizeOf = expandPath("./#folder#/#FileDownload#") />
<cfoutput><cfheader name="content-disposition" value="attachment;filename=#FileDownload#"><cfheader name="content-length" value="#getFileInfo(fileToGetSizeOf ).size#" />
<cfcontent type="#content_type#" file="#ExpandPath("./#folder#")#/#FileDownload#" deletefile="#delete_file#"></cfoutput>

There are three goals you want to achieve here:
Serve the files securely. Currently you are not protected from exploiting the system (or other user) files, for example like this (I've set passed values instead of URL keys):
<cfset folder = "../../../some/other/path/" />
<cfset FileDownload = "some_other_file.pdf" />
Show 404 page if file or directory does not exist any more.
Show some nice page once download starts. Maybe I am missing something, but redirecting user after download started (=headers are sent) is pretty tricky.
Any way, there's pretty simple and reliable solution to all of these.
You should keep the list of the files in database, so each record may include:
Unique ID.
File owner ID.
Directory name.
File name.
Description (optional, you can use filename).
Content type (optional, you still can use approach with extension).
Created date (optional, can be used for scheduled cleaning).
Downloads counter (optional, if you want to limit downloads count).
Status (optional, can be used to prevent filesystem checks for deleted files).
Note: 3-4 may be done as single column ('path/filename.ext') since paths are temporary any way.
So, when your application creates a list of links to download the files and emails the client with the list of links., it also records each file to the database. Each of these links now may look like this:
#DESCRIPTION#
When user clicks the link script performs following:
Check if ID exists in DB. If not -- redirect to 404 page.
Check if current user matches the owner ID. If not -- redirect to 404 page.
Check file status, downloads counter (if needs to be limited). If not -- redirect to 404 page.
Check actual file existence using stored directory and filename. If not -- redirect to 404 page.
IF there's a start key in URL: increment the downloads counter, serve the file using cfcontent and content type.
ELSE render the HTML of the page saying "Download will start momentarily, click this link if you don't want to wait" where link looks like download.cfm?file=#ID#&start=yes, plus you have meta http-equiv="refresh" with same URL.
Notes:
Steps 1-4 may be wrapped in single try/catch block with custom errorCode, so you can have one place of redirect.
Trick with step 5 here is that user will stay on the page when clicks the Download link, and wont see blank page. This is not exact solution for goal #3, but it would be hard to make something better without some trickery. Maybe I am wrong and someone could suggest better way here, it'd be cool. You can remove the "Click this link part" to make this page look "natural".

If your site has a 404 page, you are already directing them to an error page. Or at least your web server is. If you don't have a site wide 404 page set up, make it a cfm page to give you some extra functionality (logging, alerting, etc)

You can use FileExists to check for the existence and make the decision based on that:
<cfif NOT FileExists(fileToGetSizeOf)>
<!--- send a 404 --->
<cfelse>
<!--- send the file --->
</cfif>

You can use FileExists(absolute_path) function to check for the existence of the downloaded file.

Related

Mediawiki dumpBackup parameters

I fail to understand some options in the dumpBackup.php maintenance script of Mediawiki.
What is the effect of --include-files? In my test wiki, dumpBackup.php --current --include-files and dumpBackup.php --current both contain the pages of the File: namespace and I see no difference.
What is the effect of --uploads? In my test wiki I see that the xml file contains a tiny bit more of xml but, to me, it looks like this is all information which is there already as part of the File: page. What is the use of this flag?
When I add both --include-files and --uploads I get the next surprise. I actually expected the combined effect of both options, but what I get is the file content of the uploaded files and the upload record. Why did I not get the file contents when I used --include-files alone?
When I use only --include-files and --uploads but no --current I would have expected to get the content of the uploaded files and the upload record (and none of the other pages). However ,I get the warning no valid action specified and no further information at all
I am completely confused since I do not understand the logic behind all of this.

Jmeter - testing multiple urls in one Transaction controller and top 9 page's in another one

First I have a transaction controller with the top 9 pages inside. That is working well.
But the transaction controller with browse a random page doesn't work. I tried already different things but it keeps saying 100% error.
Can someone help?
This is my setup:
This is how i did setup the CSV data setup
And this is what is in Browse random bouwdomein
FYI in User Defined Variables is stated: BASE_URL_1 under Name
And in Value the URL (for example as www.google.com)
Hope someone can help me to get it working.
Your "different things" and "100% error" unfortunately don't tell anything to us, in order to be able to help we need to see:
At least first 2 lines of your content.csv file
View Results Tree listener showing request and response details
jmeter.log file (preferably with debug level logging enabled)
Given your content.csv file:
exists in the given relative path
has valid IP addresses and/or DNS hostnames of your "top 9 pages" your configuration should work normally

Why does my file download link seem to work, but is unable to find the file?

I added this HTML to a page that I render via a REST call:
StringBuilder builder = new StringBuilder();
. . .
builder.Append("<p></p>");
builder.Append("<a href=\"/App_Data/MinimalSpreadsheetLight.xlsx\" download>");
builder.Append("<p></p>");
. . .
return builder.ToString();
My ASP.NET Web API project has a folder named "App_Data" which does contain a file named "MinimalSpreadsheetLight.xlsx"
The download link is indeed rendered on the page, and clicking it does appear, at first, to download the file (it has the Excel icon, and it bears the file name), but beneath that it says "Failed - No file":
Is the problem with my HTML, or the path I'm using, or file permissions, or what?
I've only tested this with Chrome, so far, BTW. IOW, it's not an IE issue.
UPDATE
I tried it with a leading squiggly, too:
builder.Append("<a href=\"~/App_Data/MinimalSpreadsheetLight.xlsx\" download=\"Spreadsheet file\">");
...yet, alas, to no avail.
UPDATE 2
I changed the pertinent line of HTML to this:
builder.Append("<a href=\"App_Data/MinimalSpreadsheetLight.xlsx\" download=\"Minimal Spreadsheet file\">");
...and it displays in the source like so (with some context):
<p>(Invoice Count excludes credits and re-delivery invoices)</p><p></p><p></p><a href="App_Data/MinimalSpreadsheetLight.xlsx" download="Minimal Spreadsheet file">
...but the link does not appear at all.
UPDATE 3
I was misled by this reference, which showed no text being added; I changed the code to this:
builder.Append("Spreadsheet file");
...(adding "Spreadsheet file" and closing out the anchor tag), and now the link appears; however, I still get the "Failed - No file" msg, and 2-clicking the "downloaded file" does nothing.
UPDATE 4
I tried two other permutations of what's seen in Update 3, namely with the forward whack reintroduced prior to "App_Data":
builder.Append("Spreadsheet file");
...and with both the squiggly prepended and the forward whack:
builder.Append("Spreadsheet file");
...but the results are the same in any of these permutations ("Failed - no file").
UPDATE 5
I also tried it without the "App_Data" at all, on the off change that is not needed:
builder.Append("Spreadsheet file");
...but the same "Failed - No file" is the result of that attempt, too.
UPDATE 6
Okay, so I tried this, too (single quotes):
builder.Append("<a href='/App_Data/MinimalSpreadsheetLight.xlsx' download='Minimal Spreadsheet file'>Spreadsheet file</a>");
...but no change. The file is there:
...so why is it not seen or accessible?
UPDATE 7
This:
string fullPath = HttpContext.Server.MapPath("~/App_Data/MinimalSpreadsheetLight.xlsx");
... (which I got from here) fails to compile with, "An object reference is required for the non-static field, method, or property 'System.Web.HttpContext.Server.get'
2-clicking the err msg highlights just "Server"
UPDATE 8
This (which I got from the same place as what I tried in Update 7):
string justDataDir = AppDomain.CurrentDomain.GetData("DataDirectory").ToString();
string url2 = string.Format("Spreadsheet file</button>", justDataDir);
builder.Append(url2);
...does nothing; clicking the link doesn't even give me a fake/failed download now...
justDataDir is:
C:\Projects\ProActWebReports\ProActWebReports\App_Data
url2 is:
Spreadsheet file</button>
UPDATE 9
I noticed on further fine-tooth-combing that url2 had a forward whack in it; I changed it so that all the whacks were back, but it made no difference to Update 8's results: clicking the link does nothing whatsoever.
If somebody solves this, it will definitely get bountified after the fact.
UPDATE 10
Maybe what I really need to do is, instead of the simple html, add some jQuery that will download the file. But the question is, can jQuery access the App_Data folder any better than raw/simple html can?
The app_data folder is used by iis and asp.net as a private area in which to put database files which can only be accessed by code running on the server.
If you try to access the folder directly via your browser you will get a permissions error.
In order to make the files available for download, move them the a folder under 'Content' (if you have an mvc site) and ensure that your web.config allows the .xlsx exention to be downloaded.
It may depend on what version of iis you are using.
Downloading Docx from IE - Setting MIME Types in IIS

Google Drive watching for new files

I'm considering using Google Drive push notification in order to replace our currently pulling process.
I started playing with it, but I have 2 major problems:
Watching changes:
When watching for drive changes, I get notification with the new change id. But when I try to query it using: driveService.changes().get(changeId), I intermittently get 404. Am I doing something wrong here?
Watching files:
When watching for file changes, in case of a folder, I want to know about new files added to that folder, so I expected that when adding/removing files from this folder, the "x-goog-resource-state" will hold "add/remove" value while "x-goog-changed" will contain "children".
In reality, the "x-goog-changed" does contain "children", but the "x-goog-resource-state" is always "update", and there is no extra information about the added/deleted file.
Regarding deleted files, I know can get it by watching the file once I have it, but is there a way I can get updated about new files in a certain folder?
I was working on a similar project a few months ago. There are two things you can do to monitor changes on Google Drive :
Set Notification Push using : changes().watch()
Set Notification Push using : files().watch()
The 1st case sends you a request for everything that happens on the Drive you are monitoring, with very little information on what exactly has changed.
The 2nd case is less 'spamming', and you get to decide which folder to monitor.
However the tags on the change type are not accurate. when I was using files().watch() I tested all the use-cases, and I compared the headers of each case.
My conclusions are:
for a new file (or folder) creation inside yourfolder (yourfolder/newfile) the headers contain:
'X-Goog-Changed': 'properties'
'X-Goog-Resource-State': 'update'
which is the same when you move a file to yourfolder, or when you start following an existing file in your folder.
you get 'X-Goog-Resource-State': 'add' when you share with a user
as you can see, the header tags are not accurate/unique.
Also, note that the push-notification channel will not send you requests for files inside a folder inside yourfolder (yourfolder/folder/files). And the channel will expire at some point.
If you still have any questions, or want to know how to implement the code, let me know : )

Rendering PDF without going back to server (wicked_pdf)

I am using wicked_pdf to render PDF. The app renders a table in HTML. This table is dynamic, in the sense that, the data in it changes every 30 seconds. When the user clicks on the "Download as PDF" link, the request goes back to the server and the HTML (slightly modified for PDF) is rendered.
But the issue is that since the request is back to the server, the data would have changed. This results in the PDF table showing values differing from the HTML table. The client doesn't want this.
Basically, they want a snapshot of the static table in PDF form, not the dynamic table. How can I do this using wicked_pdf?
Thanks,
Sridhar
Common Rails way here is to use timestamps.
You should pass your actual time to your controller, so it will fetch only supposed items, like.
# views
= link_to "pdf", orders_path(updated_at: DateTime.now, format: :pdf)
# controller
orders = Order.where(updated_at >= params[:updated_at])