A POX on Us, Redux

Last week I announced a newly introduced bug in our newly introduced REST support that was causing some pain to this scenario.  I thought it was worthwhile to go into a little more detail about what the bug was and how it happened.

In previous versions of WCF, we had a setting for the HTTP transport to promote interoperability between systems that used WS-Addressing and systems that didn't.  The setting was a boolean called MapAddressingHeadersToHttpHeaders.  If you turned this setting on, we would start converting between using wsa headers and putting the equivalent information into the HTTP layer.  In particular, we'd map the wsa:To header to the HTTP Request URI.

In the latest release of WCF, we repurposed MapAddressingHeadersToHttpHeaders to make REST easier.  For normal SOAP messages, it's really not a valid scenario to be sending around messages with an empty body, so we convert those to null.  However, when you're programming to the HTTP layer, you might be able to convey some meaning with just header information, such as the status code.  In that case, you might not have a message body to send.  As we saw in the Message class yesterday though, things like the status live in a properties object that hangs off of the message itself.  If you get a null message back, you're out of luck.

We turned MapAddressingHeadersToHttpHeaders into the enumeration HttpMappingMode to solve the problem.  The name changed because this setting is more than about addressing now, and the boolean became an enumeration because we need a third choice to indicate whether your messages are going to be SOAP or POX.  The normal case became HttpMappingMode.SoapWithWSAddressing.  The case where we do address mapping became HttpMappingMode.Soap.  And, the POX case where we send through messages even if they have no body became HttpMappingMode.AnyXml.  There were two problems with this.

The first problem is that the release documentation just talked about the new AnyXml mode and didn't explain where MapAddressingHeadersToHttpHeaders went.  This was actually my fault.  I was evidently so excited about this new feature that I missed that little detail.  I've already updated the documentation for when we make future releases.

The second problem is that using HttpMappingMode.AnyXml on the server side is broken.  This happened because of the way we turned the boolean into an enumeration.  A boolean indicates two possible meanings, say A and B.  Testing if the boolean indicates A is the same as testing if the boolean does not indicate B.  When we have three meanings, A, B, and C, this doesn't work any more.  We had a test in the mapping of the addressing header that checked for HttpMappingMode.Soap when really we meant to check for anything except HttpMappingMode.SoapWithWSAddressing.  You can see how this came from the straight translation of the boolean test.  The result is that the address gets mangled for HttpMappingMode.AnyXml, and it's essentially impossible to reach the server.  As mentioned before, the workaround for now is to use HttpMappingMode.Soap on the server side.

Next time: Making Sense of Transport Quotas