Business Logic Toolkit for .NET
www.bltoolkit.net
|  Home   |  Download   |  Documentation   |  Discussions   |  License   |

  Source.Net.HttpReader.cs

 
/*
 * File:    HttpReader.cs
 * Created: 01/17/2003
 * Author:  Igor Tkachev
 *          mailto:it@rsdn.ru
 */

using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Text;
using System.Security.Cryptography.X509Certificates;
using System.Collections.Generic;

namespace BLToolkit.Net
{
    public delegate void ProcessStream(Stream stream);

    /// <summary>
    /// Encapsulates WebReader functions.
    /// </summary>
    public class HttpReader
    {
        #region Costructors

        public HttpReader()
        {
        }

        public HttpReader(string baseUri)
        {
            BaseUri = baseUri;
        }

        #endregion

        #region Public Properties

        private X509Certificate _certificate;
        public  X509Certificate  Certificate
        {
            get { return _certificate;  }
            set { _certificate = value; }
        }

        private string _baseUri;
        public  string  BaseUri
        {
            get { return _baseUri;  }
            set { _baseUri = value; }
        }

        private string _previousUri;
        public  string  PreviousUri
        {
            get { return _previousUri;  }
            set { _previousUri = value; }
        }

        private CookieContainer _cookieContainer = new CookieContainer();
        public  CookieContainer  CookieContainer
        {
            get { return _cookieContainer;  }
            set { _cookieContainer = value; }
        }

        private string _userAgent = @"HttpReader";
        public  string  UserAgent
        {
            get { return _userAgent;  }
            set { _userAgent = value; }
        }

        private string _accept =
            @"image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, */*";
        public  string  Accept
        {
            get { return _accept;  }
            set { _accept = value; }
        }

        private Uri _requestUri;
        public  Uri  RequestUri
        {
            get { return _requestUri;  }
            set { _requestUri = value; }
        }

        private string _contentType = string.Empty;
        public  string  ContentType
        {
            get { return _contentType;  }
            set { _contentType = value; }
        }

        private IWebProxy _proxy = new WebProxy();
        public  IWebProxy  Proxy
        {
            get { return _proxy;  }
            set { _proxy = value; }
        }

        private ICredentials _credentials = CredentialCache.DefaultCredentials;
        public  ICredentials  Credentials
        {
            get { return _credentials;  }
            set { _credentials = value; }
        }

        private string _html;
        public  string  Html
        {
            get { return _html; }
        }

        private readonly Hashtable _headers = new Hashtable();
        public           Hashtable  Headers
        {
            get { return _headers; }
        }

        private string _location;
        public  string  Location
        {
            get { return _location; }
        }

        private bool _sendReferer = true;
        public  bool  SendReferer
        {
            get { return _sendReferer;  }
            set { _sendReferer = value; }
        }

        private HttpStatusCode _statusCode;
        public  HttpStatusCode  StatusCode
        {
            get { return _statusCode; }
        }

        private int _timeout;
        public  int  Timeout
        {
            get { return _timeout;  }
            set { _timeout = value; }
        }

        #endregion

        #region Public Methods

        public void LoadCertificate(string fileName)
        {
            Certificate = X509Certificate.CreateFromCertFile(fileName);
        }

        #endregion

        #region Request Methods

        private HttpWebRequest PrepareRequest(string method, string requestUri, ProcessStream requestStreamProcessor)
        {
            _html = "";

            string uri = BaseUri;
            
            if (method != "SOAP")
                uri += requestUri;

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);

            if (Proxy       != null) request.Proxy       = Proxy;
            if (Credentials != null) request.Credentials = Credentials;

            request.CookieContainer = CookieContainer;
            request.UserAgent       = UserAgent;
            request.Accept          = Accept;
            request.Method          = method == "SOAP"? "POST" : method;
            request.KeepAlive       = true;

            if (SendReferer)
                request.Referer = PreviousUri ?? uri;

            foreach (string key in Headers.Keys)
                request.Headers.Add(key, Headers[key].ToString());

            if (method == "POST")
            {
                request.ContentType       = "application/x-www-form-urlencoded";
                request.AllowAutoRedirect = false;
            }
            else if (method == "SOAP")
            {
                request.ContentType       = "text/xml; charset=utf-8";
                request.AllowAutoRedirect = false;

                request.Headers.Add("SOAPAction", requestUri);
            }
            else
            {
                request.ContentType       = ContentType;
                request.AllowAutoRedirect = true;
            }

            PreviousUri = uri;
            RequestUri  = request.RequestUri;

            if (Certificate != null)
                request.ClientCertificates.Add(Certificate);

            if (Timeout != 0)
                request.Timeout = Timeout;

            if (requestStreamProcessor != null)
                using (Stream st = request.GetRequestStream())
                    requestStreamProcessor(st);

            return request;
        }

        public HttpStatusCode Request(
            string        requestUri,
            string        method,
            ProcessStream requestStreamProcessor,
            ProcessStream responseStreamProcessor)
        {
            HttpWebRequest request = PrepareRequest(method, requestUri, requestStreamProcessor);

            using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
            using (Stream          sm   = resp.GetResponseStream())
            {
                _statusCode = resp.StatusCode;
                _location   = resp.Headers["Location"];

                if (resp.ResponseUri.AbsoluteUri.StartsWith(BaseUri) == false)
                    BaseUri = resp.ResponseUri.Scheme + "://" + resp.ResponseUri.Host;

                CookieCollection cc = request.CookieContainer.GetCookies(request.RequestUri);

                // This code fixes the situation when a server sets a cookie without the 'path'.
                // IE takes this as the root ('/') value,
                // the HttpWebRequest class as the RequestUri.AbsolutePath value.
                //
                foreach (Cookie c in cc)
                    if (c.Path == request.RequestUri.AbsolutePath)
                        CookieContainer.Add(new Cookie(c.Name, c.Value, "/", c.Domain));

                if (responseStreamProcessor != null)
                    responseStreamProcessor(sm);
            }

            return StatusCode;
        }

        public IEnumerable<string> Request(
            string        requestUri,
            string        method,
            ProcessStream requestStreamProcessor)
        {
            HttpWebRequest request = PrepareRequest(method, requestUri, requestStreamProcessor);

            using (HttpWebResponse resp = (HttpWebResponse)request.GetResponse())
            using (Stream          sm   = resp.GetResponseStream())
            using (StreamReader    sr   = new StreamReader(sm, Encoding.Default))
            {
                _statusCode = resp.StatusCode;
                _location   = resp.Headers["Location"];

                if (resp.ResponseUri.AbsoluteUri.StartsWith(BaseUri) == false)
                    BaseUri = resp.ResponseUri.Scheme + "://" + resp.ResponseUri.Host;

                CookieCollection cc = request.CookieContainer.GetCookies(request.RequestUri);

                // This code fixes the case when a server sets a cookie without the 'path'.
                // IE takes this as the root ('/') value,
                // the HttpWebRequest class as the RequestUri.AbsolutePath value.
                //
                foreach (Cookie c in cc)
                    if (c.Path == request.RequestUri.AbsolutePath)
                        CookieContainer.Add(new Cookie(c.Name, c.Value, "/", c.Domain));

                while (true)
                {
                    string str = sr.ReadLine();

                    if (str == null)
                        break;

                    yield return str;
                }
            }
        }

        class DefaultRequestStreamProcessor
        {
            public DefaultRequestStreamProcessor(string data)
            {
                _data = data;
            }

            readonly string _data;

            public void Process(Stream stream)
            {
                byte[] bytes = Encoding.ASCII.GetBytes(_data);
                stream.Write(bytes, 0, bytes.Length);
            }
        }

        class DefaultResponseStreamProcessor
        {
            public DefaultResponseStreamProcessor(HttpReader reader)
            {
                _reader = reader;
            }

            readonly HttpReader _reader;

            public void Process(Stream stream)
            {
                using (StreamReader sr = new StreamReader(stream, Encoding.Default))
                    _reader._html = sr.ReadToEnd();
            }
        }

        public HttpStatusCode Get(string requestUri)
        {
            DefaultResponseStreamProcessor rp = new DefaultResponseStreamProcessor(this);

            return Request(requestUri, "GET", null, rp.Process);
        }

        public HttpStatusCode Get(string requestUri, ProcessStream responseStreamProcessor)
        {
            return Request(requestUri, "GET", null, responseStreamProcessor);
        }

        public HttpStatusCode Post(
            string requestUri,
            string postData)
        {
            return Post(
                requestUri,
                new DefaultRequestStreamProcessor(postData).Process,
                new DefaultResponseStreamProcessor(this).Process);
        }

        public HttpStatusCode Post(
            string        requestUri,
            ProcessStream requestStreamProcessor)
        {
            return Post(
                requestUri,
                requestStreamProcessor,
                new DefaultResponseStreamProcessor(this).Process);
        }

        public HttpStatusCode Post(
            string        requestUri,
            string        postData,
            ProcessStream responseStreamProcessor)
        {
            return Post(
                requestUri,
                new ProcessStream(new DefaultRequestStreamProcessor(postData).Process),
                responseStreamProcessor);
        }

        public HttpStatusCode Post(
            string        requestUri,
            ProcessStream requestStreamProcessor,
            ProcessStream responseStreamProcessor)
        {
            Request(requestUri, "POST", requestStreamProcessor, responseStreamProcessor);

            for (int i = 0; i < 10; i++)
            {
                bool post = false;

                switch (StatusCode)
                {
                    case HttpStatusCode.MultipleChoices:   // 300
                    case HttpStatusCode.MovedPermanently:  // 301
                    case HttpStatusCode.Found:             // 302
                    case HttpStatusCode.SeeOther:          // 303
                        break;

                    case HttpStatusCode.TemporaryRedirect: // 307
                        post = true;
                        break;

                    default:
                        return StatusCode;
                }

                if (Location == null)
                    break;

                Uri uri = new Uri(new Uri(PreviousUri), Location);

                BaseUri    = uri.Scheme + "://" + uri.Host;
                requestUri = uri.AbsolutePath + uri.Query;

                Request(
                    requestUri,
                    post? "POST": "GET",
                    post? requestStreamProcessor: null,
                    responseStreamProcessor);
            }

            return StatusCode;
        }

        private HttpStatusCode Soap(
            string        soapAction,
            ProcessStream inputStreamProcessor,
            ProcessStream outputStreamProcessor)
        {
            return Request("\"" + soapAction + "\"", "SOAP", inputStreamProcessor, outputStreamProcessor);
        }

        public HttpStatusCode Soap(string soapAction, string postData)
        {
            return Soap(soapAction,
                new DefaultRequestStreamProcessor(postData).Process,
                new DefaultResponseStreamProcessor(this).Process);
        }

        public HttpStatusCode Soap(string soapAction, string postData, ProcessStream outputStreamProcessor)
        {
            return Soap(
                soapAction,
                new DefaultRequestStreamProcessor(postData).Process,
                outputStreamProcessor);
        }

        public IEnumerable<string> SoapEx(string soapAction, string postData)
        {
            return Request("\"" + soapAction + "\"", "SOAP", new DefaultRequestStreamProcessor(postData).Process);
        }

        #endregion

        #region Download

        public void Download(string requestUri, string fileName)
        {
            string uri = BaseUri + requestUri;

            WebClient request = new WebClient();

            if (Proxy       != null) request.Proxy       = Proxy;
            if (Credentials != null) request.Credentials = Credentials;

            foreach (string key in Headers.Keys)
                request.Headers.Add(key, Headers[key].ToString());

            request.DownloadFile(uri, fileName);
        }

        #endregion
    }
}
 
© 2010 www.bltoolkit.net
support@bltoolkit.net