HTTP Trace was never so easy

So there I was, sitting at my PC hunting some bugs when up pops John Sheehan on IM and starts asking me questions about OPTIONS and TRACE http methods.  I pretty much always have the HTTP spec close at hand so I think I was able to at least fake some prior knowledge in attempting to answer his questions.  As the discussion continued it started to pique my interest in TRACE.  I have been meaning to look into this this obscure HTTP method for some time but have just never got around to it.

The naive explanation to TRACE is as follows.  When you make a TRACE request to a server it returns a response with the content type message/http and copy of the http headers that were sent  in the request.  You don’t ever send a body with a TRACE method, it is really just for looking at headers.  So the obvious question is why on earth would you want the server to return back to you exactly what you just sent.  Seems kind of useless considering we have tools like fiddler that will show you exactly what you sent in your request.  TRACE only really becomes interesting when there are intermediaries between you and your server.

One of the most powerful aspects of HTTP is the fact that it enables a layered architecture where a variety of machines can sit in-between the client and the origin server and interact with the request in a variety of ways.  It is this layering capability that allows caches and proxies and load balancers to be inserted transparently between the client and the server.  However, sometimes these intermediaries may also be a source of problems if they modify your request in some way.  TRACE lets you see what intermediaries are doing to your request.

With the new WCF Web API and also with other architectures like RACK and WSGI, the concept of intermediary becomes even more relevant.  In WCF Web API there is a component called a HttpMessageHandler which can act just like any other HTTP intermediary, except it is running in the same process as your service.  It accepts a HTTP request, forwards it along and eventually receives the response and then returns it.  During both the request and response phase, the HttpMessageHandler can manipulate the request.  It is also possible to “layer” these HttpMessageHandlers so that you can compose a variety of different behaviours.

With the TRACE method, we potentially have a way of seeing what the HttpMessageHandlers are doing to the request.  If you are writing the server, then you can just debug the server and trace through, but what if you are only a client author, or what if you need to debug a deployed production server.  TRACE allows you to “debug” those layers of intermediaries without direct access to the server.

To test this theory I decided to try an implement the TRACE method.  Interestingly, in the WCF Web API framework, by placing a Trace HttpMessageHandler as the last layer it is possible to echo back the results of all the prior intermediaries.

This the class that I created:

    public class TraceMessageHandler : DelegatingChannel {
        public TraceMessageHandler(HttpMessageChannel innerChannel) : base(innerChannel) {
        }

        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {

                   if (request.Method == HttpMethod.Trace) {
                       return Task<HttpResponseMessage>.Factory.StartNew(
                           () => {
                               var response = new HttpResponseMessage(HttpStatusCode.OK, "OK");
                               response.Content = new StringContent(request.ToString(), Encoding.UTF8, "message/http");
                               return response;
                           });
                    }
 
                    return base.SendAsync(request, cancellationToken);
        }
    }

This class simply checks if the HTTP method is TRACE, if not it passes the request along.  If it is a TRACE, it creates a new response object and returns the results of request.ToString() in a StringContent object.   The format of the text returned from ToString() is not the format of a regular HTTP request, but it does provide all the information that is sent in the request.

The TraceMessageHandler can be attached to a service host configuration simply by doing the following,

var config = HttpHostConfiguration.Create()
                .AddMessageHandlers(new [] { typeof(TraceMessageHandler)});

Hopefully now that I have an easy way to implement the TRACE method I might be able to start identifying specific scenarios where TRACE can be useful.  I will probably also add this message handler to the WCF Web API contrib project.

No Comments

Add a Comment

comments powered by Disqus