Closed Thread Icon

Preserved Topic: Server-Side File Serving Pages that link to <a href="https://ozoneasylum.com/backlink?for=20911" title="Pages that link to Preserved Topic: Server-Side File Serving" rel="nofollow" >Preserved Topic: Server-Side File Serving\

 
Author Thread
kevincar
Paranoid (IV) Inmate

From: north hills, ca usa
Insane since: Apr 2001

posted posted 05-15-2001 17:33

Hi Everyone,

I have a web server related question; Is it possible to serve a PDF file outside of the "realm" of the web server?

Specifically, I have a bunch of "secured" Adobe PDF files, and my Java servlet (actually a JSP page) determines which one the logged-in person is supposed to be able to look at. The trick is, I don't want people "surfing" via the URL address line for other files.

The best I can do right now is to "hide" the physical file URL on the browser. Something I tried (but it didn't work) was to code the servlet/JSP page to write HTTP header MIME info of "application/PDF" content in the HTTP header, and then write the PDF file to the browser - all it did was just dump the bytes to the browser.

I was thinking that the absolute best solution would be to have these "sensitive" files outside of the realm of the web server, so people could basically NEVER "surf" for them, and just let the JSP page dump the PDF file bytecodes to the browser, where the PDF "helper" app would then be run, according to the MIME type of the data - but alas, it didn't work

Anyone have an idea?


linear
Paranoid (IV) Inmate

From: other places
Insane since: Mar 2001

posted posted 05-15-2001 17:39

You got the right solution, sounds like you had implementation probs.

HTTP headers have to be followed by two newlines, that's the biggest mistake people make.

In PHP, I've done it exactly like you describe, here's the code:
<?php
$fp = fopen($filename, "r");
header("Content-type: application/pdf");
fpassthru($fp);
fclose($fp);
?>

Since I'm using the header() function, I'm free from having to remember that newline business. If you return headers your self, you're not.

WarMage
Maniac (V) Mad Scientist

From: Rochester, New York, USA
Insane since: May 2000

posted posted 05-15-2001 18:27

Using java... hmmm... This is an interesting problem...

Since the file is outside the relm of the web server you would have to do a bit of a work around.

The JSP displays the content of the remote file, with array values as the argument in the link, and the path to the file stored in the array. They click a link, the JSP grabs the file, though a file reader. Then places the content into a temp file (using their IP as a name), so for example 127-0-0-0.pdf, which would be in a browsable directory, and the link is then set to direct to that file. On at the end of the servlet run destroy all temp files, or the person's session, destroy the person's temp file.

This is one idea, I don't think it would be the best way to do it. I think another way would be a temp file move, or maybe you could even have the JSP set up to send the file to the user from the remote directory. I am not sure how the remote send would work, but the move would be easy, but still unsecure.

If you get a remote send to work, where the user clicks and JSP sends them the file from the directory which is not on the web server, then please tell me how you managed it!

The other problem you may have to worry about is that you have to give JSP semi-root privilages in order to achomplish all of this, which means a server breach, is a breach of the entire computer.

kevincar
Paranoid (IV) Inmate

From: north hills, ca usa
Insane since: Apr 2001

posted posted 05-15-2001 20:56

Linear,

>In PHP, I've done it exactly like you describe, here's the code:
><?php
>$fp = fopen($filename, "r");
>header("Content-type: application/pdf");
>fpassthru($fp);
>fclose($fp);
>?>

I have seen similar code while researching this problem at google and altavista -

Looking at PHP docs, fpassthru looks like a simple file dump util - a snippet of my
JSP code looks like this:

code:
String sFileName = "c:\\temp\\Secret.pdf";
File fReportDir = new File(sFileName);
response.setHeader("Content-Type", "application/pdf");

try {
FileInputStream fis = new FileInputStream(fReportDir);
int bytin = 0;
while((bytin=fis.read()) != -1) {
out.print( (char) bytin);
}
fis.close();
}
catch(Exception ioe) {
// err code here
}



but thePDF file bytes just come back to the browser as byte data -
... Is it possible my servlet output code (the out.print line) is
"mangling" the PDF byte-stream? ie, byte-swapping, or some similar
nonsense?

Thanks for any help




WarMage
Maniac (V) Mad Scientist

From: Rochester, New York, USA
Insane since: May 2000

posted posted 05-15-2001 21:07

Mind putting the page up?

That way we could see the results your getting and attempt to remedy it.

I was alluding to that problem when I said use the copy or the move, I think it has to do with the way the information gets interperated...

If I can see output and the PDF I think I could get the problem resolved.

linear
Paranoid (IV) Inmate

From: other places
Insane since: Mar 2001

posted posted 05-15-2001 21:55

You should see something in the first few bytes of the PDF that looks like this:

%PDF-1.2
%âãÏÓ

4 0 obj
<<
/Type /Page
/Parent 5 0 R
/Resources <<
/ProcSet 2 0 R
>>
>>
endobj
2 0 obj
[ /PDF ]
endobj
5 0 obj

If it doesn't have that header, it ain't a PDF.

kevincar
Paranoid (IV) Inmate

From: north hills, ca usa
Insane since: Apr 2001

posted posted 05-15-2001 22:23

Yup, that's exactly what I see:


%PDF-1.2
%âãÏÓ
6 0 obj
<<
/Linearized 1
/O 8
/H [ 677 170 ]
/L 6800
/E 5643
/N 2
/T 6563
>>
endobj
xref
6 14
0000000016 00000 n
0000000624 00000 n
0000000847 00000 n

....

Basically, if I drag the file to the browser it looks fine. It's only when I display the file through HTTP that it doesn't get interpreted right.




linear
Paranoid (IV) Inmate

From: other places
Insane since: Mar 2001

posted posted 05-15-2001 23:27

OK, I gotta echo WarMage here and say let us look at it. Sounds to me like your Acrobat plugin ain't workin.

I seem to remember that PDFs were insensitive to CR/LF mangling, but that may be an issue too. Is your server Windoze?



[This message has been edited by linear (edited 05-15-2001).]

WarMage
Maniac (V) Mad Scientist

From: Rochester, New York, USA
Insane since: May 2000

posted posted 05-16-2001 05:01

I always found winblows to be cute too

kevincar
Paranoid (IV) Inmate

From: north hills, ca usa
Insane since: Apr 2001

posted posted 05-16-2001 17:23

Well, here's what I know:

1. the PDF is good. It displays just fine when double-clicking the thing.

2. If I do a straight "<jsp:forward page="<%=\"secret.pdf\"%>" />"
it works fine - therefore corroborating the PDF being good.

3. The output loop is probably the issue. I changed the content type to
"application/download", and downloaded it, and the downloaded file
would NOT display - Adobe balked saying the file was bad.


I therefore deduce that out.print() is NOT doing what I want -
I tried out.write() and igt produced the same result - but I haven't done a
byte-code check yet...



linear
Paranoid (IV) Inmate

From: other places
Insane since: Mar 2001

posted posted 05-16-2001 17:43

sounds like CR/LF. hex dump the different versions of the file.

kevincar
Paranoid (IV) Inmate

From: north hills, ca usa
Insane since: Apr 2001

posted posted 05-16-2001 18:37

I Figured it out!!!

It was a combination of many things (as usual) - the definitive code that works is as follows;


code:
ServletOutputStream st = response.getOutputStream();
String sAgentFileName = "c:\\temp\\secret.pdf";

File fReportDir = new File(sAgentFileName);
if(fReportDir.exists()) {
response.setContentType ("application/pdf");
response.setHeader("Content-disposition", "inline;filename=\"xxx.pdf\"");
response.setContentLength((int) fReportDir.length());
try {
FileInputStream fis = new FileInputStream(fReportDir);
int intin = 0;
int tmpInt = 0;
DataInputStream dStream = new DataInputStream(fis);

byte tmpByte = 0;
char tmpChar = 0;
byte [] b = new byte[4097];
int counter = 0;
while((counter = dStream.read(b, 0, 4096)) != -1) {
st.write(b, 0, counter);
st.flush();
}
if ( dStream != null ) dStream.close();
}
catch(Exception ioe) {
// err code
}



Basically, the flush() call is crucial - you gotta flush or a browser err occurrs.
Also, you HAVE to ship out bytes to the browser - not chars - which are
(I think i'm explaining this right) chars are Unicode, and bytes are UTF-8.

[ALSO:] I couldn't get the "out" outputstream to work - I had to use
the ServletOutputStream.


Thanks for listening - I hope we all learned something :-)
Whew maybe I'll get paid this week....



[This message has been edited by kevincar (edited 05-16-2001).]

WarMage
Maniac (V) Mad Scientist

From: Rochester, New York, USA
Insane since: May 2000

posted posted 05-17-2001 02:40

Yes I believe we all did, thanks for posting the code. I would have thought that flush would have been automatic in the output stream... guess not, we all learn something new, and yes you are correct about the encoding. That would make a difference.

GW, GL


« BackwardsOnwards »

Show Forum Drop Down Menu