Downloading a file from an ftp server to the browser - asp.net

I am creating a ASP.NET (VB.NET) application that must retrieve a known remote file and return it to the visitor through their browser. I am attempting to use the sample from Microsoft located here: http://support.microsoft.com/?kbid=812406 and running into an error 'This stream does not support seek operations'. I'm not sure how to proceed.
Here is the code with the error line marked.
Dim ftpWebReq As Net.FtpWebRequest = CType(Net.WebRequest.Create(path), Net.FtpWebRequest)
ftpWebReq.Method = Net.WebRequestMethods.Ftp.DownloadFile
ftpWebReq.KeepAlive = False
ftpWebReq.UsePassive = False
ftpWebReq.Credentials = New Net.NetworkCredential(System.Web.Configuration.WebConfigurationManager.AppSettings("FtpId"), System.Web.Configuration.WebConfigurationManager.AppSettings("FtpPwd"))
Dim ftpWebResp As Net.FtpWebResponse = CType(ftpWebReq.GetResponse(), Net.FtpWebResponse)
Dim streamer As Stream = ftpWebResp.GetResponseStream()
Dim buffer(10000) As Byte ' Buffer to read 10K bytes in chunk:
Dim length As Integer ' Length of the file:
Dim dataToRead As Long ' Total bytes to read:
dataToRead = streamer.Length ' *** This is the error line ***
Response.ContentType = "application/octet-stream"
Response.AddHeader("Content-Disposition", "attachment; filename=foo.txt")
While dataToRead > 0 ' Read the bytes.
If Response.IsClientConnected Then ' Verify that the client is connected.
length = streamer.Read(buffer, 0, 10000) ' Read the data in buffer
Response.OutputStream.Write(buffer, 0, length) ' Write the data to the current output stream.
Response.Flush() ' Flush the data to the HTML output.
ReDim buffer(10000) ' Clear the buffer
dataToRead = dataToRead - length
Else
dataToRead = -1 'prevent infinite loop if user disconnects
End If
End While

Don't bother with dataToRead. Keep reading until length is 0 (i.e streamer.Read() has returned 0). This means you've reached the end of the stream.
My VB is a bit rusty, but I think the loop should look something like this:
finished = False
While Not finished ' Read the bytes.
If Response.IsClientConnected Then ' Verify that the client is connected.
length = streamer.Read(buffer, 0, 10000) ' Read the data in buffer
If length > 0 Then
Response.OutputStream.Write(buffer, 0, length) ' Write the data to the current output stream.
Response.Flush() ' Flush the data to the HTML output.
ReDim buffer(10000) ' Clear the buffer
Else
finished = True
End If
Else
finished = True
End If
End While

Related

How to get the request.body value in asp classic?

In an .asp classic page I´m getting a POST send to me(a JSON string) and it is send in the request.body, says the guy how send it.
But if I just have theresponse=request.form I am not getting anything?
So how do I get the value from a request.body?
Some payment gateway API's I've used in the past have sent responses in this fashion. The data (JSON) is sent as a binary body post.
To read it you need to use Request.BinaryRead with Request.TotalBytes, then use Adodb.Stream to convert the binary to UTF8 text:
Response.ContentType = "application/json"
Function BytesToStr(bytes)
Dim Stream
Set Stream = Server.CreateObject("Adodb.Stream")
Stream.Type = 1 'adTypeBinary
Stream.Open
Stream.Write bytes
Stream.Position = 0
Stream.Type = 2 'adTypeText
Stream.Charset = "utf-8"
BytesToStr = Stream.ReadText
Stream.Close
Set Stream = Nothing
End Function
' You shouldn't really be receiving any posts more than a few KB,
' but it might be wise to include a limit (200KB in this example),
' Anything larger than that is a bit suspicious. If you're dealing
' with a payment gateway the usual protocol is to post the JSON
' back to them for verification before processing.
if Request.TotalBytes > 0 AND Request.TotalBytes <= 200000 then
Dim postBody
postBody = BytesToStr(Request.BinaryRead(Request.TotalBytes))
Response.Write(postBody) ' the JSON... hopefully
end if

ASP.NET File download over HTTPS failure

Stuck on trying to download a file over https, works fine across http but get the message in firefox - 'FILENAME could not be saved because the source file could not be read' and 'Failed - Network Error' in Chrome.
Web application sits behind Cisco firewall in which i have opened all the ports and still no joy. Flomoxed.
Dim file As System.IO.FileInfo = New System.IO.FileInfo(FullFilePath) '-- if the file exists on the server
If file.Exists Then 'set appropriate headers
Response.ClearContent()
Response.ClearHeaders()
Dim iStream As System.IO.Stream = Nothing
' Buffer to read 10K bytes in chunk:
Dim buffer(10000) As Byte
' Length of the file:
Dim length As Integer
' Total bytes to read:
Dim dataToRead As Long
Try
' Open the file.
iStream = New System.IO.FileStream(FullFilePath, System.IO.FileMode.Open,
IO.FileAccess.Read, IO.FileShare.Read)
' Total bytes to read:
dataToRead = iStream.Length
'Response.ContentType = "application/octet-stream"
Response.ContentType = "application/pdf"
'Response.ContentType = WebApp.Common.Functions.ReturnContentType(file.Extension.ToLower())
Response.AddHeader("Content-Disposition", "attachment; filename=""" & file.Name & """")
' Read the bytes.
While dataToRead > 0
' Verify that the client is connected.
If Response.IsClientConnected Then
' Read the data in buffer
length = iStream.Read(buffer, 0, 10000)
' Write the data to the current output stream.
Response.OutputStream.Write(buffer, 0, length)
' Flush the data to the HTML output.
Response.Flush()
ReDim buffer(10000) ' Clear the buffer
dataToRead = dataToRead - length
Else
'prevent infinite loop if user disconnects
dataToRead = -1
End If
End While
Catch ex As Exception
' Trap the error, if any.
Response.Write("Error : " & ex.Message)
Finally
If iStream IsNot Nothing Then
' Close the file.
iStream.Close()
End If
Response.Close()
End Try
Response.End() 'if file does not exist
Else
Response.Write("This file does not exist.")
End If 'nothing in the URL as HTTP GET

Read large file line-by-line with ADO Stream?

I want to use ADO Stream to read lines from a local large text file with UTF-8 encoding so I try
Set objStream = CreateObject("ADODB.Stream")
objStream.Charset = "utf-8"
objStream.Type = 2
objStream.Open
objStream.LoadFromFile = strFile
objStream.LineSeparator = 10
Do Until objStream.EOS
strLine = objStream.ReadText(-2)
Loop
However the result is that the script takes lots of RAM and CPU usages. So is there any way to tell the script not to load all the file contents into memory, but just open it and read until it encounters any line separator?
As you work with Stream object, I think it's obvious, however, .LoadFromFile fill current stream with the whole file content, and no any cutomize option to load parial data from file.
As for reading 1 line, you done this already with .ReadText(-2), (-2 = adReadLine).
Set objStream = CreateObject("ADODB.Stream")
With objStream
.Charset = "utf-8"
.Type = 2
.Open
'objStream.LoadFromFile = strFile ''I see a typo here
.LoadFromFile strFile
.LineSeparator = 10 ''that's Ok
'Do Until objStream.EOS ''no need this
strLine = .ReadText(-2)
'Loop
.Close ''add this though!
End with
Set objStream = Nothing
For .LineSeparator you can use just 3 constants:
Constant Value Description
adCRLF -1 Default. Carriage return line feed
adLF 10 Line feed only
adCR 13 Carriage return only
If you need to break your Do..Loop at other letter, as .ReadText is the only choice for reading text stream, you may use it in conjunction with InStr function and Exit Do then you find your custom separator.
Const cSeparator = "_" 'your custom separator
Dim strLine, strTotal, index
Do Until objStream.EOS
strLine = objStream.ReadText(-2)
index = InStr(1, strLine, cSeparator)
If index <> 0 Then
strTotal = strTotal & Left(strLine, index-1)
Exit Do
Else
strTotal = strTotal & strLine
End If
Loop
Shortly, this is the whole optimization you can do (or at least as far as I know).
If you look at this snippet from J. T. Roff's ADO book, you'll see that in theory you can read from a file line by line (without loading it completely into memory). I tried using the file: protocoll in the source parameter, but did not succeed.
So let's try another approach: To treat the .txt file as a UTF8 encoded trivial (one column) ADO database table, you need a schema.ini file in the source directory:
[linesutf8.txt]
ColNameHeader=False
CharacterSet=65001
Format=TabDelimited
Col1=SampleText CHAR WIDTH 100
Then you can do:
Dim sTDir : sTDir = "M:/lib/kurs0705/testdata"
Dim sFName : sFName = "[linesutf8.txt]"
Dim oDb : Set oDb = CreateObject("ADODB.Connection")
Dim sCs : sCs = Join(Array( _
"Provider=MSDASQL" _
, "Driver={Microsoft Text Driver (*.txt; *.csv)}" _
, "DBQ=" + sTDir _
), ";")
oDb.open sCs
WScript.Stdin.Readline
Dim oRs : Set oRs = oDb.Execute("SELECT * FROM " & sFName)
WScript.Stdin.Readline
Do Until oRS.EOF
WScript.Echo oRS.Fields(0).Value
oRs.MoveNext
Loop
oRs.Close
oDb.Close
For some background look here.

Response.Redirect a download in progress

I have a website where a user can choose to view a video (no copyright) that is on a 3rd party website. From the moment the user choose it, it needs to be downloaded onto my web server before the user can access it. I tried to automatically start the download on the 3rd party website and make a response.redirect with this path, but when the user is watching the video, if the video has only 10 seconds downloaded, any player/browser will considere this video as a ten-seconds video and stop it after 10 seconds.
What would be the best practice to redirect a stream instead of a file?
I found that this piece of code is doing exactly what I want. It downloads a file on a third party website, and as it's streaming it, each chunk is writen in the Response so that it completely obsfuscates the origin. Thus, it is possible to serve any file from any website as if I own it.
Private Sub SendFile(ByVal url As String)
Dim stream As System.IO.Stream = Nothing
Dim bytesToRead As Integer = 10000
Dim buffer() As Byte = New Byte((bytesToRead) - 1) {}
Try
Dim fileReq As System.Net.WebRequest = CType(System.Net.HttpWebRequest.Create(url), System.Net.HttpWebRequest)
Dim fileResp As System.Net.HttpWebResponse = CType(fileReq.GetResponse, System.Net.HttpWebResponse)
If (fileReq.ContentLength > 0) Then
fileResp.ContentLength = fileReq.ContentLength
End If
stream = fileResp.GetResponseStream
Dim resp As System.Web.HttpResponse = HttpContext.Current.Response
resp.ContentType = "application/octet-stream"
resp.AddHeader("Content-Disposition", ("attachment; filename=\""" + ("mp3" + "\""")))
resp.AddHeader("Content-Length", fileResp.ContentLength.ToString)
Dim length As Integer = 1000000
While (length > 0)
If resp.IsClientConnected Then
length = stream.Read(buffer, 0, bytesToRead)
resp.OutputStream.Write(buffer, 0, length)
resp.Flush()
buffer = New Byte((bytesToRead) - 1) {}
Else
length = -1
End If
End While
Catch
stream.Close()
Finally
If (Not (stream) Is Nothing) Then
stream.Close()
End If
End Try
Response.End()
End Sub

Getting access to a binary response byte-by-byte in classic asp/JScript

I asked this question a few days ago but it seems to have gone cold fairly quickly. What I want to do is pretty simple and I can't believe someone hasn't figured it out.
Solution needs to be JScript classic ASP. I am reading a file from a remote server and I want to process that (binary) file on my server and spit the results back to the client as XML.
Here's a simplified version of what I am trying to do. This code runs, or will if the URL is filled in for your site. This test file is readbin.asp. It reads a file called test.bin, and writes the result to a stream. I used a stream because that makes it easier to read the file and parse the contents. Basically I want to:
while not end of stream
read byte from stream
process byte
here is readbin.asp:
<%# LANGUAGE = JScript %>
<%
var url = "http:// (... your URL to the file test.bin goes here...) " ;
var xmlhttp = Server.CreateObject ("MSXML2.ServerXMLHTTP") ;
xmlhttp.open ("GET", url, false) ;
xmlhttp.send () ;
var BinaryInputStream = Server.CreateObject ("ADODB.Stream") ;
BinaryInputStream.Type = 1 ; // binary
BinaryInputStream.Open ;
BinaryInputStream.Write (xmlhttp.responseBody) ;
BinaryInputStream.Position = 0 ;
Response.Write ("BinaryInputStream.size = " + BinaryInputStream.size + "<br>") ;
Response.Write ("BinaryInputStream = " + BinaryInputStream + "<br>") ;
var ByteValue = BinaryInputStream.read (1) ;
Response.Write ("ByteValue = " + ByteValue + "<br>") ;
Response.Write ("typeof (ByteValue) = " + typeof (ByteValue) + "<br>") ;
%>
My problem is: how do I get ByteValue as a number 0..255? typeof (ByteValue) is "unknown".
Ord?? Byte()?? Asc?? Chr??
You may want to take a look at this piece of code:
http://docs.hyperweb.no/source/asplib1.2/util/fileupload.asp
This code is for handling uploaded files. It is really quite similar:
- On line 224 the binary request is being read into a stream object.
- On line 232 the data is read back as ISO-8859-1 text, which is almost what you want
- You can then read each byte of this string by using the getByte() function on line 48.
This function uses the lookup table on line 33 to fix ceratin characters that get converted to unicode.
I am much more experienced with vbscript than jscript but I will give it a shot since not many takers on this question.
states there are six possible values that typeof returns: "number," "string," "boolean," "object," "function," and "undefined."
http://msdn.microsoft.com/en-us/library/259s7zc1(VS.85).aspx
The ADODB.Stream .Read object and method return a variant data type. I suspect typeof does not like the variant datatype.
http://www.w3schools.com/ado/ado_ref_stream.asp
The posting from this guy seems to explain it a bit further.
http://blogs.msdn.com/jaiprakash/archive/2007/01/09/jscript-supports-safearrays-of-variants-only.aspx
I would try casting the return stream before applying typeof to it.
Maybe not quite on the topic, but using VBScript I wrote this:
option explicit
dim fso, wshSHell, objShellApp, args, stdin,stdout
set fso = CreateObject("Scripting.FileSystemObject")
Set wshShell = CreateObject("WScript.Shell")
set objShellApp = CreateObject("Shell.Application")
Set args = Wscript.Arguments
set stdin = wscript.stdin
set stdout = wscript.stdout
dim filename, txtFile
filename = args(0)
Const adTypeBinary = 1
'Create Stream object
Dim BinaryStream, data
Set BinaryStream = CreateObject("ADODB.Stream")
'Specify stream type - we want To get binary data.
BinaryStream.Type = adTypeBinary
'Open the stream
BinaryStream.Open
'Load the file data from disk To stream object
BinaryStream.LoadFromFile filename
'Open the stream And get binary data from the object
data = BinaryStream.Read
BinaryStream.close
dim i, item, strLine, hexLine
hexLine = ""
strLine = ""
stdout.writeline "Decimal |Hex |Data | ASCII 33-254"
for i = 0 to lenb(data)-1
item = ascb(midb(data,i+1,1))
if ((i MOD 16) = 0) and (i<>0) then
stdout.writeLine right("00000000" & i,8) & "|" & right("00000000" & hex(i),8) & "|" & hexLine & " | " & strLine
hexLine = ""
strLine = ""
end if
hexLine = hexLine & right("0" & hex(item),2) & " "
if (item <= 32) or (item > 254) then
strLine=strLine + "."
else
strLine = strLine & chr(item)
end if
next
Key to this solution is to know that the variable 'data' contains an array of bytes. You can handle that by using the function lenb (length of byte array) and midb (to extract one or more bytes).
Run the script as follows:
cscript dumphex.vbs my_binary_file.bin > my_binary_file.hex.txt
This will output to standard out the hex code of all the binary file data. Each line of 16 hex codes is prefixed by a decimal + hex counter of the byte number. THe last column displays readable ascii between 33 and 254.
Also great to circumvent that annoying editor that interprets your UTF-8 codes, if you want to see just the exact codes in your ascii files.

Resources