public static proxied_http_response Create(http_request req, connection con)
        {
            if (req.Header.Values.ContainsKey("Proxy-Connection"))
            {
                String pcon = req.Header.GetValue("Proxy-Connection");

                req.Header.Values.Remove("Proxy-Connection");

                if (String.IsNullOrEmpty(pcon) == false)
                    req.Header.SetValue("Connection", pcon);
            }
            //ALL CUSTOM TAGS MUST BE REMOVED BEFORE SENDING HEADERS.
            //THIS IS FOR ONE TAG, NEEDS TO BE MORE ABSTACT. SUCH AS
            //REMOVE ALL "X-ANYTHING" TAGS. NEED TO FIND A WAY TO DO
            //THIS IN THE HEADER LOGIC POSSIBLY!
            if(req.Header.Values.ContainsKey("X-Profile"))
                req.Header.Values.Remove("X-Profile");
 
            // Formatting the proper header needs to happen before now
            // Correcting Target header.
            if(req.Header.Target.ToLower().StartsWith("http"))
            {
                if(req.Uri.OriginalString.Contains(String.Format("{0}:{1}",req.Uri.Host,req.Uri.Port)))
                {
                    req.Header.Target = req.Uri.OriginalString.Substring(
                    req.Uri.OriginalString.IndexOf(String.Format("{0}:{1}",req.Uri.Host,req.Uri.Port)) +
                    String.Format("{0}:{1}",req.Uri.Host,req.Uri.Port).Length);
                }
                else
                {
                    req.Header.Target = req.Uri.OriginalString.Substring(
                    req.Uri.OriginalString.IndexOf(req.Uri.Host) + req.Uri.Host.Length);
                }
            }
#if !OFFLINE_DEBUG
            if(con.data_available)
            {
#if DEBUG
				byte[] bytes = con.read();
				Console.Error.WriteLine(String.Format("{0}: {1}","EARLY SERVER DATA!",Encoding.Default.GetString(bytes)));
#endif
				proxied_retry_exception ex =
					new proxied_retry_exception(req,"We have not sent a request, yet the server has sent us something! This should not happen ever!",null,502);
				ex.secure = con.stream is SslStream;
				throw ex;
            }
            ///Send Request
            if (con.Client.Connected)
            {
                if (con.Client.Client.Poll(1, SelectMode.SelectWrite) && !con.Client.Client.Poll(1,SelectMode.SelectError))
                {
                    ///req.toByteArray() should be the entire request including POST!
                    byte[] requestbytes = req.ToByteArray();
					try {
	                    con.stream.Write(requestbytes, 0, requestbytes.Length);
	                    con.stream.Flush();
					} catch {
						proxied_retry_exception ex = new proxied_retry_exception(req,"Can not send request upstream!",null,502);
						ex.secure = con.stream is SslStream;
						throw ex;
					}
                }
                else { 
					proxied_retry_exception ex = new proxied_retry_exception(req,"Can not send request upstream!",null,502);
					ex.secure = con.stream is SslStream;
					throw ex;
				}
            }
			else { 
				proxied_retry_exception ex = new proxied_retry_exception(req,"Upstream server disconnected while send request!",null,502);
				ex.secure = con.stream is SslStream;
				throw ex;
			}
            //wait for data
            int count = 0;
            while (!con.is_disposed && !con.data_available && count < 3000 && con.Client.Client.Connected && req.Connection.Client.Connected &&
			       !con.Client.Client.Poll(1, SelectMode.SelectError) && !req.Connection.Client.Poll(1, SelectMode.SelectError)) 
            { 
                //if(server.Client.Poll(100, SelectMode.SelectRead))
                //    throw new Exception("Server connection failed!");
                if(count == 2999) {
					proxied_retry_exception ex = new proxied_retry_exception(req,"Server failed to respond in a timely manner after sending request!",null,502);
					ex.secure = con.stream is SslStream;
					throw ex;
				}
                System.Threading.Thread.Sleep(100); 
                count += 1;
            }
#endif
            proxied_http_response pres = new proxied_http_response();
            pres.Request = req;
            return pres;
            
        }
Esempio n. 2
0
		public virtual void           Initialize(connection con)
		{
			_connection                 = con.Client;
			_neworkStream               = con.stream;
			_neworkStream.WriteTimeout  = 10000;
			_neworkStream.ReadTimeout   = 10000;

			int         headersplit     = -1;
			Boolean     headerfound     = false;
			long        ContentLength   = -1;
			int         constpasses     = 0;
			byte[]      readbytes       = null;
			List<byte>  allbytes		= new List<byte>();

			while (con.Client.Connected && !con.Client.Client.Poll(1, SelectMode.SelectError))
			{
				if (_cancel)
					break;

				if (con.data_available)
				{
					//find the header first. Due to wacky initialization bytes are stored globally until header is found;
					readbytes = con.read();

					if (headerfound == false)
					{
						allbytes.AddRange(readbytes);

						//check for header!
						headersplit = http_function.FindHeaderBodySplit(allbytes.ToArray());
						if (headersplit > 0)
						{
							//Creates the header object and writes the intital
							//bytes to body if there are any
							HandleInitialBytes(allbytes.ToArray(),headersplit);
							CreateUri();
							headerfound = true;


							//Optimizations based on header
							// I can't measure how effective they are... yet.

							//Post data is not included in a head or get request.
							//So we know we are done regardless of the
							//Content-Length.
							if(_header.Verb == "GET" || _header.Verb == "CONNECT" || _header.Verb == "HEAD" )
								_cancel = true;

							//If we have a Content-Length then we have a definate
							//place to end the read.
							if (_header.Values.ContainsKey("Content-Length"))
							{
								ContentLength = Convert.ToInt64(_header.Values["Content-Length"]);
								if(ContentLength == 0)
									_cancel = true;
								//_timeOut = _timeOut * 2;
							}

							//Allow a little more time for the server to process post data
							//Might come in handy when uploading files.
							if (_header.Verb == "POST") {
								if(!_header.Values.ContainsKey("Content-Length"))
								{
									http_exception ex = new http_exception(this,"Content-Length is mandatory!",null,411);
									ex.add_header("Connection","close");
									throw ex;
								}
								//_timeOut = _timeOut * 2;
							}

							if(!string.IsNullOrEmpty(_header.Verb) && string.IsNullOrEmpty(this.Host)) {
								throw new Exception("request requires a host!");
							}

							//When there is a transfer-encoding there is usually no
							//Content-Length and the file size is unknown so
							//there is no exact point where we no we can end this read
							//For good measure we are giving a little more time.
							//if (_header.Values.ContainsKey("Transfer-Encoding"))
							//    if (_header.GetValue("Transfer-Encoding").ToLower() == "chunked")
							//        _timeOut = _timeOut * 2;
						}
					}

					else //headerfound == false
					{
						// Make sure that bytes is not empty very important.
						if (readbytes.Length > 0)
						{
							//Writing bytes to body file!
							AppendBytesToFile(readbytes);
							// Part of a hard timeout implemented as a death counter
							// in ProxyTransaction.
							if(Activity!=null){Activity(this,new EventArgs());}
							constpasses = 0;

						}
					}
				}
				else //client.Available <= 0
				{

					if (headerfound)
					{
						if (ContentLength == 0 )
						{
							_cancel = true;

						}
						//There is a Content-Length and it's greater than 0 but Body.Length is
						//less than Content-Length. Basically we are in mid-transfer
						else if (ContentLength > 0)
						{
							if (Body.Length < ContentLength)
							{
								Thread.Sleep(10);
								constpasses = constpasses + 1;
							} 
							else if(Body.Length == ContentLength) {
								_cancel = true;
							}
						}
						//There is no Content-Length so we are using the timeout.
						else if(ContentLength < 0)
						{
							if(_header.Httpversion == "HTTP/1.0")
								_cancel = true;
							Thread.Sleep(10);
							constpasses = constpasses + 1;
						}
					}
					else {
						Thread.Sleep(10);
						constpasses = constpasses +1;
					}
					//Checking for timeout situation.
					if (constpasses >= (_timeOut / 10))
					{
						Exception ex = new Exception("Read Timeout!");
						_errors.Add(ex);
						//if (ReadTimeOut != null) { ReadTimeOut(this, new EventArgs()); }
						//throw ex;
						_cancel = true;
					}
				}
			}
			if(! headerfound && _header.Connection.ToLower() != "close")
				if(!con.Client.Client.Connected || con.Client.Client.Poll(1, SelectMode.SelectError))
					throw new Exception("hr: Client Disconnected!");

			if(headerfound && _header != null && _header.Verb != "HEAD" && _header.Statuscode != " 206" && _header.Values.ContainsKey("Content-Length")) {
				if(Convert.ToInt32(_body.Length) != _header.ContentLength) {
#if DEBUG
					Console.Error.WriteLine(String.Format("Entity size mismatch {0}/{1}",_header.ContentLength,_body.Length));
#endif
					_header.ContentLength = Convert.ToInt32(_body.Length);
				}
			}

			if (headerfound == false || _header == null)
			{
				if(allbytes.Count == 0)
				{
					throw new Exception("Zero bytes have been recieved!");

				}
				else
				{
					throw new Exception("The request/response did not seem to have the http head/body dilimeter (CRLFCRLF)");
				}
			}
		}