/// <summary>Send the given request over the given connection.</summary>
        /// <remarks>
        /// Send the given request over the given connection.
        /// <p>
        /// This method also handles the expect-continue handshake if necessary.
        /// If it does not have to handle an expect-continue handshake, it will
        /// not use the connection for reading or anything else that depends on
        /// data coming in over the connection.
        /// </remarks>
        /// <param name="request">
        /// the request to send, already
        /// <see cref="PreProcess(Org.Apache.Http.IHttpRequest, HttpProcessor, HttpContext)">preprocessed
        ///     </see>
        /// </param>
        /// <param name="conn">
        /// the connection over which to send the request,
        /// already established
        /// </param>
        /// <param name="context">the context for sending the request</param>
        /// <returns>
        /// a terminal response received as part of an expect-continue
        /// handshake, or
        /// <code>null</code> if the expect-continue handshake is not used
        /// </returns>
        /// <exception cref="System.IO.IOException">in case of an I/O error.</exception>
        /// <exception cref="Org.Apache.Http.HttpException">
        /// in case of HTTP protocol violation or a processing
        /// problem.
        /// </exception>
        protected internal virtual HttpResponse DoSendRequest(IHttpRequest request, HttpClientConnection
                                                              conn, HttpContext context)
        {
            Args.NotNull(request, "HTTP request");
            Args.NotNull(conn, "Client connection");
            Args.NotNull(context, "HTTP context");
            HttpResponse response = null;

            context.SetAttribute(HttpCoreContext.HttpConnection, conn);
            context.SetAttribute(HttpCoreContext.HttpReqSent, false);
            conn.SendRequestHeader(request);
            if (request is HttpEntityEnclosingRequest)
            {
                // Check for expect-continue handshake. We have to flush the
                // headers and wait for an 100-continue response to handle it.
                // If we get a different response, we must not send the entity.
                bool            sendentity = true;
                ProtocolVersion ver        = request.GetRequestLine().GetProtocolVersion();
                if (((HttpEntityEnclosingRequest)request).ExpectContinue() && !ver.LessEquals(HttpVersion
                                                                                              .Http10))
                {
                    conn.Flush();
                    // As suggested by RFC 2616 section 8.2.3, we don't wait for a
                    // 100-continue response forever. On timeout, send the entity.
                    if (conn.IsResponseAvailable(this.waitForContinue))
                    {
                        response = conn.ReceiveResponseHeader();
                        if (CanResponseHaveBody(request, response))
                        {
                            conn.ReceiveResponseEntity(response);
                        }
                        int status = response.GetStatusLine().GetStatusCode();
                        if (status < 200)
                        {
                            if (status != HttpStatus.ScContinue)
                            {
                                throw new ProtocolException("Unexpected response: " + response.GetStatusLine());
                            }
                            // discard 100-continue
                            response = null;
                        }
                        else
                        {
                            sendentity = false;
                        }
                    }
                }
                if (sendentity)
                {
                    conn.SendRequestEntity((HttpEntityEnclosingRequest)request);
                }
            }
            conn.Flush();
            context.SetAttribute(HttpCoreContext.HttpReqSent, true);
            return(response);
        }
        /// <summary>Waits for and receives a response.</summary>
        /// <remarks>
        /// Waits for and receives a response.
        /// This method will automatically ignore intermediate responses
        /// with status code 1xx.
        /// </remarks>
        /// <param name="request">the request for which to obtain the response</param>
        /// <param name="conn">the connection over which the request was sent</param>
        /// <param name="context">the context for receiving the response</param>
        /// <returns>the terminal response, not yet post-processed</returns>
        /// <exception cref="System.IO.IOException">in case of an I/O error.</exception>
        /// <exception cref="Org.Apache.Http.HttpException">
        /// in case of HTTP protocol violation or a processing
        /// problem.
        /// </exception>
        protected internal virtual HttpResponse DoReceiveResponse(IHttpRequest request, HttpClientConnection
                                                                  conn, HttpContext context)
        {
            Args.NotNull(request, "HTTP request");
            Args.NotNull(conn, "Client connection");
            Args.NotNull(context, "HTTP context");
            HttpResponse response   = null;
            int          statusCode = 0;

            while (response == null || statusCode < HttpStatus.ScOk)
            {
                response = conn.ReceiveResponseHeader();
                if (CanResponseHaveBody(request, response))
                {
                    conn.ReceiveResponseEntity(response);
                }
                statusCode = response.GetStatusLine().GetStatusCode();
            }
            // while intermediate response
            return(response);
        }