Just a short, simple blog for Bob to share his thoughts.
28 August 2007 • by Bob • FTP, IIS
I received the following question from Mickey Binder in response to my blog entries about the new FTP service for IIS7:
"When using virtual hosts will it always be necessary to provide DOMAIN|Username or is it me doing something wrong. I can see in your documentation how it should be setup, I just wonder why it still needs the DOMAIN in the user login as this should already be specified by the host I connect to (Like with the http virtual hosts)."
I thought that was a great question, and I think that it deserves a detailed response. The short answer is that you need to provide the host name somehow when connecting to an FTP site, and FTP simply does not work the way that HTTP does. I'll explain why in detail with this blog post.
HTTP provides a way to pass the host name in the headers that are passed between the client and server, but FTP currently does not provide this same functionality. Looking at one of my older blog posts, I pointed out that there are three ways that you can create unique bindings for a Web/HTTP site: IP address, port, or host header. Based on its current design, FTP can create unique bindings by IP address or port, but the FTP protocol currently does not allow for something like host headers.
Here's why - I'm sure most everyone is aware that HTTP packets consist of a set of headers and possibly a block of data. Here's an example of a simple GET request:
GET /default.aspx HTTP/1.0 [crlf]
Accept: */* [crlf]
[crlf]
When HTTP 1.1 was published in RFC 2068 and RFC 2616 it defined a header for specifying a "host" name in a separate name/value pair:
GET /default.aspx HTTP/1.1 [crlf]
Host: example.com [crlf]
Accept: */* [crlf]
[crlf]
This allows multiple virtual servers ("hosts") on the same IP address and port that are differentiated by host name. While this works great for the HTTP protocol, the FTP protocol currently has no comparable functionality. As such, the FTP protocol would have to be updated to allow multiple hosts on the same IP address and port, then IIS and all FTP clients would need to be updated to accommodate the changes to FTP.
I realize that most everyone is aware that when you attempt to connect to an HTTP or FTP server from a client, the client looks up the IP address using a name server and then creates a connection to the server by IP address. What many people may not realize is that the server is basically unaware of the host name that the client used - at connection time the server is really only concerned with inbound data on the IP address.
That being said, the connection protocol could provide a mechanism for specifying the host name. For example, as I mentioned above the HTTP/1.1 protocol provides a mechanism for specifying host names using a host header and FTP does not. In fact, if you were to open Network Monitor or similar tool and capture an FTP connection between a client and a server, you would be able to see that the host name is not passed as part of the FTP conversation between the client and server.
For the new FTP service for IIS7 we wanted to find a way to have host names in FTP, so we approached the situation with two possible ideas:
In the end, we chose to do both.
First of all we have "Virtual Host" names; this is the "ftp.example.com|username" syntax that led to the original question. Here's the way that this can be used in a hosting environment. Let's say that a web hoster has a customer with several Web/FTP sites that he needs to update. The web hoster gives all of his customers the same ftp address, like "ftp.example.com". When setting up the bindings for the Web/FTP sites the web hoster configures each site for the appropriate HTTP/FTP bindings, using host names like "www.contoso.com" & "www.fabrikam.com" for the HTTP bindings and "ftp.contoso.com" & "ftp.fabrikam.com" for FTP bindings. (All of the Web names would be set up in DNS, of course, but the FTP names are somewhat optional as I'll explain later.)
Since HTTP provides host headers to pass the host name, the Web client & Web server will both know which site they're working with. Since FTP doesn't have a built-in way to pass a host name, the customer will connect to the "ftp.example.com" name that his web hoster gave him and log in using the appropriate "ftp.contoso.com|customer" or "ftp.fabrikam.com|customer" syntax. The FTP service for IIS7 will then internally route the FTP activity to the correct site based on the FTP bindings. If the FTP names "ftp.contoso.com" & "ftp.fabrikam.com" were registered in DNS, the client would still need to specify the appropriate "ftp.contoso.com|customer" or "ftp.fabrikam.com|customer" syntax when logging in because the FTP activity did not actually pass the host name in any way.
The great thing about the "Virtual Host" names solution is that it is backwards-compatible because any client should be able to send the "ftp.example.com|username" syntax.
We also wanted to see if the FTP protocol could be updated to allow sending a host name as part of the FTP session like HTTP does. After some research I discovered that Robert Elz and Paul Hethmon had provided a detailed discussion of a "HOST" command for FTP in their Internet draft titled "Extensions to FTP" during their work with the FTPEXT Working Group at the IETF. I contacted the two of them and with their approval Paul and I submitted a new IETF draft detailing a HOST command for FTP, which is posted at the following URL:
http://www.ietf.org/internet-drafts/draft-hethmon-mcmurray-ftp-hosts-00.txt
Here's the way that the HOST command works: the FTP server and FTP client both need to know that the HOST command is supported. The FTP client connects to an FTP server using either a DNS name or IP address and sends a FEAT command and sees that HOST is supported, so the client sends "HOST ftp.example.com" before sending USER and PASS, which allows the FTP server to route the request to the correct FTP site based on the bindings. (An FTP client could skip the FEAT command completely and simply attempt a HOST command and process the FTP reply, but that's not the best approach.)
The FTP HOST command solution is not backwards-compatible, however, because an FTP client needs to be able to send the "HOST ftp.example.com" syntax. Some FTP clients allow sending custom commands, which enables this functionality. For example, if you are using the FTP.EXE command-line tool that comes in Windows, you can type "quote HOST ftp.example.com" when connecting to the new FTP server for IIS7 and it will route the request to the appropriate site. In an ideal world, FTP clients will start negotiating the HOST feature behind the scenes and you should never know that this is occurring, which is how almost all Web browsers currently work. (e.g. When you enter "www.example.com" in the address bar of a Web browser it will automatically add the host header to the HTTP request.)
So the long answer to the original question is that you have two ways of specifying a host with the new FTP service for IIS7:
So my thanks to Mickey Binder for his great question, and I hope this helps other people understand this concept a little better.
06 July 2007 • by Bob • FTP, Scripting
A few weeks ago my friend Jaroslav posted a blog entry about viewing the current FTP7 sessions using Javascript, and I followed that up with a blog post about viewing the current FTP7 sessions using VBScript.
This blog entry follows up on those postings by showing you how to view the current FTP7 sessions using C#. To do so, start a new Windows Console Application project using C# in Visual Studio 2005 on a computer running Windows Server 2008 with the new FTP7 server installed. You will need to add a reference to the AppHostAdminLibrary by manually browsing to the nativerd.dll file that's located in the %WinDir%\System32\InetSrv folder. After you've added the reference, replace all of the C# code from the project template with the following C# code:
using System; using System.Collections.Generic; using System.Text; using AppHostAdminLibrary; namespace FtpDumpSessions { class FtpDumpSessions { static void Main(string[] args) { AppHostWritableAdminManager objAdminManager = new AppHostWritableAdminManager(); // get the collection of sites IAppHostElement objSitesElement = objAdminManager.GetAdminSection( "system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST"); uint intSiteCount = objSitesElement.Collection.Count; Console.WriteLine( "Site count: {0}", intSiteCount); try { // loop through the sites collection for (int intSite = 0; intSite < intSiteCount; ++intSite) { // get a site IAppHostElement objFtpSite = objSitesElement.Collection[intSite]; // get the FTP section IAppHostElement objFtpSiteElement = objFtpSite.ChildElements["ftpServer"]; // get the sessions collection IAppHostElement objFtpSessions = objFtpSiteElement.ChildElements["sessions"]; uint intSessionCount = objFtpSessions.Collection.Count; Console.WriteLine( "\tFTP sessions for {0}: {1}", objFtpSite.Properties["name"].Value, intSessionCount); // loop through the sessions for (int intSession = 0; intSession < intSessionCount; ++intSession) { IAppHostElement objFtpSession = objFtpSessions.Collection[intSession]; // loop through each session's properties for (int intProperty = 0; intProperty < objFtpSession.Properties.Count; ++intProperty) { Console.WriteLine( "\t\t{0}: {1}", objFtpSession.Properties[intProperty].Name, objFtpSession.Properties[intProperty].Value); } } } } catch (System.Exception ex) { Console.WriteLine( "\r\nError: {0}", ex.Message); } } } }
When you compile and run the project, you should see a listing of all users connected to your FTP7 sites.
That's about it for this post - have fun!
06 July 2007 • by Bob • FTP, Scripting
A few weeks ago my friend Jaroslav posted a blog entry about viewing the current FTP7 sessions using Javascript, and I followed that up with a blog post about viewing the current FTP7 sessions using C#.
This blog entry follows up on those postings by showing you how to view the current FTP7 sessions using VBScript. To do so, copy the following VBScript code to Windows Notepad and save the file as "ftp_sessions.vbs" on a computer running Windows Server 2008 with the new FTP7 server installed:
Option Explicit Dim objAdminManager, objSiteCollection, objFtpSiteElement Dim objSite, objFtpSession, objFtpSessions, objFtpProperty Dim intSite, intFtpSession, intFtpProperty Dim intSiteCount, intFtpSessionCount, intFtpPropertyCount Set objAdminManager = WScript.CreateObject("Microsoft.ApplicationHost.AdminManager") ' get the collection of sites Set objSiteCollection = objAdminManager.GetAdminSection( _ "system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST" ) intSiteCount = CInt(objSiteCollection.Collection.Count) WScript.Echo String(40,"*") WScript.Echo "Site count: " & intSiteCount WScript.Echo String(40,"*") ' loop through the sites collection For intSite = 0 To intSiteCount-1 ' get a site Set objSite = objSiteCollection.Collection.Item(intSite) ' get the FTP section Set objFtpSiteElement = objSite.ChildElements.Item("ftpServer") ' get the sessions collection Set objFtpSessions = objFtpSiteElement.ChildElements.Item("sessions") intFtpSessionCount = CInt(objFtpSessions.Collection.Count) WScript.Echo String(40,"=") WScript.Echo "FTP sessions for " & _ objSite.Properties.Item("name").Value & _ ": " & intFtpSessionCount WScript.Echo String(40,"=") ' loop through the sessions For intFtpSession = 0 To intFtpSessionCount - 1 Set objFtpSession = objFtpSessions.Collection.Item(intFtpSession) intFtpPropertyCount = CInt(objFtpSession.Properties.Count) ' loop through each session's properties For intFtpProperty = 0 To intFtpPropertyCount - 1 Set objFtpProperty = objFtpSession.Properties.Item(intFtpProperty) WScript.Echo CStr(objFtpProperty.Name) & ": " & CStr(objFtpProperty.Value) Next WScript.Echo String(40,"-") Next Next
To make sure that you don't see any message box pop-ups, run the script from the command-line using the following syntax:
cscript.exe ftp_sessions.vbs
That's about it for this post - have fun!
11 May 2007 • by Bob • Scripting, MIDI
OK - I have to admit, when you realize that you are making software choices based on scripting language support you start to get the feeling that there are times when you just have to accept the fact that you are a geek.
Here's a case in point: I write music as a hobby, and when shopping for a program to write sheet music with, I chose Sibelius because I discovered that they have a really cool scripting language called "ManuScript". OK - so the name is kind of silly, but it's pretty cool to write code with.
The way it works is that you create what Sibelius calls a "plug-in", and you assign it to a category that will be used as the menu under which your plug-in will be displayed. Once you've done all that, you can start writing code.
For example, I needed to add sustain pedal MIDI events to an entire piano score, and doing so manually would have been a tedious exercise. So I made my life easier and created a quick plug-in that adds the MIDI events to apply the sustain pedal at full level to the beginning of every measure, and then adds the MIDI events to lift the sustain pedal at the end of every measure:
// Verify that a score is open. if (Sibelius.ScoreCount=0) { Sibelius.MessageBox("Please open a score."); return false; } // Retrieve a score object for the active score. score = Sibelius.ActiveScore; // Retrieve an object for the current selection. selection = score.Selection; if (selection.IsPassage) { // Loop through the highlighted measures. for each Bar b in selection { // Add MIDI sustain pedal events. b.AddText(1,"~C64,127",TechniqueTextStyle); b.AddText(b.Length,"~C64,0",TechniqueTextStyle); }
// Return a status message. Sibelius.MessageBox("Finished."); }
I should point out, however, that this is meant to be a brief example of what you can do. Running this same plug-in on the same selection will re-add the sustain pedal events to your score; I didn't add any advanced logic to check for the existence of any prior sustain pedal events. If anyone wants to take on that challenge, have fun and don't forget to share your results!
28 April 2007 • by Bob • FrontPage, IIS
Following up on my FrontPage Server Extensions on Vista and Longhorn blog post from last February, I'm happy to announce that Microsoft and Ready to Run Software have released the first beta version of the Microsoft FrontPage 2002 Server Extensions (FPSE 2002) for Windows Server Code Name "Longhorn" and Windows Vista.
The beta version of FPSE 2002 can be downloaded from the following URL:
Additional documentation about installing and using this version of FPSE 2002 can be found at the following URL:
It should be noted that this version of FPSE 2002 is a beta release and is therefore unsupported. Also, this version of FPSE 2002 introduces no new functionality; it is essentially the same version of FPSE 2002 that was created for Windows Server 2003 that has been updated to work on Windows Server Code Name "Longhorn" and Windows Vista. That being said, this version of FPSE 2002 will enable web hosters and developers to author their web content on servers or workstations that are running IIS 7.0 on Windows Server Code Name "Longhorn" and Windows Vista.
Feedback about this release can be sent to fpbeta@rtr.com.
26 April 2007 • by Bob • FTP, IIS
It's been a long time in development, but Microsoft has released a beta version of a new FTP service that we have completely rewritten for Windows Server code name "Longhorn". This new FTP service contains many great new features, such as:
There are way too many features to list in such a short space, so a good place for addtional information is the "What’s New for Microsoft and FTP?" article. I encourage you to download the beta version of the new FTP service today, and listed below are the links for the download pages for each of the individual installation packages:
After installing the new FTP server, the following walkthroughs on the www.iis.net web site should help get you started:
In closing, the beta version of this new FTP service has a lot to offer, and we've put a lot of time and effort into making what we think is a great start for the future of FTP for IIS. About the only piece of bad news that I have for anyone is that this new FTP service will not work on Windows Server 2003 with IIS 6.0.
All in all, our team is excited to see people start testing with this beta version. And lest I forget, my special thanks go to:
Thanks everyone!
08 February 2007 • by Bob • FrontPage, IIS
As most people that have installed IIS 7 on Windows Vista or Windows codenamed "Longhorn" have realized, there are no options to install the FrontPage Server Extensions, leaving the only possibly way to edit your web site that is hosted on a Vista/Longhorn computer is to edit the web site locally using the file system, or to use FTP to upload your files to a remote Vista/Longhorn computer.
The FrontPage Server Extensions (FPSE) 2002 are part of the Office XP system of products. The Office XP system, including FPSE 2002, left mainstream support on July 11th, 2005, according to the Office lifecycle policy. At that time, the FrontPage Server Extensions were removed from the Microsoft Download Center. Office policy is to remove software from the Download Center that is no longer supported. This policy allows us to focus our support efforts on the latest technologies. FPSE 2002 continues to be available on Windows Server 2003 in the Add Windows Components section of the Add/Remove Programs control panel.
FPSE 2002 will continue to be supported by security updates through the end of the extended support period, and all existing security content will remain available. For more information on the support lifecycle policy, see the Microsoft Lifecycle web page at the following URL:
http://support.microsoft.com/?pr=lifecycle
Because Microsoft realizes that the FrontPage Server Extensions are essential to many web hosting companies, the Internet Information Services product team is researching the development of an updated version of FPSE 2002 that will work with Microsoft Windows codenamed "Longhorn" and Microsoft Windows Vista.
04 January 2007 • by Bob • FrontPage
I had a bunch of FrontPage shortcuts lying around, so I thought that I should list them together in a single blog.
Much like inserting a hit counter on your web page, nothing screams "amateur" faster than using one of the built-in FrontPage themes or templates to design your web site. That being said, not all FrontPage themes and templates are bad - it's just that many of them are so awful that they give the rest of the market a bad name.
Personally, I have seen several professionally-designed templates that use FrontPage's Dynamic Web Templates (*.DWT) to construct the look and feel for some really great-looking web sites. It pays to be choosy, of course, and find the right theme/template that works for your target audience. With that in mind, I have several theme and template sites listed below.
For a large collection of non-FrontPage-specific templates, see the Open Source Web Design website at the following URL:
At one time there were a bunch of add-ins for FrontPage lying around on the Internet, but sadly those days are gone. Just the same, here are a few of the remaining links that contain Add-ins for FrontPage:
This is probably one of the most useful links for the FrontPage Server Extensions, but be forewarned - it's not an easy guide to follow:
The FrontPage SDKs are no longer available from Microsoft, so I have them mirrored here:
File Description | File Link | File Size |
---|---|---|
FrontPage 1.0 SDK | fpsdk10.zip | 3.25 mb |
FrontPage 1.1 SDK | fpsdk11.zip | 706.24 kb |
FrontPage 97 SDK | fpsdk20.zip | 1.04 mb |
FrontPage 98 SDK | fpsdk30.zip | 1.46 mb |
FrontPage 2000 SDK | fpsdk40.zip | 797.12 kb |
FrontPage 2002 SDK | fpsdk50.zip | 1.52 mb |
2025 UPDATE: This post was written several years ago, and many of the links were no longer there. However, during a review of old blogs, I updated the old URLs to use the Internet Archive, so the links in this blog appear to work as they did when the blog was first written.
02 January 2007 • by Bob • FrontPage, Scripting
As the old adage says, "Necessity is the mother of invention." With that in mind, I had a friend drop by my office the other day and ask me a question that started me on another quest for code.
What he asked me was whether there was a way where he could create an off-line backup of his web site. Of course, there are whole sections of the industry these days that are devoted to such things, but he wanted a simple way to create a backup on his home or work computer of his web site that is hosted at an ISP. Some time ago I wrote a FrontPage VBA macro for another friend that could be used to automate publishing, but only from within the FrontPage application itself. Since the FrontPage application exists as a COM object, I theorized that I could rewrite the code from the macro into a Windows Script Host (WSH) application that should do the trick. The code that you see below is the results of my little 'experiment'.
Usage Notes:
Once you have taken the above items into account, copy & paste the script code into Notepad and save it to your computer with a "*.vbs" file extension. To execute the code, just double-click the script. The script will pop-up a message box when it has finished publishing a copy of the web site to your computer.
Option Explicit ' -------------------------------------------------- ' ' Declare our constants. ' ' -------------------------------------------------- Const fpPublishAddToExistingWeb = 2 Const fpPublishCopySubwebs = 4 Const fpPublishLogInTempDir = 8 Const fpPublishCopyAllFiles = 64 ' -------------------------------------------------- ' ' This section defines the publishing variables. ' ' -------------------------------------------------- Dim strSourceUrl, strDestinationFolder Dim strUsername, strPassword Dim strBackupDate, strBackupTime strBackupDate = Cstr(Year(Date())) & _ Right("00" & Cstr(Month(Date())),2) & _ Right("00" & Cstr(Day(Date())),2) strBackupTime = Right("00" & Cstr(Hour(Time())),2) & _ Right("00" & Cstr(Minute(Time())),2) & _ Right("00" & Cstr(Second(Time())),2) strSourceUrl = "https://www.example.com/" strDestinationFolder = "c:\Backups\www.example.com\" & _ strBackupDate & "_" & strBackupTime strUsername = "server\administrator" strPassword = "Password1" ' -------------------------------------------------- ' ' This section checks to see if FrontPage is ' installed, and exits if it is not installed. ' ' -------------------------------------------------- ' wait 10 seconds to "debounce" the server WScript.Sleep 10000 ' get a FrontPage Application object Dim objFP: Set objFP = WScript.CreateObject("FrontPage.Application") ' exit if the object does not exist If Err.Number = -2147352567 Then WScript.Quit ' -------------------------------------------------- ' ' This section publishes the webs. ' ' -------------------------------------------------- ' sanitize the publishing path strDestinationFolder = CleanPath(strDestinationFolder) ' only continue the path can actually be created If MakePath(strDestinationFolder) = True Then ' open the root web on the source objFP.Webs.Open strSourceUrl, strUsername, strPassword ' publish the root web to the destination objFP.ActiveWeb.Publish strDestinationFolder, _ fpPublishAddToExistingWeb + fpPublishCopySubwebs + fpPublishCopyAllFiles + fpPublishLogInTempDir ' close the root web objFP.ActiveWeb.Close End If ' -------------------------------------------------- ' ' This section cleans up and exits. ' ' -------------------------------------------------- Set objFP = Nothing WScript.Quit ' ---------------------------------------- ' ' This function builds a path ' ' PASS: File path to construct ' RETURN: TRUE/FALSE for success/failure ' ' ---------------------------------------- Function MakePath(tmpText) On Error Resume Next Dim tx,ty,tz Dim tmpFSO Dim blnTempStatus Set tmpFSO = WScript.CreateObject("Scripting.FileSystemObject") blnTempStatus = True ty = Split(tmpText,"\") For tx = 0 To UBound(ty) tz = tz & ty(tx) & "\" If tmpFSO.FolderExists(tz) = False Then tmpFSO.CreateFolder(tz) If Err.Number <> 0 Then blnTempStatus = False End If Next MakePath = blnTempStatus End Function ' ---------------------------------------- ' ' This function sanitizes a path for valid characters ' ' PASS: File path to construct ' RETURN: New path ' ' ---------------------------------------- Function CleanPath(tmpText) On Error Resume Next Const tmpValid = "\.-1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" Dim tx,ty,tz For tx = 1 To Len(tmpText) ty = Mid(tmpText,tx,1) If (InStr(tmpValid,ty)>0) Or (tx=2 and ty=":") Then tz = tz & ty Else tz = tz & "_" End If Next CleanPath = tz End Function
Happy coding!
Note: This blog was originally posted at http://blogs.msdn.com/robert_mcmurray/
30 December 2006 • by Bob • Random Thoughts
2006 is rapidly coming to a close, and the new year is almost upon us. Before I go home for the weekend I wanted to wish everyone:
Happy New Year!
Gutes Neues Jahr!
Feliz Año Nuevo!
Bonne Année!
С Новым годом!