views:

1051

answers:

2

I'm in a tough situation in which a Java web service endpoint hosted on an IBM HTTP Server (IHS) requires a Content-Length header, although it supposedly conforms to HTTP/1.1. If I send the header, everything works. If I leave it off, I get a 500 error response informing me that my POST entity body was empty (even though it was not).

We've invested significant time into our WCF client for these services (developed by a third party) and I can't seem to find a good way to append a Content-Length header to the request. I am able to add arbitrary headers (i.e. X-Dan-Lynn-Header) to the request using an IClientMessageInspector as described in blog posts like this, but WCF seems to ignore a Content-Length header.

My options are:

a) figure out how to force WCF to append a Content-Length header to the HTTP POST request or,

b) find or write an extremely simple-yet-transparent HTTP proxy that decorates the request with a Content-Length header.

Thanks!

Sample IClientMessageInspector.BeforeSendRequest:


public object BeforeSendRequest(ref Message request, IClientChannel channel)
{
    var buffer = request.CreateBufferedCopy(Int32.MaxValue);
    var tempRequest = buffer.CreateMessage();


    HttpRequestMessageProperty httpRequest = GetHttpRequestProp(tempRequest);
    if (httpRequest != null)
    {
        if (string.IsNullOrEmpty(httpRequest.Headers[HttpRequestHeader.ContentLength]))
        {
            httpRequest.Headers.Add(HttpRequestHeader.ContentLength, GetMessageLength(buffer).ToString());
            httpRequest.Headers.Add("X-Dan-Lynn-Header", "abcdefghijk");
        }

    }

    request = tempRequest;
    request.Properties[HttpRequestMessageProperty.Name] = httpRequest;

    return null;
}

Sample request generated by WCF (and the preceding IClientMessageInspector):

POST /path/to/service HTTP/1.1
Content-Type: text/xml; charset=utf-8
X-Dan-Lynn-Header: abcdefghijk
SOAPAction: "http://tempuri.org/path/to/service/action"
Host: service.host.tld
Transfer-Encoding: chunked
Connection: Keep-Alive


<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"&gt;
    <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"&gt;
        .......body removed for clarity......

    </s:Body>
</s:Envelope>
A: 

I am not currently able to actually try to run the code to see what happens but something like

WCFClient client = new WCFClient();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))    
{     
    HttpRequestMessageProperty req = new HttpRequestMessageProperty();            
    req.Headers.Add("Content-Length", "YOUR CONTENT LENGTH HERE");      
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = req;      
}

see http://msdn.microsoft.com/en-us/library/aa395196.aspx for more information on how you can use the OperationContextScope object to include additional headers.

update: I do have to say I find this a strange issue. I wonder why the content length isn't being set. I wouldn't be surprissed if your actual problem is somewhere else.

olle
+2  A: 

Figured it out. Setting the binding to use transferMode="Streamed" was causing a Transfer-Encoding: chunked. We needed streamed transfers due to very large responses from the web service, so I was able to go with:

Bad:

transferMode="Streamed"

Good:

transferMode="StreamedResponse"

Changing the binding to this solved the problem:

<basicHttpBinding>
    <binding name="MyBinding" closeTimeout="00:30:00" openTimeout="00:30:00"
      receiveTimeout="00:30:00" sendTimeout="00:30:00" allowCookies="false"
      bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
      maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="16777216"
      messageEncoding="Text" textEncoding="utf-8" transferMode="StreamedResponse"
      useDefaultWebProxy="false">
      <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="65536"
        maxBytesPerRead="4096" maxNameTableCharCount="16384" />
      <security mode="None" />
    </binding>
  </basicHttpBinding>
Dan Lynn
thanks for sharing your solution - but could you explain what about this binding you changed? Did you change to "basicHttpBinding"? From what? Just interested to document these things for other folks who might run into the same (or similar) problems!
marc_s
I was using basicHttpBinding from the onset, but it was previously set to transferMode="Streamed". This causes the binding to treat both requests and responses as streamd (aka chunked). The IBM HTTP Server configuration was throwing errors for a chunked Transfer-Encoding
Dan Lynn