private void ServerThread_DoWork(Object args) { Object[] arg = (Object[])args; int port = (int)arg[0]; IPAddress ifaceip = (IPAddress)arg[1]; //Boolean natt = (Boolean)arg[2]; TcpListener listener = null; List<connection> clients = new List<connection>(); int threadsleep = 100; listener = new TcpListener(ifaceip, port); listener.Start(); while (true) { // Break loop if cancel pending if (_cancel) { _cancel = false; listener.Stop(); foreach(connection c in clients) { c.Client.Client.Disconnect(false); c.Client.Close(); } clients.Clear(); return; } // Establishes new Client connections and adds them to the list to b // processed. while (listener.Pending()) { TcpClient client = listener.AcceptTcpClient(); //client.NoDelay = true; //client.Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true); connection tcc = new connection(); tcc.Client = client; tcc.ConnectionEstablished = DateTime.Now; clients.Insert(0, tcc); } // Create a copy to work on instead of working directly on // the list. connection[] nowclients = clients.ToArray (); #if DEBUG_CON if(nowclients.Length != lastclientc) { lastclientc = nowclients.Length; Console.Error.WriteLine("Client Connections: " + lastclientc); } #endif // This thread has the potential to lock up the whole // pc if there are no connections to process. Here // we attempt to put in some sleep time if there are // no connections. This might require some tweaking. if(nowclients.Length > 0) threadsleep = 10; else threadsleep = 500; try { #region Main Loop for (int i = 0; i < nowclients.Length; i++) { // Skip Clients that are processing. if (nowclients[i].processing) { continue; } else if(nowclients[i].is_disposed) { nowclients[i].Tag = null; clients.Remove(nowclients[i]); } // Remove clients that have disconnected. else if (!nowclients[i].Client.Connected || nowclients[i].Client.Client.Poll(1, SelectMode.SelectError)) { nowclients[i].Close(); nowclients[i].Tag = null; clients.Remove(nowclients[i]); continue; } // This fires the main process else if (!nowclients[i].processing && !nowclients[i].is_disposed && nowclients[i].data_available) { nowclients[i].processing = true; nowclients[i].lifespans += 1; nowclients[i].ActivityUpdate(); HandleRequest(nowclients[i]); continue; } // Disconnect clients that have been idle for too long. if(!nowclients[i].processing && (DateTime.Now - nowclients[i].LastActivity) > TimeSpan.FromSeconds(_idle_timeount)) { nowclients[i].Close(); nowclients[i].Tag = null; clients.Remove(nowclients[i]); } } // Believe it or not this is extremely important. // Without this line, this thread can lock the entire // computer up. Thread.Sleep(threadsleep); #endregion } catch (Exception ex) { #if DEBUG Console.Error.WriteLine(ex.Message); Console.Error.WriteLine(ex.StackTrace); #endif throw ex; } } }
public abstract void HandleRequest(connection cc);
public override void HandleRequest(connection cc) { ParameterizedThreadStart pts = new ParameterizedThreadStart(worker_DoWork); Thread t = new Thread(pts); t.IsBackground = false; t.Priority = ThreadPriority.Normal; t.Start(new Object[] { cc,_scripters }); }
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 override void Initialize (connection con) { try { base.Initialize (con); } catch (Exception ex) { #if DEBUG if(_request != null) Console.Error.WriteLine("Error: " +_request.Uri.ToString()); Console.Error.WriteLine(ex.Message); Console.Error.WriteLine(ex.StackTrace); #endif proxied_retry_exception ex1 = new proxied_retry_exception( this.Request,"Response init problem",ex,502); ex1.secure = con.stream is SslStream; this.Errors.Add(ex1); throw ex1; } if(Header.Statuscode == "408") { proxied_retry_exception ex = new proxied_retry_exception( this.Request,"Server replied with 'bad request'",null,408); ex.secure = con.stream is SslStream; this.Errors.Add(ex); throw ex; } }
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)"); } } }