views:

567

answers:

2

I am trying to make an Http POST to an Apache web server.

I am finding that setting ContentLength seems to be required for the request to work.

I would rather create an XmlWriter directly from GetRequestStream() and set SendChunked to true, but the request hangs indefinitely when doing so.

Here is how my request is created:

    private HttpWebRequest MakeRequest(string url, string method)
    {
        HttpWebRequest request = HttpWebRequest.Create(url) as HttpWebRequest;
        request.Method = method;
        request.Timeout = Timeout; //Property in my class, assume it's 10000
        request.ContentType = "text/xml"; //I am only writing xml with XmlWriter
        if (method != WebRequestMethods.Http.Get)
        {
            request.SendChunked = true;
        }
        return request;
    }

How can I make SendChunked work so I do not have to set ContentLength? I do not see a reason to store the XmlWriter's string somewhere before sending it to the server.

EDIT: Here is my code causing the problem:

    using (Stream stream = webRequest.GetRequestStream())
    {
        using (XmlWriter writer = XmlWriter.Create(stream, XmlTags.Settings))
        {
            Generator.WriteXml<TRequest>(request, writer);
        }
    }

Before I did not have a using on the Stream object returned from GetRequestStream(), I assumed XmlWriter closed the stream when disposed, but this is not the case.

One of the answers below, let me to this. I'll mark them as the answer.

As far as HttpWebRequest is concerned, my original code works just fine.

+2  A: 

This should work the way you have it written. Can we see the code that actually does the uploading? Are you remembering to close the stream?

Aaronaught
My XmlWriter is in a using block, and it merely writes some elements and attributes with some looping. It calls WriteEndDocument to end the document. I am beginning to wonder if it's the server and not .Net, but I do not have a windows server to test with, although the version of Apache is pretty new.
Jonathan.Peppers
`WriteEndDocument` does not actually close the stream. Somewhere in your code, you are invoking `GetRequestStream` (or `BeginGetRequestStream`); once you are finished writing your XML, you need to invoke the `Close` method on that `Stream` instance. If you don't, it won't know when you're finished uploading and the connection will sit open forever.
Aaronaught
You are `using` the `XmlWriter`, which will dispose the `XmlWriter` and only the `XmlWriter`. It is the **Stream** that you need to call `Dispose` on (or `Close`, which is the recommended method). `XmlWriter` will not do this for you.
Aaronaught
+1  A: 
Cory Charlton
That would violate the HTTP 1.1 spec. It's not clearly documented, but you definitely do not have to set the `ContentLength` property when you use `SendChunked = true`. One setting replaces the other.
Aaronaught
http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4"If a message is received with both a Transfer-Encoding header field and a Content-Length header field, the latter MUST be ignored."So it's permitted according to the RFC, but it doesn't mean it's supported by the application receiving the POST.The easy way is to get the length and set it, but what fun would that be :) It's always fun to explore optimized solutions.
Mikael Svenson
Well, the application receiving the POST is Apache, as noted in the original question. Unless it's a very, very old version of Apache, it will support chunked encoding.
Aaronaught
Maybe I'm missing something but I don't see him setting a Transfer-Encoding value in his example. Also we're not really discussing the HTTP spec but rather the HttpRequest .NET object and how it functions. It's very possible the HttpRequest object requires parameters that would violate a spec in order to function propertly and then crafts a request that is up to spec. I'll look at the HttpRequest class and see what I find.
Cory Charlton
Setting `SendChunked` to `true` sets `Transfer-Encoding: chunked` in the HTTP headers. They are one and the same. If a value were required for `ContentLength` then it would defeat the purpose of the `SendChunked` property. Either he's leaving the stream open or it's the server that's broken.
Aaronaught
@Aaron: My edited post has an example to show this is not the case, at least not in the `TransferEncoding` property. Setting `SendChunked` = `true` still has an empty `TransferEncoding` value. Whether this is true when the actual request is sent I cannot say.
Cory Charlton
@Aaron: It's not true when the request is build, you are correct.
Cory Charlton
I feel like we are off topic, how do I make SendChunked work? If the answer is: you can't, then I'll move on.
Jonathan.Peppers