0

My program has been using:

        Dim DLLink1 As String
        DLLink1 = Trim(TextBox2.Text)
        Dim DownloadDirectory1 As String
        DownloadDirectory1 = Trim(TextBox4.Text)
        Try
            Button3.Enabled = False
            '  My.Computer.Network.DownloadFile(DLLink1, (DownloadDirectory1 + "/UpdatedClient.zip"))
            Dim HttpReq As HttpWebRequest = DirectCast(WebRequest.Create(DLLink1), HttpWebRequest)

            Using HttpResponse As HttpWebResponse = DirectCast(HttpReq.GetResponse(), HttpWebResponse)
                Using Reader As New BinaryReader(HttpResponse.GetResponseStream())
                    Dim RdByte As Byte() = Reader.ReadBytes(1 * 1024 * 1024 * 10)
                    Using FStream As New FileStream(DownloadDirectory1 + "/UpdatedClient.zip", FileMode.Create)
                        FStream.Write(RdByte, 0, RdByte.Length)
                    End Using
                End Using
            End Using
        Finally
            MsgBox("Finished Download.")
            Button3.Enabled = True
            Label4.Visible = True

I tried this previously, and it didn't work at all:

My.Computer.Network.DownloadFile(DLLink1, (DownloadDirectory1 + "/UpdatedClient.zip"))

The website requires you to be logged in, so I made a spare account for the program:

WebBrowser1.Navigate("http://www.mpgh.net/forum/admincp/")
    Timer1.Start()
    Button2.Enabled = False

Then

WebBrowser1.Document.GetElementById("vb_login_username").SetAttribute("value", "AutoUpdaterAccount")
    WebBrowser1.Document.GetElementById("vb_login_password").SetAttribute("value", "password")

    Dim allelements As HtmlElementCollection = WebBrowser1.Document.All

    For Each webpageelement As HtmlElement In allelements

        If webpageelement.GetAttribute("type") = "submit" Then

            webpageelement.InvokeMember("click")
            Timer1.Stop()
            Label5.Text = "Authorized."
            Button2.Enabled = True

So now you're logged into the account, on the website, but when the code above to download runs, it downloads a zip, but it's corrupted. So I opened it with notepad++ and this is what I get (Does this mean it didn't login for the download, and it only logged in with the webbrowser and they aren't linked? Or something? Like My firefox logins aren't linked with chrome?:

The code is huge, it's like a HTML coding. Here is the link to a online notepad I put it on: http://shrib.com/nCOucdfL

Another thing, a webbrowser can't be showing on the program, it can be on the outside not showing, like I did with the login. They also can't click the save button like on a normal web browser when a window pops up, I want it to download automatically to where they set it using a button which sets the directory as DownloadDirectory1

DylanGM
  • 39
  • 7
  • Read the returned file. I just went through it briefly and it looks like the website is returning an error. The file says `BEGIN TEMPLATE: STANDARD_ERROR` near the very top. Reading further down the file, it appears they have some sort of protection in effect against automated bots and hackers. – dotNET Jan 25 '15 at 06:01
  • Is there anyway to bypass it? If you can't find a way, i'll ask a website admin for some help. The website is http://mpgh.net/ and the download link is http://www.mpgh.net/forum/attachment.php?attachmentid=266579&d=1417312178 – DylanGM Jan 25 '15 at 06:09
  • The source code you posted is from a webpage that says "You are not logged in or you do not have permission to access this page". The problem is that you are using the web browser control to log into the website which is great but then you are using your `HttpWebRequest` to try and download the file but that code is not linked to the web browser control, therefore it is a separate session which is not logged in and that is why you get the error. Unfortunately I do not think there is (an easy) way to link them together. – Joe Uhren Jan 25 '15 at 06:10
  • If you know, or know of where to find a hard way, I am willing to learn, and go through with it. It's a auto updater for servers. A couple are waiting for me to release, so I don't want to let them down. :P – DylanGM Jan 25 '15 at 06:12
  • Is it possible to instead of using `HttpWebRequest` in the code, use `webbrowser`? Or make `HttpWebRequest` login? Or maybe combined sessions? – DylanGM Jan 25 '15 at 06:13
  • I have tons of experience doing web scraping but I have never needed to automatically download files before. You can login with `HttpWebRequest` but you have to do everything manually. Save cookies and pass them back with every request. Trust me, it's not at all simple like using the web browser control which does all of that for you. I haven't tried any of this but take a look at the answers and comments on this page and let us know how it goes. There are a few promising suggestions: http://stackoverflow.com/questions/15419632/download-a-file-through-the-webbrowser-control – Joe Uhren Jan 25 '15 at 06:19
  • Alright, so there are a couple solutions here that might work. I have a pictures here of my program. I'm not finished with it but once I am, i'm passing it to a buddy that can make it look better, so ignore my crappy colors. http://s29.postimg.org/6vmgkvmxj/myprogram.jpg The right webbrowser will not be shown, and the bottom text box will also not be shown. The download link will be configured by the host, and then given to the users. I want all the users to have to do, is click authenticate, select directory, and then download. Making it simple as possible, no popups or anything. – DylanGM Jan 25 '15 at 06:29
  • . So, what way do you think would be the best way to achieve this? – DylanGM Jan 25 '15 at 06:31
  • Sorry about the color, it gets saved and blurs up. The top button is `Authorize` next down is `Choose Download Directory` then the next down is the directory after choosen, and then `Download`. Once downloaded, a button with `Download Complete` pops up. – DylanGM Jan 25 '15 at 06:32
  • The "best" way to achieve this would be to use `HttpWebRequest` because you control everything and you don't need any other controls. Assuming it is possible (because I haven't ever done it before), the "easiest" solution is to use the web browser control since you have already figured out how to log in and the only thing left is to see if you can get an automatic download to happen without user interaction. Going the web browser control way seems cheap but hey, if it works, I say do it. Going down the `HttpWebRequest` path means sniffing http headers and writing post values back to the site. – Joe Uhren Jan 25 '15 at 06:38
  • Alright so, i'm going to make it travel to the download page that should start the download automatically. How would I change the download directory to DownloadDirectory1 set by the user? – DylanGM Jan 25 '15 at 06:46
  • Unfortunately it pops up a window asking to download, then select directory, and then it shows you it downloading. Can't use webbrowser unless there is a way to disable those, or code it to automatically choose what it asks. I'll look into `HttpWebRequest` if you don't reply soon. – DylanGM Jan 25 '15 at 06:59
  • Again, I don't have the answer as I've never done this before. What I would do is check out the first answer from the page I showed you. You will obviously have to remove the part about the savefiledialog and just use your DownloadDirectory1 path instead. Also, you most likely will not be able to use the download page itself but instead you will need to find the direct download link on the download page and direct the web browser control there and then use the `WebClient` code to see if you can save the file without a prompt. You would also most likely need to suppress the save prompt somehow. – Joe Uhren Jan 25 '15 at 07:04
  • If you go the `HttpWebRequest` route then I can give you a few pointers. For sure you need some kind of app or plugin to see the http headers being passed back and forth. In the past I have used the firefox plugin 'Live HTTP Headers' but I think the Telerik Fidder app would help as well for any browser. You will have to log in manually and then check the headers to see what data is passed in and what is passed back. Also check into using `HttpWebRequest` to post data as that is what you will have to do to emulate the login and then save cookie data and pass it back with your get requests – Joe Uhren Jan 25 '15 at 07:09
  • Alright. So should I come back here for help, if I run into anything that requires me to do so? Or is there another way I should contact you? – DylanGM Jan 25 '15 at 07:18
  • Heh, get to 20 points and we can move this conversation to chat. I'll check back here periodically but I'm hoping someone who has done this sort of thing before will chime in with an easier answer. – Joe Uhren Jan 25 '15 at 07:32
  • Lol, easiest way to get 20 points is? I've been trying for 4 days. I got 2 downvotes for no reason. – DylanGM Jan 25 '15 at 08:20

1 Answers1

0

It must be your lucky day because today I woke up and decided that I would like to help you with your cause. I first tried to get the download to work with the web browser control but unfortunately I am sure this is not possible without extending the web browser control and we don't want to do that today.

As I mentioned in the comments, the only way I really know that this is possible (without user interaction) is to log in via the HttpWebRequest method. It's pretty tricky stuff. Definitely not for beginners.

Now I must admit that this isn't the cleanest, most "proper" and user-friendly code around, so if anyone wants to suggest a better way to do things, I am all ears.

I suggest you test this first before you incorporate it into your existing app. Just create a new vb.net app and replace all of the code in Form1 with the code below. You will have to update the usernamehere and passwordhere strings with your real username and password. Also, the file is saving to C:\file.rar by default so you can change this path if you want. This code completely removes the need for the web browser control (unless you are using it for something else) so most likely you can remove that from your real application once you incorporate this properly:

Imports System.Net
Imports System.IO
Imports System.Text

Public Class Form1
    Private Const gsUserAgent As String = "Mozilla/5.0 (Windows NT 6.1; WOW64; rv:35.0) Gecko/20100101 Firefox/35.0"

    Const sUsername As String = "usernamehere"
    Const sPassword As String = "passwordhere"
    Const sMainURL As String = "http://www.mpgh.net/"
    Const sCheckLoginURL As String = "http://www.mpgh.net/forum/login.php?do=login"
    Const sDownloadURL As String = "http://www.mpgh.net/forum/attachment.php?attachmentid=266579&d=1417312178"
    Const sCookieLoggedInMessage As String = "mpgh_imloggedin=yes"

    Dim oCookieCollection As CookieCollection = Nothing
    Dim sSaveFile As String = "c:\file.rar"

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        StartScrape()
    End Sub

    Private Sub StartScrape()
        Try
            Dim bContinue As Boolean = True

            Dim sPostData(15) As String

            sPostData(0) = UrlEncode("vb_login_username")
            sPostData(1) = UrlEncode(sUsername)
            sPostData(2) = UrlEncode("vb_login_password")
            sPostData(3) = UrlEncode(sPassword)
            sPostData(4) = UrlEncode("vb_login_password_hint")
            sPostData(5) = UrlEncode("Password")
            sPostData(6) = UrlEncode("s")
            sPostData(7) = UrlEncode("")
            sPostData(8) = UrlEncode("securitytoken")
            sPostData(9) = UrlEncode("guest")
            sPostData(10) = UrlEncode("do")
            sPostData(11) = UrlEncode("login")
            sPostData(12) = UrlEncode("vb_login_md5password")
            sPostData(13) = UrlEncode("")
            sPostData(14) = UrlEncode("vb_login_md5password_utf")
            sPostData(15) = UrlEncode("")

            If GetMethod(sMainURL) = True Then
                If SetMethod(sCheckLoginURL, sPostData, sMainURL) = True Then
                    ' Login successful

                    If DownloadMethod(sDownloadURL, sMainURL) = True Then
                        MessageBox.Show("File downloaded successfully")
                    Else
                        MessageBox.Show("Error downloading file")
                    End If
                End If
            End If
        Catch ex As Exception
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try
    End Sub

    Private Function GetMethod(ByVal sPage As String) As Boolean
        Dim req As HttpWebRequest
        Dim resp As HttpWebResponse
        Dim stw As StreamReader
        Dim bReturn As Boolean = True

        Try
            req = HttpWebRequest.Create(sPage)
            req.Method = "GET"
            req.AllowAutoRedirect = False
            req.UserAgent = gsUserAgent
            req.Accept = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
            req.Headers.Add("Accept-Language", "en-us,en;q=0.5")
            req.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
            req.Headers.Add("Keep-Alive", "300")
            req.KeepAlive = True

            resp = req.GetResponse        ' Get the response from the server 

            If req.HaveResponse Then
                ' Save the cookie info if applicable
                SaveCookies(resp.Headers("Set-Cookie"))

                resp = req.GetResponse        ' Get the response from the server 
                stw = New StreamReader(resp.GetResponseStream)
                stw.ReadToEnd()    ' Read the response from the server, but we do not save it
            Else
                MessageBox.Show("No response received from host " & sPage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                bReturn = False
            End If
        Catch exc As WebException
            MessageBox.Show("Network Error: " & exc.Message.ToString & " Status Code: " & exc.Status.ToString & " from " & sPage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            bReturn = False
        End Try

        Return bReturn
    End Function

    Private Function SetMethod(ByVal sPage As String, ByVal sPostData() As String, sReferer As String) As Boolean
        Dim bReturn As Boolean = False
        Dim req As HttpWebRequest
        Dim resp As HttpWebResponse
        Dim str As StreamWriter
        Dim sPostDataValue As String = ""

        Try
            req = HttpWebRequest.Create(sPage)
            req.Method = "POST"
            req.UserAgent = gsUserAgent
            req.Accept = "application/x-shockwave-flash,text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"
            req.Headers.Add("Accept-Language", "en-us,en;q=0.5")
            req.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7")
            req.Referer = sReferer
            req.ContentType = "application/x-www-form-urlencoded"
            req.Headers.Add("Pragma", "no-cache")
            req.Headers.Add("Keep-Alive", "300")

            If oCookieCollection IsNot Nothing Then
                ' Pass cookie info from the login page
                req.CookieContainer = SetCookieContainer(sPage)
            End If

            str = New StreamWriter(req.GetRequestStream)

            If sPostData.Count Mod 2 = 0 Then
                ' There is an even number of post names and values

                For i As Int32 = 0 To sPostData.Count - 1 Step 2
                    ' Put the post data together into one string
                    sPostDataValue &= sPostData(i) & "=" & sPostData(i + 1) & "&"
                Next i

                sPostDataValue = sPostDataValue.Substring(0, sPostDataValue.Length - 1) ' This will remove the extra "&" at the end that was added from the for loop above

                ' Post the data to the server

                str.Write(sPostDataValue)
                str.Close()

                ' Get the response

                resp = req.GetResponse

                If req.HaveResponse Then
                    If resp.Headers("Set-Cookie").IndexOf(sCookieLoggedInMessage) > -1 Then
                        ' Save the cookie info
                        SaveCookies(resp.Headers("Set-Cookie"))
                        bReturn = True
                    Else
                        MessageBox.Show("The email or password you entered are incorrect." & vbCrLf & vbCrLf & "Please try again.", "Unable to log in", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                        bReturn = False
                    End If
                Else
                    ' This should probably never happen.. but if it does, we give a message
                    MessageBox.Show("The email or password you entered are incorrect." & vbCrLf & vbCrLf & "Please try again.", "Unable to log in", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
                    bReturn = False
                End If
            Else
                ' Did not specify the correct amount of parameters so we cannot continue
                MessageBox.Show("POST error.  Did not supply the correct amount of post data for " & sPage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
                bReturn = False
            End If
        Catch ex As Exception
            MessageBox.Show("POST error.  " & ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            bReturn = False
        End Try

        Return bReturn
    End Function

    Private Function DownloadMethod(ByVal sPage As String, sReferer As String) As Boolean
        Dim req As HttpWebRequest
        Dim bReturn As Boolean = False

        Try
            req = HttpWebRequest.Create(sPage)
            req.Method = "GET"
            req.AllowAutoRedirect = False
            req.UserAgent = gsUserAgent
            req.Accept = "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
            req.Headers.Add("Accept-Language", "en-US,en;q=0.5")
            req.Headers.Add("Accept-Encoding", "gzip, deflate")
            req.Headers.Add("Keep-Alive", "300")
            req.KeepAlive = True

            If oCookieCollection IsNot Nothing Then
                ' Set cookie info so that we continue to be logged in
                req.CookieContainer = SetCookieContainer(sPage)
            End If

            ' Save file to disk

            Using oResponse As System.Net.WebResponse = CType(req.GetResponse, System.Net.WebResponse)
                Using responseStream As IO.Stream = oResponse.GetResponseStream
                    Using fs As New IO.FileStream(sSaveFile, FileMode.Create, FileAccess.Write)
                        Dim buffer(2047) As Byte
                        Dim read As Integer

                        Do
                            read = responseStream.Read(buffer, 0, buffer.Length)
                            fs.Write(buffer, 0, read)
                        Loop Until read = 0

                        responseStream.Close()
                        fs.Flush()
                        fs.Close()
                    End Using

                    responseStream.Close()
                End Using

                oResponse.Close()
            End Using

            bReturn = True
        Catch exc As WebException
            MessageBox.Show("Network Error: " & exc.Message.ToString & " Status Code: " & exc.Status.ToString & " from " & sPage, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
            bReturn = False
        End Try

        Return bReturn
    End Function

    Private Function SetCookieContainer(sPage As String) As System.Net.CookieContainer
        Dim oCookieContainerObject As New System.Net.CookieContainer
        Dim oCookie As System.Net.Cookie

        For c As Int32 = 0 To oCookieCollection.Count - 1
            If IsDate(oCookieCollection(c).Value) = True Then
                ' Fix dates as they seem to cause errors/problems
                oCookieCollection(c).Value = Format(CDate(oCookieCollection(c).Value), "dd-MMM-yyyy hh:mm:ss")
            End If

            oCookie = New System.Net.Cookie
            oCookie.Name = oCookieCollection(c).Name
            oCookie.Value = oCookieCollection(c).Value
            oCookie.Domain = New Uri(sPage).Host
            oCookie.Secure = False
            oCookieContainerObject.Add(oCookie)
        Next

        Return oCookieContainerObject
    End Function

    Private Sub SaveCookies(sCookieString As String)
        Dim sCookieStrings() As String = sCookieString.Trim.Replace(" HttpOnly,", "").Replace(" HttpOnly", "").Replace(" domain=.mpgh.net,", "").Split(";".ToCharArray())

        oCookieCollection = New CookieCollection

        For Each sCookie As String In sCookieStrings
            If sCookie.Trim <> "" Then
                Dim sName As String = sCookie.Trim().Split("=".ToCharArray())(0)
                Dim sValue As String = sCookie.Trim().Split("=".ToCharArray())(1)

                oCookieCollection.Add(New Cookie(sName, sValue))
            End If
        Next
    End Sub

    Private Function UrlEncode(ByRef URLText As String) As String
        Dim AscCode As Integer
        Dim EncText As String = ""
        Dim bStr() As Byte = Encoding.ASCII.GetBytes(URLText)

        Try
            For i As Long = 0 To UBound(bStr)
                AscCode = bStr(i)

                Select Case AscCode
                    Case 48 To 57, 65 To 90, 97 To 122, 46, 95
                        EncText = EncText & Chr(AscCode)

                    Case 32
                        EncText = EncText & "+"

                    Case Else
                        If AscCode < 16 Then
                            EncText = EncText & "%0" & Hex(AscCode)
                        Else
                            EncText = EncText & "%" & Hex(AscCode)
                        End If

                End Select
            Next i

            Erase bStr
        Catch ex As WebException
            MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
        End Try

        Return EncText
    End Function
End Class
Joe Uhren
  • 1,342
  • 1
  • 13
  • 27