Uri encoding, file download doesn't work with , and whitespace - c#

I have an asp.net webpage that allows downloading files.
When i had the problem of downloading a file with whitespace(Test 1 4 3.txt) it will turn the file into: Test+1+4+3.txt
I used:
_Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(_fileName, System.Text.Encoding.UTF8));
And it solved the issue.
Now i have a new issue:
When a file contains , it changes it into %2c and i the UrlEncode doesn't fix it.
i Tried using:
_Response.AddHeader("Content-Disposition", "attachment;filename=" + Uri.EscapeDataString(_fileName));
But it's the old setting and it doesn't support whitespace.
What can i do to solve such a case?
Should i use regex / switch?
This is my function:
public static bool ResponseFile(HttpRequest _Request, HttpResponse _Response, string _fileName, string _fullPath, long _speed = 1024000)
{
try
{
FileStream myFile = new FileStream(_fullPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
try
{
_Response.AddHeader("Accept-Ranges", "bytes");
_Response.Buffer = false;
long fileLength = myFile.Length;
long startBytes = 0;
int pack = 10240; //10K bytes
int sleep = (int)Math.Floor((double)(1000 * pack / _speed)) + 1;
if (_Request.Headers["Range"] != null)
{
_Response.StatusCode = 206;
string[] range = _Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[1]);
}
_Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
if (startBytes != 0)
{
_Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
_Response.AddHeader("Connection", "Keep-Alive");
_Response.ContentType = "application/octet-stream";
//Old didn't work with both + and ,
//_Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(_fileName, System.Text.Encoding.UTF8));
_Response.AddHeader("Content-Disposition", "attachment;filename=" + Uri.EscapeDataString(_fileName));
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + 1;
for (int i = 0; i < maxCount; i++)
{
if (_Response.IsClientConnected)
{
_Response.BinaryWrite(br.ReadBytes(pack));
Thread.Sleep(sleep);
}
else
{
i = maxCount;
}
}
}
catch
{
return false;
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
return false;
}
return true;
}

This solved it:
_Response.AddHeader("Content-Disposition", "attachment;filename=\"" + _fileName + "\"");

Related

ZIP download is blocking because of organisation policy in asp.net

As am having my ZIP file in the folder and if I click download report button am blocking to download based on my organization policy.
But I need to download this ZIP file from the code how can we achieve this.
The code which I used as below
string[] filenames = Directory.GetFiles(SourceFolder);
ZipFilePath = DestinationFolder + #"\" + ZipFileName;
using (ZipOutputStream s = new
ZipOutputStream(File.Create(ZipFilePath)))
{
s.SetLevel(6);
byte[] buffer = new byte[4096];
foreach (string file in filenames)
{
if (Path.GetFileName(file).Contains(SubString) || Path.GetFileName(file).Contains("logfile"))
{
ZipEntry entry = new
ZipEntry(Path.GetFileName(file));
entry.DateTime = DateTime.Now;
s.PutNextEntry(entry);
using (FileStream fs = File.OpenRead(file))
{
int sourceBytes;
do
{
sourceBytes = fs.Read(buffer, 0,
buffer.Length);
s.Write(buffer, 0, sourceBytes);
} while (sourceBytes > 0);
}
}
}
s.Finish();
s.Close();
}
string DownloadFileName = ZipFilePath;
DownloadFileName = DownloadFileName.Replace("\\", "~");
RadAjaxManager1.ResponseScripts.Add("setTimeout(function(){ document.location.href = 'DownloadHandler.ashx?FileName=" + DownloadFileName + "'; return false; },300);");
The DownloadHandler.ashx page as below
public void ProcessRequest(HttpContext context)
{
try
{
HttpResponse rspns = context.Response;
string FileToDownload = context.Request.QueryString["FileName"];
string FileName = string.Empty;
if (context.Request.QueryString["Name"] != null)
{
FileName = context.Request.QueryString["Name"];
}
if (FileToDownload!=null)
{
FileToDownload = FileToDownload.Replace("~", "\\");
FileName = System.IO.Path.GetFileName(FileToDownload);
}
else
{
//FileName = Convert.ToString(iTAPSession.UserData);
}
rspns.AppendHeader("content-disposition", "attachment; filename=\"" + FileName.Replace(" ", "%20"));
rspns.TransmitFile(FileToDownload);
rspns.End();
}
catch (Exception e)
{
}
}
public bool IsReusable
{
get
{
return false;
}
}
am getting the below exception
Based on your organization's access policies, access to this website or download ( http://xxxxxxx/ITAADemo/DownloadHandler.ashx?FileName=D:~ITAADemo~Files~SuperAdmin~bn4wgrusef1xgmjhqokd2yo2~~TextAnalytics~~zipdownload~Report_2018-Jul-19-11-39-31.zip ) has been blocked because the file type "application/zip" is not allowed.

When calculating to report backgroundworker progressBar i'm getting exception cant divide by zero what is wrong?

This is the method:
Getting the Length of the files give 0 already.
public void DownloadFtpContent(object sender ,string file, string filesdirectories,string fn)
{
try
{
BackgroundWorker bw = sender as BackgroundWorker;
string filenameonly = Path.GetFileName(file);
string ftpdirectories = Path.Combine(ftpcontentdir, filesdirectories);
string fileurl = "ftp://" + file;
FtpWebRequest reqFTP;
reqFTP = (FtpWebRequest)FtpWebRequest.Create(fileurl);
reqFTP.Credentials = new NetworkCredential(UserName, Password);
reqFTP.UseBinary = true;
reqFTP.UsePassive = true;
reqFTP.KeepAlive = true;
reqFTP.Method = WebRequestMethods.Ftp.DownloadFile;
reqFTP.Proxy = null;
FtpWebResponse response = (FtpWebResponse)reqFTP.GetResponse();
Stream responseStream = response.GetResponseStream();
if (!Directory.Exists(ftpdirectories))
{
Directory.CreateDirectory(ftpdirectories);
}
FileStream writeStream = new FileStream(ftpdirectories + "\\" + filenameonly, FileMode.Create);
string fnn = ftpdirectories + "\\" + filenameonly;
int Length = 2048;
Byte[] buffer = new Byte[Length];
int bytesRead = responseStream.Read(buffer, 0, Length);
long FileSize = new FileInfo(fnn).Length;
string FileSizeDescription = GetFileSize(FileSize);
while (bytesRead > 0)
{
writeStream.Write(buffer, 0, bytesRead);
bytesRead = responseStream.Read(buffer, 0, Length);
string SummaryText = String.Format("Transferred {0} / {1}", GetFileSize(bytesRead), FileSizeDescription);
bw.ReportProgress((int)(((decimal)bytesRead / (decimal)FileSize) * 100), SummaryText);
}
writeStream.Close();
response.Close();
}
catch (WebException wEx)
{
//MessageBox.Show(wEx.Message, "Download Error");
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message, "Download Error");
}
}
}
Already on this line the result is 0:
long FileSize = new FileInfo(fnn).Length;
In fnn i have: c:\myftpdownloads\root\Images\CB 967x330.jpg
Why the result of the Length is 0 ?
And the file is not 0kb size.
EDIT
This is how i'm calling the download method from backgroundworker dowork event:
private void backgroundWorker2_DoWork(object sender, DoWorkEventArgs e)
{
for (int i = 0; i < numberOfFiles.Count; i++)
{
int fn = numberOfFiles[i].IndexOf(txtHost.Text, 0);
string fn1 = numberOfFiles[i].Substring(txtHost.Text.Length + 1, numberOfFiles[i].Length - (txtHost.Text.Length + 1));
string dirs = Path.GetDirectoryName(fn1);
string filename = Path.GetFileName(fn1);
ftpProgress1.DownloadFtpContent(sender,numberOfFiles[i], dirs, filename);
}
}
In fnn i have: c:\myftpdownloads\root\Images\CB 967x330.jpg Why the result of the Length is 0 ?
It doesn't really matter why the result of the length is 0. It does matter that you divide that number by 0 without any protection.
Just check before you divide:
if( FileSize != 0 ){...}

Downloading a File on ASP.net C#

I have a serious Problem with Download in my ASP.net Project.
I used the same code in 2 pages to download a file :
private bool DownloadAnhang_Tracking(string fileName, string filepath)
{
////File Path and File Name
string filePath = filepath;
string downloadableFileName = fileName;
System.IO.FileInfo filename;
FileStream myFile;
try
{
filename = new System.IO.FileInfo(filePath);
myFile = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
}
catch (IOException ex)
{
this.ShowErrorNotification("Fehler: " + ex.Message);
throw;
}
////Reads file as binary values
BinaryReader binaryReader = new BinaryReader(myFile);
////Check whether file exists in specified location
if (filename.Exists)
{
try
{
long startBytes = 0;
string lastUpdateTiemStamp = File.GetLastWriteTimeUtc(filePath).ToString("r");
string encodedData = HttpUtility.UrlEncode(downloadableFileName, Encoding.UTF8) + lastUpdateTiemStamp;
Response.Clear();
Response.Buffer = false;
Response.AddHeader("Accept-Ranges", "bytes");
Response.AppendHeader("ETag", "\"" + encodedData + "\"");
Response.AppendHeader("Last-Modified", lastUpdateTiemStamp);
Response.ContentType = "application/octet-stream";
Response.AddHeader("Content-Disposition", "attachment;filename=" + filename.Name);
Response.AddHeader("Content-Length", (filename.Length - startBytes).ToString());
Response.AddHeader("Connection", "Keep-Alive");
Response.ContentEncoding = Encoding.UTF8;
////Send data
binaryReader.BaseStream.Seek(startBytes, SeekOrigin.Begin);
////Dividing the data in 1024 bytes package
int maxCount = (int)Math.Ceiling((filename.Length - startBytes + 0.0) / 1024);
////Download in block of 1024 bytes
int i;
for (i = 0; i < maxCount && Response.IsClientConnected; i++)
{
Response.BinaryWrite(binaryReader.ReadBytes(1024));
Response.Flush();
}
////if blocks transfered not equals total number of blocks
if (i < maxCount)
{
return false;
}
else
{
return true;
}
}
catch
{
return false;
}
finally
{
Response.End();
binaryReader.Close();
myFile.Close();
}
}
else
{
this.ShowErrorNotification("Der Anhang wurde nicht gefunden!");
}
return false;
}
So used this code in another page, but it doesn't work anymore! I pass the same information to the method but it doesn't work! The Error is from MSAjax:
0x800a139e - Runtime Error in JavaScript:
Sys.WebForms.PageRequestManagerParserErrorException: The message
received from the server could not be parsed. Common causes for this
error are when the response is modified by calls to Response.Write(),
response filters, HttpModules, or server trace is enabled.
I don't get why this code works on page 1 but not on page 2.
Im using ASP.Net 4.5 WebForms with C#

Missing last bytes of a file

I'm new at pogramming and I have a problem that I cant solve. I have create a program that share files, like dropbox. I have a server, that is working fine and a client.
The problem is, when I'm trying to download a file from the server, it seems that some bytes are missing from the stream.
clientSocket = new TcpClient(Program.host, Program.port);
NetworkStream networkStream = clientSocket.GetStream();
StreamWriter write = new StreamWriter(networkStream);
write.WriteLine(need);
write.Flush();
write.WriteLine(loca);
write.Flush();
StreamReader read = new StreamReader(networkStream);
Int64 size = Convert.ToInt64(read.ReadLine());
long blocks = size / 1024;
long blocksDown = 0;
try
{
string fileName = string.Empty;
int qtd = 0;
int blockSize = 1024;
double progress = 0;
Int64 qtdDown = 0;
Byte[] dataByte = new Byte[blockSize];
bool download = true;
lock (this)
{
networkStream.Read(dataByte, 0, dataByte.Length);
int fileNameLen = BitConverter.ToInt32(dataByte, 0);
fileName = Encoding.ASCII.GetString(dataByte, 4, fileNameLen);
if (File.Exists(Program.loc + fileName))
switch (MessageBox.Show("Ficheiro já existente!\r\nDeseja Substituir?", "Aviso", MessageBoxButtons.YesNo,
MessageBoxIcon.Warning))
{
case DialogResult.Yes:
File.Delete(Program.loc + fileName);
download = true;
break;
case DialogResult.No:
download = false;
break;
}
if (download)
{
Stream fileStream = File.OpenWrite(Program.loc + fileName);
fileStream.Write(dataByte, 4 + fileNameLen, (1024 - (4 + fileNameLen)));
bool progChanged = false;
backWork.WorkerReportsProgress = true;
double progAnt = 0;
while (true)
{
qtd = networkStream.Read(dataByte, 0, blockSize);
qtdDown += qtd;
progress = (double)qtdDown * (double)100 / (double)size;
if (Math.Round(progress) > Math.Round(progAnt))
{
progChanged = true;
progAnt = progress;
}
if (Math.Round(progress) > 0 && progChanged)
{
backWork.ReportProgress(((int)Math.Round(progress)));
progChanged = false;
}
fileStream.Write(dataByte, 0, qtd);
fileStream.Flush();
blocksDown++;
if (qtd == 0)
{
backWork.ReportProgress(100);
qtd = networkStream.Read(dataByte, 0, blockSize);
networkStream.Close();
fileStream.Close();
break;
}
}
MessageBox.Show("O ficheiro " + fileName + " foi guardado em " + Program.loc + ".", "Download",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
This is what I'm doing. I'm doing the download on a Background worker.
First I write on the stream what I'm doing then I open the stream of the file, and then start reading the stream and writing to the file.
#Ňuf I tried what you said and still doesnt work
The code looks like this, and the bytes from qtdDown and size are not equal. Sorry if if there are some parts in portuguese, my native langage is portuguese.
btnAct.Enabled = false;
btnBro.Enabled = false;
btnDown.Enabled = false;
btnSend.Enabled = false;
menuStrip1.Enabled = false;
pBar.Value = 0;
clientSocket = new TcpClient(Program.host, Program.port);
NetworkStream networkStream = clientSocket.GetStream();
StreamWriter write = new StreamWriter(networkStream);
write.WriteLine(need);
write.Flush();
write.WriteLine(loca);
write.Flush();
int blockSize = 1024;
byte[] fileSizeBytes = new byte[blockSize];
networkStream.Read(fileSizeBytes, 0, blockSize);
string fileSizeString = Encoding.ASCII.GetString(fileSizeBytes, 0, fileSizeBytes.Length);
fileSize = Convert.ToInt64(fileSizeString);
qtdDown = 0;
try
{
string fileName = string.Empty;
int qtd = 0;
double progress = 0;
Byte[] dataByte = new Byte[blockSize];
bool download = true;
lock (this)
{
networkStream.Read(dataByte, 0, dataByte.Length);
int fileNameLen = BitConverter.ToInt32(dataByte, 0);
fileName = Encoding.ASCII.GetString(dataByte, 4, fileNameLen);
if (File.Exists(Program.loc + fileName))
switch (MessageBox.Show("Ficheiro já existente!\r\nDeseja Substituir?", "Aviso", MessageBoxButtons.YesNo,
MessageBoxIcon.Warning))
{
case DialogResult.Yes:
File.Delete(Program.loc + fileName);
download = true;
break;
case DialogResult.No:
download = false;
break;
}
if (download)
{
Stream fileStream = File.OpenWrite(Program.loc + fileName);
fileStream.Write(dataByte, 4 + fileNameLen, (1024 - (4 + fileNameLen)));
networkStream.ReadTimeout = 60;
backWork.WorkerReportsProgress = true;
double progAnt = 0;
while (true)
{
qtd = networkStream.Read(dataByte, 0, blockSize);
qtdDown += qtd;
progress = (double)qtdDown * (double)100 / (double)fileSize;
if (Math.Round(progress) > Math.Round(progAnt))
{
progAnt = progress;
backWork.ReportProgress(((int)Math.Round(progress)));
}
fileStream.Write(dataByte, 0, qtd);
if (qtdDown == fileSize)
{
backWork.ReportProgress(100);
fileStream.Close();
networkStream.Close();
break;
}
}
MessageBox.Show("O ficheiro " + fileName + " foi guardado em " + Program.loc + ".", "Download",
MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
catch (Exception ex)
{
menuStrip1.Enabled = true;
btnAct.Enabled = true;
btnBro.Enabled = true;
btnDown.Enabled = true;
btnSend.Enabled = true;
MessageBox.Show("Ocorreu um erro!" + "\r\nBytes Downloaded: "
+ qtdDown.ToString() + "\\" + fileSize.ToString() + "\r\nDetalhes do Erro: " + ex.Message, "Download",
MessageBoxButtons.OK, MessageBoxIcon.Error);
}
menuStrip1.Enabled = true;
btnAct.Enabled = true;
btnBro.Enabled = true;
btnDown.Enabled = true;
btnSend.Enabled = true;
You are loosing bytes by calling read.ReadLine(). Although this function returns only data from one line, it internally reads more data from network stream to internal buffer and keeps remaining data for subsequent read.Read() calls, which never happens in your code.
Read data either using StreamReader or read them directly from NetworkStrem, but do not mix readings from both together.
I added this line in the last if, * || (fileSize - qtdDown) < 1024* and the files now work, I don't know if those last bytes are important, but the files now work.

Download function failing with big file sizes

Hi my download function.
protected void downloadFunction(string fileName)
{
string filePath = #"D:\SoftwareFiles\";
LogMessageToFile("Download started " + filePath + fileName);
byte[] array = File.ReadAllBytes(filePath + fileName);
Response.Clear();
Response.ContentType = "application/x-newton-compatible-pkg";
Response.AppendHeader("Content-Disposition",
"attachment;filename=" + fileName);
Response.BinaryWrite(array);
Response.End();
}
When handling filesize of 20, 200mb no problem.
When handling 1gb file, an exception is thrown:
Overflow or underflow in the arithmetic operation.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.ArithmeticException: Overflow or underflow in the arithmetic operation.
What to do?
My guess is that you're running out of memory in the byte[] array.
You can try breaking the file down and reading it in chunks.
I found a code example from a Google search to get you started:
C# file downloader AKA Response.BinaryWrite
using System;
using System.IO;
using System.Web;
public class Download
{
public static void SmallFile(string filename, string filepath, string contentType)
{
try
{
FileStream MyFileStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
long FileSize;
FileSize = MyFileStream.Length;
byte[] Buffer = new byte[(int)FileSize];
MyFileStream.Read(Buffer, 0, (int)MyFileStream.Length);
MyFileStream.Close();
HttpContext.Current.Response.ContentType = contentType;
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
HttpContext.Current.Response.BinaryWrite(Buffer);
}
catch
{
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Downloading Error!");
}
HttpContext.Current.Response.End();
}
public static void LargeFile(string filename, string filepath, string contentType)
{
Stream iStream = null;
// Buffer to read 10K bytes in chunk
//byte[] buffer = new Byte[10000];
// Buffer to read 1024K bytes in chunk
byte[] buffer = new Byte[1048576];
// Length of the file:
int length;
// Total bytes to read:
long dataToRead;
try
{
// Open the file.
iStream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
// Total bytes to read:
dataToRead = iStream.Length;
HttpContext.Current.Response.ContentType = contentType;
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
// Read the bytes.
while (dataToRead > 0)
{
// Verify that the client is connected.
if (HttpContext.Current.Response.IsClientConnected)
{
// Read the data in buffer.
length = iStream.Read(buffer, 0, 10000);
// Write the data to the current output stream.
HttpContext.Current.Response.OutputStream.Write(buffer, 0, length);
// Flush the data to the HTML output.
HttpContext.Current.Response.Flush();
buffer = new Byte[10000];
dataToRead = dataToRead - length;
}
else
{
//prevent infinite loop if user disconnects
dataToRead = -1;
}
}
}
catch (Exception ex)
{
// Trap the error, if any.
//HttpContext.Current.Response.Write("Error : " + ex.Message);
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Error : file not found");
}
finally
{
if (iStream != null)
{
//Close the file.
iStream.Close();
}
HttpContext.Current.Response.End();
HttpContext.Current.Response.Close();
}
}
public static void ResumableFile(string filename, string fullpath, string contentType)
{
try
{
FileStream myFile = new FileStream(fullpath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
BinaryReader br = new BinaryReader(myFile);
try
{
HttpContext.Current.Response.AddHeader("Accept-Ranges", "bytes");
HttpContext.Current.Response.Buffer = false;
long fileLength = myFile.Length;
long startBytes = 0;
//int pack = 10240; //10K bytes
int pack = 1048576; //1024K bytes
if (HttpContext.Current.Request.Headers["Range"] != null)
{
HttpContext.Current.Response.StatusCode = 206;
string[] range = HttpContext.Current.Request.Headers["Range"].Split(new char[] { '=', '-' });
startBytes = Convert.ToInt64(range[1]);
}
HttpContext.Current.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString());
if (startBytes != 0)
{
HttpContext.Current.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength));
}
HttpContext.Current.Response.AddHeader("Connection", "Keep-Alive");
HttpContext.Current.Response.ContentType = contentType;
HttpContext.Current.Response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(filename, System.Text.Encoding.UTF8));
br.BaseStream.Seek(startBytes, SeekOrigin.Begin);
int maxCount = (int)Math.Floor((double)((fileLength - startBytes) / pack)) + 1;
for (int i = 0; i < maxCount; i++)
{
if (HttpContext.Current.Response.IsClientConnected)
{
HttpContext.Current.Response.BinaryWrite(br.ReadBytes(pack));
}
else
{
i = maxCount;
}
}
}
catch
{
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Error : file not found");
}
finally
{
br.Close();
myFile.Close();
}
}
catch
{
HttpContext.Current.Response.ContentType = "text/html";
HttpContext.Current.Response.Write("Error : file not found");
}
}
}

Categories

Resources