«
July 2006
»
The server committed a protocol violation
Tuesday 25 July
One of the issues involving XML-RPC.NET that turns up fairly frequently is when the library throws an instance of System.Net.WebException with the message ""The server committed a protocol violation". This usually occurs because from .NET 1.1 SP1 onwards the parsing of HTTP responses became much more strict, as a security measure to prevent attacks which exploit malformed HTTP status lines and headers. The strict behaviour can be switched off via the application config file:
<?xml version ="1.0"?>
<configuration>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true" />
</settings>
</system.net>
</configuration>
From .NET 2.0 this behaviour can be configured programmatically using the HttpWebRequestElement useUnsafeHeaderParsing property. At first when I read about this I assumed it was a property that can be set dynamically at runtime, for example in the same way as the HttpWebRequest KeepAlive property. But in fact its used in the new 2.0 configuration infrastructure to set the value in the config file (although once you do this the new value applies to the current running application as well as any apps launched afterwards. The new configuration infrastructure is pretty complex but this code seems to work ok:
Configuration config = ConfigurationManager.OpenExeConfiguration( ConfigurationUserLevel.None); SettingsSection section = (SettingsSection)config.GetSection( "system.net/settings"); section.HttpWebRequest.UseUnsafeHeaderParsing = false; config.Save();
ConfigurationUserLevel.None specifies that the configuration file in the same directory as the executable should be modified so this file has to be writable. The other options PerUserRoaming and PerUserRoamingAndLocal can be used in different scenarios.
Finally, I found the code below in a post on the .NET Framework Networking and Communication forum. This uses reflection to set the private field useUnsafeHeaderParsing to true and as a result may not be suitable in all scenarios where the relevant code access security permission is not available. (Note: add System.Configuration.dll as a reference to your project.)
public static bool SetAllowUnsafeHeaderParsing()
{
//Get the assembly that contains the internal class
Assembly aNetAssembly = Assembly.GetAssembly(
typeof(System.Net.Configuration.SettingsSection));
if (aNetAssembly != null)
{
//Use the assembly in order to get the internal type for
// the internal class
Type aSettingsType = aNetAssembly.GetType(
"System.Net.Configuration.SettingsSectionInternal");
if (aSettingsType != null)
{
//Use the internal static property to get an instance
// of the internal settings class. If the static instance
// isn't created allready the property will create it for us.
object anInstance = aSettingsType.InvokeMember("Section",
BindingFlags.Static | BindingFlags.GetProperty
| BindingFlags.NonPublic, null, null, new object[] { });
if (anInstance != null)
{
//Locate the private bool field that tells the
// framework is unsafe header parsing should be
// allowed or not
FieldInfo aUseUnsafeHeaderParsing = aSettingsType.GetField(
"useUnsafeHeaderParsing",
BindingFlags.NonPublic | BindingFlags.Instance);
if (aUseUnsafeHeaderParsing != null)
{
aUseUnsafeHeaderParsing.SetValue(anInstance, true);
return true;
}
}
}
}
return false;
}
Adding a File to the Compile ItemGroup
Saturday 22 July
I've finally got round to switching from NAnt to MSBuild for building XML-RPC.NET so I'm tentatively finding my way around MSBuild at the moment. One thing I wanted to do was to ensure that builds of the XML-RPC.NET assembly do not have a valid version number when built from within the Visual Studio IDE, so they don't get confused with proper builds. I use a file called AssemblyBuildNumber.cs, created during a build, to define the build number so I wanted to exclude that from builds within the IDE.
My first attempt was to add a condition to the entry for the file in the Compile item group in the project file:
<ItemGroup>
<Compile Include="AssemblyBuildNumber.cs"
Condition="'$(BuildingInsideVisualStudio)' == ''">
<SubType>Code</SubType>
</Compile>
...
However, although this works from a build point of view, it results in the file being flagged as missing in the IDE Solution Explorer window. So I found a way of adding the file to the Compile ItemGroup at build time by overriding the BeforeBuild target. If you look in the Microsoft.Common.Targets file (located in %windir%\Microsoft.NET\Framework\v2.0.50727) you can see that this target is defined solely for being overidden:
<!--
=====================================
BeforeBuild
Redefine this target in your project in order to run tasks just before Build
=====================================
-->
<Target Name="BeforeBuild"/>
In the overriding version of BeforeBuild I used the CreateItem task to add the required file to the Compile item group but only if the build is not from within the IDE:
<Target Name="BeforeBuild">
<CreateItem Include="AssemblyBuildNumber.cs"
Condition="'$(BuildingInsideVisualStudio)' == ''">
<Output TaskParameter="Include" ItemName="Compile"/>
</CreateItem>
</Target
Of course, I'm new to MSBuild and I may well be missing a blatantly obvious one-liner to do this. If there is, please email me and I'll post an update here.
The requested FTP command is not supported when using HTTP proxy
Tuesday 18 July
I was using the FtpUpload task from the MSBuild Community Tasks Project and after moving to a different machine started catching an InvalidOperationException with the message "The requested FTP command is not supported when using HTTP proxy". It turns out that only the RETR, LIST, and NLST methods are supported by System.Net. FtpWebRequest when a HTTP proxy is configured and it doesn't matter that you are not setting a proxy in your code: if a HTTP proxy (not FTP proxy) is configured in the system proxy settings (i.e. what you see in your Internet Explorer properties), then you will get this error when trying to upload to the FTP server.
The workaround is use IE to change the system settings to switch off the use of the HTTP proxy. However if you have access to the affected code the solution is to set the Proxy property of the request to null, for example:
WebRequest request = WebRequest.Create("ftp://myserver/foo");
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential("user", "pwd");
request.Proxy = null;
Stream requestStream = request.GetRequestStream();
// ...
New Release of XML-RPC.NET
Thursday 13 July
FYI there is a new release of XML-RPC.NET available.
This release fixes the problem I mentioned a couple of weeks ago whereby ASP.NET applications running under medium trust were experiencing VerificationExceptions ("Operation could destabilize the runtime") when using XML-RPC.NET. I build a version with all switch statements containing more than a handful of conditions replaced by if-else statements and Kevin Harder at Telligent verified that this fixed the problem. This makes it possible to continue with a single build of the assembly which works on all versions of the .NET runtime.
Postel's Robustness Principle Revisited
Tuesday 4 July
Right now I'm fixing some code, originally written by someone long departed from our development group, which decodes encoded words in email message headers. Encoded words makes it possible to include non-ASCII text in headers. This sample contains two encoded words:
Subject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=
=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=
The three parts of an encoded word are character set, encoding (base64 or printed quotable), and encoded text, defined in RFC 2047. The RFC defines various restrictions on how you can use encoded words, for example:
- An 'encoded word' may not be more that 75 characters long.
- ... unencoded white space characters (such as SPACE and HTAB) are FORBIDDEN within an 'encoded word'.
- ... an 'encoded word' that appears in a header field defined as '*text' MUST be separated from any adjacent 'encoded word' or 'text' by 'linear-white-space'.
- A multi-octet character may not be split across adjacent 'encoded word's.
And so on. Unfortunately many mail agents do not use encoded words correctly even though the RFC is reasonably clear. However we can't reject invalid encoded words because end-users would blame our software, not the originating mail agents, if they hear garbled message subjects being voiced via text-to-speech. So although we always use encoded words correctly when sending messages we accept incorrect usage of encoded words when decoding them. You might think that this is an application of the often quoted Postel Robustness Principle, as described in RFC 793:
2.10. Robustness Principle
TCP implementations will follow a general principle of robustness: be conservative in what you do, be liberal in what you accept from others.
I thought the same until yesterday until I came across an archived message from Mark Crispin:
![]()
This statement is based upon a terrible misunderstand of Postel's robustness principle. I knew Jon Postel. He was quite unhappy with how his robustness principle was abused to cover up non-compliant behavior, and to criticize compliant software.
Jon's principle could perhaps be more accurately stated as "in general, only a subset of a protocol is actually used in real life. So, you should be conservative and only generate that subset. However, you should also be liberal and accept everything that the protocol permits, even if it appears that nobody will ever use it."
So the next time that someone uses the Robustness Principle to argue that your code should accept any old rubbish as input, you can point out what Postel really meant.
Outsourcing Lowers Expectations?
Monday 3 July
James Robertson discusses a rather provocatively titled piece by James McGovern which describes an anecdote about how outsourcing lowers expectations for individual consultant productivity
Perhaps this lowering of expectations applies to in-house developers and not just consultants. After all what would happen if when taking on permanent staff you gave your recruiting agency a job description and then simply accepted the developers they sent you without interviewing or selecting them in any way. It would be inevitable that you'd end up with people who would never have got the job in the normal course of events, for example because of over-inflated claims of experience and technical knowledge, or just general incompetence. Then what would happen to expectations as you follow this opposite to the Lake Wobegon hiring strategy? Surely within a short period of time your development group would be working at a lower level of productivity and quality, not just because the average level of skill has dropped but because of the viscous drag of ineptitude the newcomers will exert on your more competent developers?
So why won't this happen with outsourcing? You won't have any choice over the developers working for you. You might strike it lucky, you might not. The chances are you'll end up with developers with less experience and competence than you're expecting. With time they may well come up to speed on the sort of work you do but then you find they're been transferred onto some other project the outsourcing company has signed up for and you're back to square one with a new bunch of developers. Even at a distance your own developers will be affected because they will have to spend a lot of time sorting out issues which the external developers can't handle. You may even end up with the bizarre scenario where your developers all but stop doing any new work because they spend most of their time helping out the external developers, or fixing bugs because the external developers don't know enough about the product to fix them. And so you reduce the level of expectation that your own developers can write new code. It's not difficult to imagine how demotivating this can be for those developers.
One final point: the anecdotal and personal evidence I have on this is that it is nothing to do with where in the world work is outsourced to; it is fundamentally related to the nature of outsourcing.