public virtual HandlerThread GetHandlerThread(ClientInfo info) { return new HandlerThread (info); }
internal void ClientClosed(ClientInfo ci) { clients.Remove (ci); }
void DoProcess(ClientInfo ci) { ClientData data = (ClientData)ci.Data; string sessid = (string)data.req.Cookies ["_sessid"]; if (sessid != null) data.req.Session = (Session)sessions [sessid]; bool closed = Process (ci, data.req); data.state = closed ? ClientState.Closed : ClientState.Header; data.read = 0; HttpRequest oldreq = data.req; data.req = new HttpRequest (); // Once processed, the connection will be used for a new request data.req.Session = oldreq.Session; // ... but session is persisted data.req.From = ((IPEndPoint)ci.Socket.RemoteEndPoint).Address; }
void SendResponse(ClientInfo ci, HttpRequest req, HttpResponse resp, bool close) { StringBuilder builder = new StringBuilder (); // Create Headers builder.Append ("HTTP/1.0 "); builder.Append (resp.ReturnCode); builder.Append (Responses [resp.ReturnCode]); builder.Append ("\r\nDate: "); builder.Append (DateTime.Now.ToString ("R")); builder.Append ("\r\nServer: UnityEmbedded/1.0 (iOS)"); //builder.Append ("\r\nConnection: "); //builder.Append ((close ? "close" : "Keep-Alive")); if (resp.RawContent == null) { builder.Append ("\r\nContent-Length: "); builder.Append (resp.Content.Length); } else { builder.Append ("\r\nContent-Length: "); builder.Append (resp.RawContent.Length); } builder.Append ("\r\nContent-Encoding: utf-8"); builder.Append ("\r\nContent-Type: "); builder.Append (resp.ContentType); // ADDING CUSTOM HEADERS(new feature) if (!CUSTOM_RESPONSE_HEADERS.StartsWith ("$")) builder.Append (CUSTOM_RESPONSE_HEADERS); if (req.Session != null) { builder.Append ("\r\nSet-Cookie: _sessid="); builder.Append (req.Session.ID); builder.Append ("; path=/"); } foreach (DictionaryEntry de in resp.Header) { builder.Append ("\r\n"); builder.Append (de.Key); builder.Append (": "); builder.Append (de.Value); } builder.Append ("\r\n\r\n"); // Send Header ci.Send (builder.ToString ()); // Send Body if (resp.RawContent != null) { ci.Send (resp.RawContent); } else { ci.Send (resp.Content); } // Close if not persistent connection if (close) { ci.Close (); } }
void ClientRead(ClientInfo ci, string text) { // Read header, if in right state ClientData data = (ClientData)ci.Data; if (data.state != ClientState.Header) return; // already done; must be some text in content, which will be handled elsewhere text = text.Substring (data.headerskip); data.headerskip = 0; string[] lines = text.Replace ("\r\n", "\n").Split ('\n'); data.req.HeaderText = text; // First line: METHOD /path/url HTTP/version string[] firstline = lines [0].Split (' '); if (firstline.Length != 3) { SendResponse (ci, data.req, new HttpResponse (400, "Incorrect first header line " + lines [0]), true); return; } if (firstline [2].Substring (0, 4) != "HTTP") { SendResponse (ci, data.req, new HttpResponse (400, "Unknown protocol " + firstline [2]), true); return; } data.req.Method = firstline [0]; data.req.Url = firstline [1]; data.req.HttpVersion = firstline [2].Substring (5); int p; for (int i = 1; i < lines.Length; i++) { p = lines [i].IndexOf (':'); if (p > 0) data.req.Header [lines [i].Substring (0, p)] = lines [i].Substring (p + 2); } // If ? in URL, split out query information p = firstline [1].IndexOf ('?'); if (p > 0) { data.req.Page = data.req.Url.Substring (0, p); data.req.QueryString = data.req.Url.Substring (p + 1); } else { data.req.Page = data.req.Url; data.req.QueryString = ""; } if (data.req.Page.IndexOf ("..") >= 0) { SendResponse (ci, data.req, new HttpResponse (400, "Invalid path"), true); return; } data.req.Host = (string)data.req.Header ["Host"]; if (null == data.req.Host) { SendResponse (ci, data.req, new HttpResponse (400, "No Host specified"), true); return; } if (null != data.req.Header ["Cookie"]) { string[] cookies = ((string)data.req.Header ["Cookie"]).Split (';'); foreach (string cookie in cookies) { p = cookie.IndexOf ('='); if (p > 0) { data.req.Cookies [cookie.Substring (0, p).Trim ()] = cookie.Substring (p + 1); } else { data.req.Cookies [cookie.Trim ()] = ""; } } } if (null == data.req.Header ["Content-Length"]) data.req.ContentLength = 0; else data.req.ContentLength = Int32.Parse ((string)data.req.Header ["Content-Length"]); //if(data.req.ContentLength > 0){ data.state = ClientState.PreContent; data.skip = text.Length + 4; //} else DoProcess(ci); //ClientReadBytes(ci, new byte[0], 0); // For content length 0 body }
/// <summary> /// /// </summary> /// <param name="ci"></param> /// <param name="bytes"></param> /// <param name="len"></param> void ClientReadBytes(ClientInfo ci, byte[] bytes, int len) { //CleanUpSessions (); int ofs = 0; ClientData data = (ClientData)ci.Data; switch (data.state) { case ClientState.Content: break; case ClientState.PreContent: data.state = ClientState.Content; if ((data.skip - data.read) > len) { data.skip -= len; return; } ofs = data.skip - data.read; data.skip = 0; break; default: //case ClientState.Header: data.read += len - data.headerskip; return; data.read += len; return; } //data.req.Content += Encoding.Default.GetString (bytes, ofs, len - ofs); data.req.Content += Encoding.UTF8.GetString (bytes, ofs, len - ofs); data.req.BytesRead += len - ofs; data.headerskip += len - ofs; if (data.req.BytesRead >= data.req.ContentLength) { if (data.req.Method == "POST") { if (data.req.QueryString == "") data.req.QueryString = data.req.Content; else data.req.QueryString += "&" + data.req.Content; } ParseQuery (data.req); DoProcess (ci); } }
//static long tTotal; protected virtual bool Process(ClientInfo ci, HttpRequest req) { //long tIn = DateTime.Now.Ticks; HttpResponse resp = new HttpResponse (); resp.Url = req.Url; for (int i = handlers.Count - 1; i >= 0; i--) { IHttpHandler handler = (IHttpHandler)handlers [i]; if (handler.Process (this, req, resp)) { SendResponse (ci, req, resp, resp.ReturnCode != 200); //tTotal += DateTime.Now.Ticks - tIn; //Console.WriteLine ("Total: " + tTotal + " ticks"); return resp.ReturnCode != 200; } } return true; }
public override HandlerThread GetHandlerThread(ClientInfo info) { return new IPhoneHandlerThread(info); }
void SendResponse(ClientInfo ci, HttpRequest req, HttpResponse resp, bool close) { StringBuilder builder = new StringBuilder(); // Create Headers builder.Append("HTTP/1.0 "); builder.Append(resp.ReturnCode); builder.Append(Responses [resp.ReturnCode]); builder.Append("\r\nDate: "); builder.Append(DateTime.Now.ToString("R")); builder.Append("\r\nServer: UnityEmbedded/1.0 (iOS)"); //builder.Append ("\r\nConnection: "); //builder.Append ((close ? "close" : "Keep-Alive")); if (resp.RawContent == null) { builder.Append("\r\nContent-Length: "); builder.Append(resp.Content.Length); } else { builder.Append("\r\nContent-Length: "); builder.Append(resp.RawContent.Length); } builder.Append("\r\nContent-Encoding: utf-8"); builder.Append("\r\nContent-Type: "); builder.Append(resp.ContentType); // ADDING CUSTOM HEADERS(new feature) if (!CUSTOM_RESPONSE_HEADERS.StartsWith("$")) { builder.Append(CUSTOM_RESPONSE_HEADERS); } if (req.Session != null) { builder.Append("\r\nSet-Cookie: _sessid="); builder.Append(req.Session.ID); builder.Append("; path=/"); } foreach (DictionaryEntry de in resp.Header) { builder.Append("\r\n"); builder.Append(de.Key); builder.Append(": "); builder.Append(de.Value); } builder.Append("\r\n\r\n"); // Send Header ci.Send(builder.ToString()); // Send Body if (resp.RawContent != null) { ci.Send(resp.RawContent); } else { ci.Send(resp.Content); } // Close if not persistent connection if (close) { ci.Close(); } }
internal ClientData(ClientInfo ci) { req.From = ((IPEndPoint)ci.Socket.RemoteEndPoint).Address; }
void ClientRead(ClientInfo ci, string text) { // Read header, if in right state ClientData data = (ClientData)ci.Data; if (data.state != ClientState.Header) { return; } // already done; must be some text in content, which will be handled elsewhere text = text.Substring(data.headerskip); data.headerskip = 0; string[] lines = text.Replace("\r\n", "\n").Split('\n'); data.req.HeaderText = text; // First line: METHOD /path/url HTTP/version string[] firstline = lines [0].Split(' '); if (firstline.Length != 3) { SendResponse(ci, data.req, new HttpResponse(400, "Incorrect first header line " + lines [0]), true); return; } if (firstline [2].Substring(0, 4) != "HTTP") { SendResponse(ci, data.req, new HttpResponse(400, "Unknown protocol " + firstline [2]), true); return; } data.req.Method = firstline [0]; data.req.Url = firstline [1]; data.req.HttpVersion = firstline [2].Substring(5); int p; for (int i = 1; i < lines.Length; i++) { p = lines [i].IndexOf(':'); if (p > 0) { data.req.Header [lines [i].Substring(0, p)] = lines [i].Substring(p + 2); } } // If ? in URL, split out query information p = firstline [1].IndexOf('?'); if (p > 0) { data.req.Page = data.req.Url.Substring(0, p); data.req.QueryString = data.req.Url.Substring(p + 1); } else { data.req.Page = data.req.Url; data.req.QueryString = ""; } if (data.req.Page.IndexOf("..") >= 0) { SendResponse(ci, data.req, new HttpResponse(400, "Invalid path"), true); return; } data.req.Host = (string)data.req.Header ["Host"]; if (null == data.req.Host) { SendResponse(ci, data.req, new HttpResponse(400, "No Host specified"), true); return; } if (null != data.req.Header ["Cookie"]) { string[] cookies = ((string)data.req.Header ["Cookie"]).Split(';'); foreach (string cookie in cookies) { p = cookie.IndexOf('='); if (p > 0) { data.req.Cookies [cookie.Substring(0, p).Trim()] = cookie.Substring(p + 1); } else { data.req.Cookies [cookie.Trim()] = ""; } } } if (null == data.req.Header ["Content-Length"]) { data.req.ContentLength = 0; } else { data.req.ContentLength = Int32.Parse((string)data.req.Header ["Content-Length"]); } //if(data.req.ContentLength > 0){ data.state = ClientState.PreContent; data.skip = text.Length + 4; //} else DoProcess(ci); //ClientReadBytes(ci, new byte[0], 0); // For content length 0 body }
public HandlerThread(ClientInfo ci) { this.clientInfo = ci; }
internal void KeyExchangeComplete(ClientInfo ci) { // Key exchange is complete on this client. Client ready // handlers may still force a close of the connection if (ClientReady != null) if (!ClientReady (this, ci)) ci.Close (); }
/// <summary> /// /// </summary> /// <param name="req"></param> /// <returns></returns> /* public Session RequestSession (HttpRequest req) { if (req.Session != null) { if (sessions[req.Session.ID] == req.Session) return req.Session; } req.Session = new Session (req.From); sessions[req.Session.ID] = req.Session; return req.Session; } */ /// <summary> /// /// </summary> /* void CleanUpSessions (bool unconditionally) { ICollection keys = sessions.Keys; ArrayList toRemove = new ArrayList (); foreach (string k in keys) { Session s = (Session)sessions[k]; int time = (int)((DateTime.Now - s.LastTouched).TotalSeconds); if ((time > sessionTimeout) || unconditionally) { toRemove.Add (k); } } foreach (object k in toRemove) sessions.Remove (k); } void CleanUpSessions () { CleanUpSessions (false); } */ /// <summary> /// /// </summary> /// <param name="s"></param> /// <param name="ci"></param> /// <returns></returns> bool ClientConnect(Server s, ClientInfo ci) { ci.Delimiter = "\r\n\r\n"; ci.Data = new ClientData (ci); ci.OnRead += new ConnectionRead (ClientRead); ci.OnReadBytes += new ConnectionReadBytes (ClientReadBytes); return true; }
// ASYNC CALLBACK CODE void AcceptCallback(IAsyncResult ar) { try { Socket server = (Socket)ar.AsyncState; Socket cs = server.EndAccept (ar); // Start the thing listening again server.BeginAccept (new AsyncCallback (AcceptCallback), server); ClientInfo c = new ClientInfo (cs, null, null, ClientDirection.Both, false); c.server = this; // Allow the new client to be rejected by the application if (Connect != null) { if (!Connect (this, c)) { // Rejected cs.Close (); return; } } // Initiate key exchange c.EncryptionType = encType; switch (encType) { case EncryptionType.None: KeyExchangeComplete (c); break; /* case EncryptionType.ServerKey: c.encKey = GetSymmetricKey (); byte[] key = ClientInfo.GetLengthEncodedVector (c.encKey); cs.Send (key); c.MakeEncoders (); KeyExchangeComplete (c); break; case EncryptionType.ServerRSAClientKey: RSACryptoServiceProvider rsa = new RSACryptoServiceProvider (); RSAParameters p = rsa.ExportParameters (true); cs.Send (ClientInfo.GetLengthEncodedVector (p.Modulus)); cs.Send (ClientInfo.GetLengthEncodedVector (p.Exponent)); c.encParams = p; break; */ default: throw new ArgumentException ("Unknown or unsupported encryption type " + encType); } clients.Add (c); #if MONOTOUCH GetHandlerThread(c).Start(); #else c.BeginReceive (); #endif } catch (ObjectDisposedException) { } catch (SocketException) { } catch (Exception e) { SystemLogger.Log (SystemLogger.Module .CORE, null, e); } }
public IPhoneHandlerThread(ClientInfo ci) : base(ci) { }