/// <summary> /// This function return the default error page as Application Response. /// </summary> /// <param name="request"></param> /// <param name="ex"></param> /// <returns></returns> public static ApplicationResponse Generate404Page(HttpRequest request, string bodyMessage,string pageHeader,string title="Error Page") { //Check if the defaultPage exist if (!File.Exists(HttpApplicationManager.RootDirectory + "\\" + HttpApplicationManager.DefaultPage)) { //No data to sent back so the connection will be close. return new ApplicationResponse(request) { Action = ResponseAction.Disconnect }; } //Get the file byte[] page = Helper.GetFile(HttpApplicationManager.RootDirectory + "\\" + HttpApplicationManager.DefaultPage); string page_str = new String(Encoding.UTF8.GetChars(page)); //fill the page with exception information page_str = page_str.Replace("<%ws_title%>", title); page_str = page_str.Replace("<%ws_domain%>", HttpApplicationManager.CurrentDomain + ":" + HttpApplicationManager.ServicePort); page_str = page_str.Replace("<%ws_header%>", pageHeader); page_str = page_str.Replace("<%ws_message%>", bodyMessage); page = Encoding.UTF8.GetBytes(page_str); //Get the pageHeader byte[] binheader = GetHeader(page.Length,MimeType.text_html,true,false); //build the response byte[] completeResponse = binheader.Concat(page); ApplicationResponse response = new HttpResponse(completeResponse, request); return response; }
/// <summary> /// Page load event /// </summary> /// <param name="req"></param> protected override void PageLoad(HttpRequest req) { try { if (req.UrlParameters.Count > 0) { /// /// the client send /// string operation = req.GetQueryStringValue("op"); switch (operation) { case "listen": // Thread.Sleep(1000); string jsonsettings = req.GetQueryStringValue("set"); FrameIndex settings = JsonConvert.DeserializeObject<FrameIndex>(HttpHelper.CleanJsonString(jsonsettings)); string frame = imgPrefix + (globalcounter++) + img_value_delimeter + settings.ZoomX + img_value_delimeter + settings.ZoomY + img_value_delimeter + ".jpg"; SendMessage(new FrameIndex() { Code = MessageType.getFrame, Img = frame }, false); break; } } } catch (Exception ex) { } }
/// <summary> /// This Events is triggered when a page loads. /// </summary> /// <param name="req"></param> protected abstract void PageLoad(HttpRequest req);
/// <summary> /// This function check if the RawRequest be received from the browser is well formed. /// </summary> /// <param name="e"></param> /// <param name="req"></param> /// <returns></returns> public static bool TryValidate(RawRequest e, out HttpRequest req) { HttpRequestType request = HttpRequestType.HttpPage; try { /// /// There are a lot of tecnique to extract the information in an http browser request, /// this solutions split the request string and analize each blocks. /// req = new HttpRequest(e); /// ///Decode the bytes in Utf8 chars and Split the string request by "\r\n" /// req.CompleteRequest = new String(Encoding.UTF8.GetChars(e.RawData)); string[] groups = req.CompleteRequest.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < groups.Length; i++) { string headerblock = groups[i]; if (i > 0 && headerblock.Contains(":")) { //From the second block we have fileds with the pattern <name:value> string[] block = headerblock.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries); req.Requests.Add(block[0], block[1]); } else { /// /// The first block always include the request path ,the method and the protocol http. /// ex. GET /path/resource.ext HTTP/1.1 /// string[] subparts = headerblock.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries); //copy the path req.CompletePath = subparts[1]; if (subparts[0] == "GET") req.Method = HttpMethodType.Get; if (subparts[0] == "POST") req.Method = HttpMethodType.Post; if (!String.IsNullOrEmpty(subparts[1])) { //split the path in "directories" string[] resourcePaths = subparts[1].Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries); if (resourcePaths.Length > 0) { /// /// We make a distinction between HttpStaticRequest and HttpPage /// string resourceFullName = resourcePaths[resourcePaths.Length - 1]; if (HttpHelper.IsStaticResource(resourceFullName)) { request = HttpRequestType.HttpStaticRequest; } } } else throw new InvalidOperationException("Invalid Request : " + req.CompleteRequest); /// /// separate the request path from possibly query-url /// string[] subPaths = subparts[1].Split(new string[] { "?" }, StringSplitOptions.RemoveEmptyEntries); req.Path = subPaths[0]; req.Paths = subPaths[0].Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries).ToList(); } } //Save the query url parts in a dictionary : req.UrlParameters string[] queryparams = HttpHelper.GetUrlQueries(HttpHelper.RemoveToken(req.CompletePath)); foreach (string p in queryparams) { string[] query = p.Split(new String[] { "=" }, StringSplitOptions.RemoveEmptyEntries); if (query.Length == 2) { req.UrlParameters.Add(query[0], query[1]); } } } catch (Exception) { //If somethig goes wrong the validation return false. req = null; return false; } req.Type = request; return true; }
/// <summary> /// Return an application istance that correspond with the request. /// </summary> /// <param name="e"></param> /// <param name="application"></param> /// <returns>false if not exist</returns> public bool TryGetApplicationInstance(HttpRequest e, out ApplicationInstanceBase application) { /// /// The logic to get the right application from a request is very simple, /// For identify the application we look the main path in the url, is the first after the domain domain.xxx ex: /// http://domain.xxc/maindir/dir1/dir2 so, dir1/dir2 are internal paths relatively at the main path maindir. /// The rule is the main path indicate the name of the application, so /// http://localhost:8080/chat/index.html identify the chat application /// http://localhost:8080/chat/chat2/index.html identify the chat application /// /// application = null; string[] paths = e.Path.Split(new string[] { "/" }, StringSplitOptions.RemoveEmptyEntries); if (paths.Length == 0) return false; string mainPath = paths[0]; /// /// Immediately check if exist an ApplicationUniqueName equal to mainpath /// if (!applications.ContainsKey(mainPath)) return false; //Ok the applicatoin Exist! SessionManager sessionMgr = applications[mainPath]; ApplicationSettings settings = sessionMgr.Info; string sessionKey = string.Empty; /// /// The SessionManager is found now we check if already exist any session /// switch (settings.SessionType) { case ApplicationSessionMode.SingletonSession: /// /// SingletonSession /// application = sessionMgr.GetOrCreateSingletonInstance(); return true; case ApplicationSessionMode.BrowserSession: /// /// We need a session key to identfy one particolare browser /// sessionKey = e.Rawrequest.Connection.IP + "@" + e.Requests["User-Agent"]; break; case ApplicationSessionMode.IpSession: /// /// We need a session key to identfy one Ip address /// sessionKey = e.Rawrequest.Connection.IP.ToString(); break; } application = sessionMgr.GetOrCreateInstanceBySessionKey(sessionKey); return true; }
/// <summary> /// Dispatch a response to the other sessions. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> /// <param name="req"></param> public void ShareApplicationOutput(ApplicationInstanceBase sender, ApplicationResponse e, HttpRequest req) { //### verify if application exist if (applications.ContainsKey(sender.Info.UniqueApplicationName)) { //### Session manager cointains all instances SessionManager session = applications[sender.Info.UniqueApplicationName]; foreach (var item in session.SessionList) { //### Skip the sender if (item.Value.ApplicationId != sender.ApplicationId) { item.Value.OnNewShareResponse(sender, e, req); } } } }
/// <summary> /// This method try to find a resource in a ResourceDirectory path and return a response. /// </summary> /// <param name="request"></param> /// <returns></returns> public ApplicationResponse ResponseStaticResource(HttpRequest request) { string resource = request.Path; ApplicationResponse output = null; if (resource[0] != '/') resource = "/" + resource; //Get resource mime type MimeType type = HttpHelper.GetResourceMime(resource); //Check if Gzip compression is enable bool gzip = request.isGZIPSupported(); //Get a file byte[] file = Helper.GetFile(RootDirectory + request.Path); if (file != null) { //compress data id Gzip is supported file = gzip ? HttpHelper.CompressGZIP(file) : file; //get a pageHeader byte[] header = HttpHelper.GetHeader(file.Length, type, true, gzip); //build the complete response byte[] response = header.Concat(file); //create the response output = new HttpResponse(response, request); } else { //file not found: return 404 response output = new HttpResponse(HttpHelper.GetHtml404Header(0, type), request); } return output; }
/// <summary> /// Page load event. /// </summary> /// <param name="req"> /// The request from the browser. /// </param> protected override void PageLoad(HttpRequest req) { /// /// The ChatServer application is strictly relate with the javascript implementation, /// so if the request contains query url string parameters means that invoking by the XMLHttpRequest object (ajax pattern). /// You can choose a different way to distinguish 'pure' pageload event (called in Asp.net postback) from ajax event. /// /// The query url request has this pattern: ?op=<operation>&<par1>=<value1>&<par2>=<value2> where op stands for 'operation'. /// string page = Request.Paths[Request.Paths.Count - 1]; if (req.UrlParameters.Count > 0) { SharedChatMessage sharedresponse = null; ChatMessage message = null; string operation = req.GetQueryStringValue("op"); switch (operation) { case "login": /// /// Login operation process steps: /// 1) Check username and password , if one of these is empty we respond with an alert /// 2) Validation of the user /// 3) Respond with a redirect /// string username = req.GetQueryStringValue("username"); string password = req.GetQueryStringValue("password"); if (String.IsNullOrEmpty(username) || String.IsNullOrEmpty(password)) { BuildChatResponse(new ChatMessage() { MessageCode = (int)MessageType.alert, Value = "Login request error." }, true); return; } currentUsername = username; currentPassowrd = password; isValidUser = true; BuildChatResponse(new ChatMessage() { MessageCode = (int)MessageType.eval, Value = "window.location=\"" + roomPage + "\"" }, true); return; case "listen": /// /// When the room page is loaded start to send 'listen' operation request in loop, /// at every listen request we respond with a chatmessage getting from the queue or,if is empty ,with a skip action message. /// But firstable we sent adduser action message with SharedChatMessage envelop for notify the new user. /// if (!sendAdduser) { sendAdduser = true; message = new ChatMessage() { MessageCode = (int)MessageType.adduser, User = currentUsername, }; BuildChatResponse(message, false); this.response = sharedresponse = new SharedChatMessage(Response.ResponseData, Response.AppRequest, message); return; } if (localqueuemessages.Count == 0) { System.Threading.Thread.Sleep(500); BuildChatResponse(new ChatMessage() { MessageCode = (int)MessageType.skip, Value = "" }, false); } else { ChatMessage msg = null; if (localqueuemessages.TryDequeue(out msg)) BuildChatResponse(msg, false); } return; case "message": /// /// A chat message is sent by the user, /// firstable we build ChatMessage packet replacing the response with SharedChatMessage envelop, /// that is why SharedChatMessage is visible to the other session (see OnNewShareResponse). /// /// string value = req.GetQueryStringValue("value"); message = new ChatMessage() { MessageCode = (int)MessageType.chatmessage, Value = value, User = currentUsername }; BuildChatResponse(message, false); sharedresponse = new SharedChatMessage(Response.ResponseData, Response.AppRequest, message); Response = sharedresponse; return; default: throw new InvalidOperationException("Invalid request"); } } if (page == roomPage) { /// /// if the user not perform the login the roomPage will not be loaded, will be sent a login page /// if (!isValidUser) { BuildResponseFile(ApplicationDirectory() + "\\" + loginPage,MimeType.text_html); return; } else { byte[] room = Helper.GetFile(ApplicationDirectory() + "\\" + roomPage); string msg = new string(Encoding.UTF8.GetChars(room)); msg = msg.Replace("<%ws_username%>", this.currentUsername); BuildResponse(msg); } } }