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; }
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)"); } } }