File upload in servlet corrupts the file - servlets

I am uploading a file using using (Valums uploader) and I using servlet at server side. File type is application/pdf. Code is :
String filename= request.getHeader("X-File-Name");
InputStream is = request.getInputStream();
File tmp = File.createTempFile(filename, "");
tmp.deleteOnExit();
FileOutputStream fos = new FileOutputStream(tmp);
IOUtils.copy(is, fos);
byte[] bytes = new byte[(int) tmp.length()];
is.read(bytes);
Now these bytes are getting stored into database as longblob. But it seems that inputStream in above code is adding some more data in the file thats why file data is getting corrupted. I download the same data as pdf file, found that both- original uploaded file and now downloaded file have the same size, but when the downloaded file is opened in Acrobat, it reports "File is corrupted". For upload request I have used only file input. So there are no chances of other input params in inputStream. Also the bytes array in above code are as it is passed for download. Why is data getting corrupted?

Your problem might be the data length you are reading. I had similar problem and posted on this issue link
Java: Binary File Upload using Restlet + Apache Commons FileUpload
Hope this helps

Related

Upload dynamically created XML file using SFTP guidance

Currently I am generating an xml file for download using posted fields with the following code:
string attachment = "attachment; filename=" + FileName + ".xml";
Response.ClearContent();
Response.ContentType = "application/xml";
Response.AddHeader("content-disposition", attachment);
Response.Write(Session["FileForDownload"]);
Response.End();
This is working fine.
However I want to sftp upload the generated file to a specified directory on a server.
I have had success in connecting using ssh.net and have been able to create a new directory etc.
My question is how can I generate the file and then sftp it using ssh.net?
I've tried using a file stream with no success. I'm guessing the file needs to be temporarily stored and then retrieved for upload.
This is my current code segment for the specified problem:
SftpClient sftp = new SftpClient("host", "user", "pwd");
sftp.Connect();
sftp.ChangeDirectory("directory/");
Stream fs = File.OpenRead(Server.MapPath(#"filetobeuploaded"));
sftp.UploadFile(fs, Session["FileName"].ToString());
sftp.Disconnect();
I recognize that there won't be a file already on the server to upload.
Any help would be much appreciated as this is the final piece of the puzzle in my application.
Cheers
Fixed: I found a solution by generating a temp XML file in the server, uploading and deleting it. Thanks for your reply anyway

where do on-fly-generated-images with a servlet store?

if I'm generating images using servlets/actions something like this:
byte[] imageBytes = getImageAsBytes();
response.setContentType("image/jpeg");
response.setContentLength(imageBytes.length);
response.getOutputStream().write(imageBytes);
when user access the servlet, where are those images storing? will it download to user temp folder and load it o it's saving user HTTP_SESSION?
domain.com/image/randomImageServlet?param1=a&param2=b
It isn't stored anywhere except, maybe, in the cache of the browser. Why would you want it to be stored anywhere. You load the bytes in memory, and stream them to the response output stream. They're just downloaded on the wire exactly like your generated HTML is.

Split zip file using DotNetZip Library

I'm using DotNetZip Library to create a zip file with about 100MB.I'm saving the zip file directly to the Response.OutputStream
Response.Clear();
// no buffering - allows large zip files to download as they are zipped
Response.BufferOutput = false;
String ReadmeText= "Dynamic content for a readme file...\n" +
DateTime.Now.ToString("G");
string archiveName= String.Format("archive-{0}.zip",
DateTime.Now.ToString("yyyy-MMM-dd-HHmmss"));
Response.ContentType = "application/zip";
Response.AddHeader("content-disposition", "attachment; filename=" + archiveName);
using (ZipFile zip = new ZipFile())
{
// add a file entry into the zip, using content from a string
zip.AddFileFromString("Readme.txt", "", ReadmeText);
// add the set of files to the zip
zip.AddFiles(filesToInclude, "files");
// compress and write the output to OutputStream
zip.Save(Response.OutputStream);
}
Response.Close();
what i need is to split this 100MB file in to with about 20MB sections and provide the download facility to the user.how can i achieve this?
Your question is sort of independent of the ZIP aspect. Basically it seems you want to make available for download a large file of 100mb or more, and you want to do it in parts. Some options:
Save it to a regular file, then transmit it in parts. The client would have to make a distinct download request for each of the N parts, selecting the appropriate section of the file via the HTTP Range header. The server would have to be set up to server ZIP files with the appropriate MIME type etc.
save it to a split (spanned) zip file, which implies N different files. The client would then make an HTTP GET for each of the distinct files. The server would have to be set up to server .zip, .z00, .z01, etc. I'm not sure if built-in OS tools handle split zip files appropriately.
save the file as one large blob, and have the client use BITS or some other restartable download facility.

Extracting zip from stream with DotNetZip

public void ZipExtract(Stream inputStream, string outputDirectory)
{
using (ZipFile zip = ZipFile.Read(inputStream))
{
Directory.CreateDirectory(outputDirectory);
zip.ExtractSelectedEntries("name=*.jpg,*.jpeg,*.png,*.gif,*.bmp", " ", outputDirectory,
ExtractExistingFileAction.OverwriteSilently);
}
}
[HttpPost]
public ContentResult Uploadify(HttpPostedFileBase filedata)
{
var path = Server.MapPath(#"~/Files");
var filePath = Path.Combine(path, filedata.FileName);
if (filedata.FileName.EndsWith(".zip"))
{
ZipExtract(Request.InputStream,path);
}
filedata.SaveAs(filePath);
_db.Photos.Add(new Photo
{
Filename = filedata.FileName
});
_db.SaveChanges();
return new ContentResult{Content = "1"};
}
I try to read zip archive from stream and extract files. Got the following exception in the line "using (ZipFile zip = ZipFile.Read(inputStream))" : ZipEntry::ReadDirEntry(): Bad signature (0xC618F879) at position 0x0000EE19
Any ideas how to handle this exception?
The error is occurring because the stream you are trying to read is not a valid zip bytestream. In most cases, Request.InputStream will not represent a zip file. It will represent an HTTP message, which will look like this:
POST /path/for/your/app.aspx HTTP/1.1
User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.2; ...)
Content-Type: application/x-www-form-urlencoded
Content-Length: 11132
...more stuff here...
I think what you are doing is trying to read that message as if it were a zip file. That's not gonna work. The file content is actually embedded in the "... more stuff here..." part.
To work toward solving this, I suggest you work in smaller steps.
First, get the file upload to work, saving the content of the uploaded file to a filesystem file on the server. Then, on the server, try to open the file as a zipfile. If it works, then you should be able to replace the file saving portion, with ZipFile.Read(). If you cannot open the file that you saved, then it means that the file that you saved is not a zip file. Either it is incomplete, or, more likely, it includes extraneous data, like the HTTP headers.
If you have trouble successfully uploading a binary file like a zip file, first work on uploading a text file. You can more easily verify the upload of a text file on the server, by simply opening the uploaded content in a text editor, and checking that it contains exactly the content of the file that was uploaded from the client. Once you have this working, move to a binary file. Then you can move to a full streaming approach, using DotNetZip to read the stream. Once you get to this point, there should be no need to save the file to the filesystem, before reading it as a zip file, but you may want to save it anyway, for other reasons.
To help, you may want to use Fiddler2, the debugging HTTP proxy. Install it on the browser machine, turn it on, and it will help you see the messages that get sent from the browser to the ASPNET application on the server. You'll see that a file upload contains more that just the bare file data.
A more stable solution could be to use ICSharpCode ZipLib: http://www.sharpdevelop.net/OpenSource/SharpZipLib/Default.aspx

When downloading a file using FileStream, why does page error message refers to aspx page name, not file name?

After building a filepath (path, below) in a string (I am aware of Path in System.IO, but am using someone else's code and do not have the opportunity to refactor it to use Path). I am using a FileStream to deliver the file to the user (see below):
FileStream myStream = new FileStream(path, FileMode.Open, FileAccess.Read);
long fileSize = myStream.Length;
byte[] Buffer = new byte[(int)fileSize + 1];
myStream.Read(Buffer, 0, (int)myStream.Length);
myStream.Close();
Response.ContentType = "application/csv";
Response.AddHeader("content-disposition", "attachment; filename=" + filename);
Response.BinaryWrite(Buffer);
Response.Flush();
Response.End();
I have seen from: ASP.NET How To Stream File To User reasons to avoid use of Response.End() and Response.Close().
I have also seen several articles about different ways to transmit files and have diagnosed and found a solution to the problem (https and http headers) with a colleague.
However, the error message that was being displayed was not about access to the file at path, but the aspx file.
Edit: Error message is:
Internet Explorer cannot download MyPage.aspx from server.domain.tld
Internet Explorer was not able to open this Internet site. The requested site is either unavailable or cannot be found. Please try again later.
(page name and address anonymised)
Why is this? Is it due to the contents of the file coming from the HTTP response .Flush() method rather than a file being accessed at its address?
Even though you are sending a file, it is the "page" that contains the header information that describes the file you are sending. The browser still has to download that page, then sees the "attachment; filename=" and gives you the file instead.
So if there is an error, it will be page that is shown as the problem. It's a bit like getting a corrupted email with an attachment, you seen the problem in the email not the attachment itself.
Don't call Response.End();

Resources