• Post Reply Bookmark Topic Watch Topic
  • New Topic

Downloading (opening) a file in a browser  RSS feed

 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Howdy.

I have inherited a web application that has a sort of "sourcesafe" feature on it. For example, a person can upload a file (which is stored as a BLOB in an oracle 8i database) via a friendly web page...and can then at a later date come back in and "check out" the version, modify it, and add the new version back in. There is also an option to "Download" the file onto the user's local machine. This is where the problem comes in. When clicking on the Download button the user is currently given the option to either "Open" or "Save" the file. If "Save" is selected, the user is prompted to save the file to his local disk and everything is wonderful when it is opened up later. This works for .doc, .ppt, .html, .gifs, etc. However, if the user selects the "Open" selection, the file is supposed to open up right there without saving. This isn't working for ANY extensions or files.

Depending on what type of file the user is attempting to open, a different error message will ensue, but it basically comes down to the fact that the file can't be found. For example, downloading a .pdf gives this error:

"There was an error opening the file. The file cannot be found."

Here's a snippet of the code that is actually doing the work in the Action class. I can offer more code if necessary.

BufferedOutputStream out = null;

try
{
out = new BufferedOutputStream(response.getOutputStream());
response.setContentType(fileBean.getContentType());
response.setHeader ("Content-Disposition", "attachment; filename=\"" + fileBean.getName() + "\"");
out.write(fileBean.getData());
out.flush();
}
finally
{
if (out != null)
{
out.close();
}
}

How come the save works and not the open? I have a feeling I'm missing something simple here...

Thanks for your help!
bryan
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
No dice, huh? Should I post this in a different forum?
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The error message may be a red herring. Have a look at the headers with an HTTP spying application, and see what you're getting for Content-Type headers. Make sure they make sense.

Otherwise, does the test machine correctly open .doc/.ppt/whatever files launched from some other source on the web? It could simply be misconfiguration there.
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Content type was my guess, too. What is fileBean? How does it determine content type? I wrote my own little web server and downloaded a list of about 400 extensions and mime types that makes files open correctly ... so far.
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Excellent ideas. Here's what I've come up with so far.

I've taken a look at the contentType that is stored in the response object. It is being set from the FileBean and is being set correctly for the different types i've tested.

.pdf = application/pdf
.gif = image/gif
.txt = plain/txt
.htm = txt/html
etc...

So that part is actually being set correctly. A FileBean has the following fields:

public class FileBean
extends BaseSecureBean
{
/**
* The id value of the folder containing this file.
*/
protected Integer folderId;


/**
* The physical name of the uploaded file.
*/
protected String name;


/**
* The content type of the uploaded file.
*/
protected String contentType;


/**
* The "title" of this file. Entered by the user as a brief label of what
* the file is. Note that this differs from the actual physical file name.
*/
protected String title;


/**
* A description of what this file is.
*/
protected String description;


/**
* A description of what this file is.
*/
protected byte data[];


/**
* Specifies whether or not the file is checked out.
*/
protected Boolean checkedOut;


/**
* If the file is checked out, this is the date it occured.
*/
protected Calendar checkoutDate;


/**
* The userId of the user who last checked out this file.
*/
protected Integer checkoutUserId;


/**
* Specifies whether or not this file has been deleted.
*/
protected Boolean deleted;


/**
* The user id of the last user to update this file.
*/
protected Integer userId;


/**
* The version number of this file.
*/
protected Integer version;


/**
* Specifies date when this file was last updated.
*/
protected Calendar lastModified;


/**
* The last name of the user who last modified this file.
*/
protected String lastModifiedByLastName;


/**
* The first name of the user who last modified this file.
*/
protected String lastModifiedByFirstName;


/**
* A boolean value specifying whether or not the user is attempting to
* check in a new version of the file.
*/
protected boolean checkInFile;

/**
* The file size.
*/
protected long size;


All of these fields have appropiate getters and setters as well, but all of that is working appropiately.

Any more ideas? I really do appreciate it!

Thanks,
b
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Also...a FileBean is populated with the contentType from a call to the database. The content type of a file is stored in the db when the file is uploaded (saved).
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ah, that's interesting! What kind of content type values do you get? Here are few samples from my mapping:

I found almost 400 extension-type mappings by googling for "mime type". All of them that I've tried seem to work ok.
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, I get those exactly...plus here are some more:

.gif = image/gif
.txt = plain/txt
.htm = txt/html

I just don't have a clue why they will "save" but not "open"?
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You didn't answer my questions: Are you sure that the browser is receiving those content types, or are you just assuming that since you're setting them, they're getting there? And second, can the test machine properly handle opening similar documents from other web sites?
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ah yes.

The second item is definitely ok. I can open up all of those extensions just fine from another source using this same machine. I've actually done that today already.

Now for the first one, I downloaded some HTTP Spy software called IP Interceptor. I've had succes in running it, but I'm not entirely sure what I'm looking for? I'm guessing I'm simply looking for the presence of the content-type appearing in the response?
 
Ernest Friedman-Hill
author and iconoclast
Sheriff
Posts: 24217
38
Chrome Eclipse IDE Mac OS X
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by bryan nelson:
I'm guessing I'm simply looking for the presence of the content-type appearing in the response?


Yes, along with anything untoward you might find.
 
Joe Ess
Bartender
Posts: 9439
12
Linux Mac OS X Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My understanding is that this line:

is a hack to force a browser to prompt the user to save a file. "attachment" is not a recoginzed MIME Type by the IANA. The browser can't match that with an application so it throws in the towel and prompts the user. I'd think that for the browser to open an application for a document, you'd need to set the content disposition a valid MIME type.
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I believe what's going on with that line of code can be summed up the best here: Content-Disposition

However, I didn't actually write that code myself...so I'm a bit confused as to if it is actually being implemented correctly. I do think that that particular line is correct, but I'm not sure if I need to do something else afterwards?

Now, as far as searching through the response for the correct content-type...I can't find it with the HTTP Spy software, but I also can't find much else with it either. I am certain, however, that the response object is being set with the correct content-type because of stepping through it with the debugger in Eclipse that actually shows that object being populated.
 
Joe Ess
Bartender
Posts: 9439
12
Linux Mac OS X Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Originally posted by bryan nelson:
I believe what's going on with that line of code can be summed up the best here: Content-Disposition


Yea, that's exactly what I'm talking about (quoted from your link):

First, set the Content-Type header to a nonstandard value such as application/x-download. It's very important that this header is something unrecognized by browsers because browsers often try to do something special when they recognize the content type.


If the browser doesn't recognize the file type, it can't delegate that type to an application. I'm thinking you need two links, one to save the file, another to open the file. The link to open the file would set the MIME type to something that would be recognized (i.e. application/pdf for a PDF file).
 
bryan nelson
Ranch Hand
Posts: 95
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello again,

I totally agree with you here:


quote:
First, set the Content-Type header to a nonstandard value such as application/x-download. It's very important that this header is something unrecognized by browsers because browsers often try to do something special when they recognize the content type.


If the browser doesn't recognize the file type, it can't delegate that type to an application.


However, I'm already doing this in the line of code above. See my original code:



Line 2 above is setting the content type in the header. Apparently it's so common to do that, that they've made a specific method to do it. See
Content-Type What is the MIME type of the following document? Default for servlets is text/plain, but they usually explicitly specify text/html. Setting this header is so common that there is a special method in HttpServletResponse for it: setContentType.
from Servlet Tutorial

I have indeed verified that this is being set correctly by changing the disposition type from "attachment" to "inline". This modifies line 3 above to look like this:



If I do this the browser immediately tries to open the file for certain types of extensions in the browser (ex. htm, txt) which works fine. So I know that the content-type is getting set correctly. Having this as inline even gives me the desired behaviour for something like a word document: It prompts me to either "open" or "save" the file and both work!

So now, I just need to figure out how to merge the two behaviours. Meaning that I want the behaviour of the "inline" on all files (it just opens up htm and txt docs without the prompt), but the behaviour of the "attachment" in so much as it ALWAYS prompts the user to "open" or "save".

A fine description of these two types can be found here: attachment vs. inline

Any ideas on merging these two behaviours?

Thanks!
b
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!