2

Rather than using a link like the following in a html page:

<a href="http://www.somesite.com/path/to/file.pdf">Display file</a>

I would like to obfuscate the path to the file from the remote user. So I wrote a Perl CGI script to do so, a simplified version is shown here:

#!/usr/bin/perl -T

use strict;
use warnings;
use CGI qw/:all/;

my $basepath = '/some/path/to';
my $f = param("f") || '';

($f eq '') && die;

my $path = "$basepath/$f.pdf";

open(PATH, "<$path") || die;
binmode PATH;

print header(-type => "application/pdf",
             -target => "$f");
print;

while (<PATH>) {
    print($_);
}
close(PATH);

I save this script as $htdoc/cgi-bin/getpdf.cgi, then use the following URL in the html file instead:

<a href="http://www.somesite.com/cgi-bin/getpdf.cgi?f=file">Display file</a>

This script works, but the file name shown to the user is the name of the script (getpdf.cgi), not the name of the file being served (file.pdf). This is not very good because no matter what file is being served, the file name is getpdf.cgi. I would like it to be the actual file name (which is passed as the f= param in the URL, with the .pdf extension appended).

I tried using the following header() instead of what's in the script above:

print header(-type => "application/pdf",
             -target => "$f",
             -attachment => "$f.pdf");

Note the added -attachment line. This does override the file name to file.pdf, but it causes the browser to open a "Save as" dialog window rather than just displaying the file.

How to solve this problem?


UPDATE: TUrns out I needed to have the following in my header:

Content-Type: application/pdf
Content-Disposition: inline; filename="$f.pdf"

The first header line is easily generated with CGI.pm's header() method:

print header(-type => 'application/pdf');

But CGI.pm does not give me a way to generate the second line, at least not the version that's on the server. If I use the following code:

print header(-type => 'application/pdf', -attachment => "$f.pdf");

Then the generated header looks like this:

Content-Type: application/pdf
Content-Disposition: attachment; filename="$f.pdf"

Having "attachment" causes the browser to pop up a "Save as" dialog box which I don't want to be the default behavior. I want "inline", but header() has no parameter for it.

I also found that I cannot use multiple header() calls, that seems to cause everything after the first one to be ignored.

So the solution is not to use header() at all, but just explicitly call print() to output the needed header lines, plus one blank line to signify end-of-header.

I tested this on Chrome, Firefox and IE. They work as intended in displaying the PDF file. If I then try to download it, the correct file name is provided as default on Chrome and Firefox. On IE it still shows the default file name as getpdf.cgi.

At this point I think I'll just chalk it up to be yet another IE "bug" and leave it at that.

amblabs
  • 121
  • 2
  • 1
    seems like CGI day today.. – Gerhard Nov 21 '17 at 09:44
  • 1
    @GerhardBarnard I should create a bookmarklet for that lightning talk to insert a comment directly. – simbabque Nov 21 '17 at 09:49
  • 1
    @simbabque sounds like a plan to me. – Gerhard Nov 21 '17 at 09:50
  • @GerhardBarnard have you watched it? Sawyer says something about drinking to much lemonade that _that_ guy gave to him. That's Club Mate, a high caffeine drink from Germany. And that guy is me. :) – simbabque Nov 21 '17 at 09:51
  • 2
    Please feel free to post this code on [codereview.se]. You're using a lot of very unperlish syntax, and I'd like to give you some feedback. – simbabque Nov 21 '17 at 09:52
  • Ahh. yes I did, I never even thought that it is you. That is great! I saw you linked the video it in the previous CGI question as well. – Gerhard Nov 21 '17 at 09:52
  • Is this marked as duplicate to: https://stackoverflow.com/questions/6293893/how-to-force-files-to-open-in-browser-instead-of-download-pdf – amblabs Nov 21 '17 at 10:44
  • If so, I just tried to add print header("Content-Disposition: inline; filename=\"$f.pdf\"); but it still shows the file name as getpdf.cgi. – amblabs Nov 21 '17 at 10:45
  • @simbabque I posted the code on Code Review as you suggested: https://codereview.stackexchange.com/questions/180951/un-perl-ish-syntax – amblabs Nov 21 '17 at 11:04
  • @GerhardBarnard I'm the guy off-screen moderating the lightning talks in that conference. I ... urged Sawyer to give the talk. It was originally a 10 minute talk, which he did not actually change. All the caffeine helped to get it into a generous 6 minutes. – simbabque Nov 21 '17 at 11:11
  • @simbabque I think the start off the video proves the caffeine :) it is very intriguing though, the video should get more views. – Gerhard Nov 21 '17 at 11:29
  • Does your solution apply to the marked duplicate? That would be a better place to post it than to your question. – Teepeemm Nov 22 '17 at 02:57
  • Use a raw header: `header(-type => "application/pdf", -target => $file, '-Content-Disposition' => "inline; filename=\"$file\"")` – ceving Apr 16 '19 at 13:39

0 Answers0