wwFtp and WinInet Problems with IE 11
November 25, 2013 •
In the last few weeks I've gotten a few notes from various customers that wwFtp has started to break for them after upgrading to IE 11. It appears there's been a new bug introduced with IE 11 that causes failures on certain types of connections.
There's more info on this in this StackOverflow question:
Specifically it points at some reproducible problems.
So far all the problems I've heard reported are related to file uploads rather than downloads. And for uploads there are a few workaround available.
Setting the Scenario
So I set up a simple test to upload some files to my own FTP server and sure enough I can see the problem occurring with this code:
CLEAR DO wwftp DO wwutils LOCAL o as wwFtp o=create("wwFTP") ? o.FTPConnect("www.west-wind.com","ricks",GetSystemPassword()) ? o.FTPSendFileEx("c:\temp\geocrumbs.jpg","geocrumbs.jpg") ? o.FTPSendFileEx("c:\temp\iefullscreen.png","iefullscreen.png") ? o.FTPSendFileEx("c:\temp\iemetrononfullscreen.png","iemetrononfullscreen.png") ? o.cErrorMsg o.FTPClose() RETURN
Here I'm using FtpSendFileEx() to upload multiple files on a single connection and when I run this the third FTPSendFileEx call ends up failing with a 12003 error (extended error) with an error message basically echoing back the transfer command.
200 Type set to I
226 Transfer OK
Oddly this looks like the transfer worked even though the error message shows, but examing the target folder on the server reveals that the file was not actually sent or at least not written over there.
So what can we do?
Disable lPassiveFtp
wwFtp by default uses Passive FTP as it's more flexible for going through firewalls and proxied HTTP connections. By default lPassiveFtp is .T. and so passive FTP is used. Passive FTP basically creates a connection does it's transfer and drops the connection and automatically reestablishes as needed. In the process the FTP connection might actually jump ports.
By setting:
o.lPassiveFtp = .F.
wwFtp uses Active connections which stay alive for the duration of the connection made and stays fixed on a single port.
Using Active Connections I had no problems with uploading many files.
Unfortunately, active connections do not always work and can be flaky with connection drop offs, but it entirely depends on the environment. In general I recommend using Passive as the default but in light of the current bug, using Active at least should be tried (and you should always expose that setting as an option in your application settings so you can easily switch modes.
Connect and disconnect for each Transfer
Another option for sending files is to simply not reuse connections and send files by opening, sending and closing the connection. Doing this is reliable but it'll add a little overhead especially if you're sending lots of files.
So this works too:
LOCAL o as wwFtp o=create("wwFTP") o.lPassiveFtp = .T. ? o.FTPConnect("www.west-wind.com","ricks",GetSystemPassword()) ? o.FTPSendFileEx("c:\temp\geocrumbs.jpg","geocrumbs.jpg") o.FTPClose() ? o.FTPConnect("www.west-wind.com","ricks",GetSystemPassword()) ? o.FTPSendFileEx("c:\temp\iefullscreen.png","iefullscreen.png") o.FTPClose() ? o.FTPConnect("www.west-wind.com","ricks",GetSystemPassword()) ? o.FTPSendFileEx("c:\temp\iemetrononfullscreen.png","iemetrononfullscreen.png") o.FTPClose()
Use FtpSendFileEx2
Some time ago I quietly added an wwFtp::FtpSendFileEx2() function to wwFtp. The original FtpSendEx() method is a very low level function that makes a bunch of internal API calls from within Visual FoxPro. It also adds some additional features like giving you the ability to get notified of chunks of data being sent.
Even prior to this IE 11 issue, I've found that on occasion when sending large numbers of files, FtpSendFileEx() would occasionally stall for no apparent reason. It was rare but enough of a problem to consider alternatives. The alternative was to build another routine - FtpSendFileEx2(), which provides the same functionality but calls one of the higher level WinInet functions (FtpPutFile()) which is basically a single command. It turns out that using FtpPutFile() under the hood is a lot more reliable than the various API streaming functions.
FptSendFileEx2() is parameter compatible with FtpSendFile() but - it doesn't support the update even calls the OnFtpBufferUpdate() to provide progress information as the file is sent off a single API call into WinInet.
LOCAL o as wwFtp o=create("wwFTP") ? o.FTPConnect("www.west-wind.com","ricks",GetSystemPassword()) ? o.FTPSendFileEx2("c:\temp\geocrumbs.jpg","geocrumbs.jpg") ? o.FTPSendFileEx2("c:\temp\iefullscreen.png","iefullscreen.png") ? o.FTPSendFileEx2("c:\temp\iemetrononfullscreen.png","iemetrononfullscreen.png") o.FTPClose()
and that works reliably too.
I use FtpSendFileEx2() in Help Builder to upload HTML help files to a Web site, and that can be 1000s of files in a session - and it works without problems, so this is what I would recommend you use for uploading files in bulk.
What to use?
If you're uploading a bunch of smallish files a use FtpSendFileEx2() - you won't need progress info on a per file basis, but you can certainly handle intra file upload info. If you upload just one or two larger files and you need the OnFtpUpdate() API to provide progress info, use FtpSendFileEx() but just make sure you reconnect for each file upload.
Switching active/passive mode is just a quick fix that might help get you out of a bind, but as a long term solution I'd still recommend you use Passive mode as it's much more reliable.
Hopefully this will be a temporary issue that Microsoft addresses soon - this is turning out to be a major headache for some of my customers who've been calling in frantically asking to see if there's a solution to this problem. It sucks when an application that's been running for 10 years mysteriously breaks after a silly browser update.
Bernie Murciano
December 04, 2013