// *** Public API ***
 public AgentDocument PerformAction(AgentSession session, AgentAction action)
 {
     return(PerformAction(session, action, 0));
 }
        public AgentDocument PerformAction(AgentSession session, AgentAction action, int timeout)
        {
            AgentDocument document = null;

            // these resources must be released if any exceptions occur
            HttpWebRequest  actionRequest  = null;
            StreamWriter    paramWriter    = null;
            HttpWebResponse actionResponse = null;
            Stream          responseStream = null;

            try
            {
                // set up the request and its headers
                actionRequest = (HttpWebRequest)WebRequest.Create(new Uri(action.WebURL));

                if (action.Referer != null && action.Referer.Length > 0)
                {
                    actionRequest.Referer = action.Referer;
                }

                if (action.IsPost)
                {
                    actionRequest.Method = "POST";
                }
                else
                {
                    actionRequest.Method = "GET";
                }

                actionRequest.ContentType       = "application/x-www-form-urlencoded";
                actionRequest.UserAgent         = "Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1";
                actionRequest.Accept            = "text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,video/x-mng,image/png,image/jpeg,image/gif;q=0.2,*/*;q=0.1";
                actionRequest.AllowAutoRedirect = action.AllowRedirect;
                actionRequest.KeepAlive         = false;         // true;

                if (timeout > 0)
                {
                    actionRequest.Timeout = timeout;
                }

                actionRequest.Headers.Add("Accept-Language", "en-us,en;q=0.5");
                actionRequest.ProtocolVersion = new Version(action.Version);

                actionRequest.CookieContainer = session.Cookies;

                if (action.IsPost)
                {
                    string content = "";

                    foreach (string key in action.ElementKeyOrder)
                    {
                        string requestValue = HttpUtility.UrlEncode((string)action.Elements[key]);
                        content += key + "=" + requestValue + "&";
                    }

                    if (content.Length > 0)
                    {
                        content = content.Substring(0, content.Length - 1);
                    }

                    paramWriter = new StreamWriter(actionRequest.GetRequestStream());
                    paramWriter.Write(content);
                    paramWriter.Flush();
                    paramWriter.Close();
                }

                document = new AgentDocument();

                actionResponse = (HttpWebResponse)actionRequest.GetResponse();

                document.RedirectUri = actionResponse.GetResponseHeader("Location");

                responseStream = actionResponse.GetResponseStream();
                StringWriter responseBuilder = new StringWriter();

                // now this looks less efficient than using a StreamReader (and it probably is), but at least this
                // doesn't result in huge memory leaks.  the stream reader class bears investiation!
                byte[] buffer = new byte[1024];
                int    n;

                try
                {
                    do
                    {
                        n = responseStream.Read(buffer, 0, buffer.Length);

                        char[] charBuffer = new char[buffer.Length];
                        for (int i = 0; i < buffer.Length; i++)
                        {
                            charBuffer[i] = (char)buffer[i];
                        }

                        responseBuilder.Write(charBuffer, 0, n);
                    } while (n > 0);
                }
                catch (Exception ex)
                {
                    Logger.Instance.Error(action.WebURL, ex);
                }

                document.ResponseString = responseBuilder.GetStringBuilder().ToString();
                responseBuilder.Close();

                // new logging thing


                if (DoLogging)
                {
                    Logger.Instance.Debug("In: " + action + "\n-------\nOut: " + document);
                }

                document.Uri = actionResponse.ResponseUri.ToString();
            }
            catch (Exception ex)
            {
                if (DoLogging)
                {
                    Logger.Instance.Error("In: " + action + "\n-------\nOut: " + document, ex);
                }

                throw ex;
            }
            finally
            {
                try
                {
                    if (paramWriter != null)
                    {
                        paramWriter.Close();
                    }
                }
                catch
                {
                }
                try
                {
                    if (responseStream != null)
                    {
                        responseStream.Close();
                    }
                }
                catch
                {
                }
                try
                {
                    if (actionResponse != null)
                    {
                        actionResponse.Close();
                    }
                }
                catch
                {
                }
            }

            return(document);
        }