예제 #1
0
        /// <summary>
        /// This is the very first point where Sprocket interrupts the ASP.Net HTTP pipeline
        /// and allows itself to start handling requests. Note that this is way before the
        /// standard ASP.Net page framework would kick in. At this point state information like
        /// cookies and sessions have not yet been loaded.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void FireBeginRequest(object sender, EventArgs e)
        {
            if (!AjaxRequestHandler.IsAjaxRequest)
            {
                // The SprocketPath refers to the bit after the application base path and before the
                // querystring, minus any leading and trailing forward-slashes. (/) For example if the
                // full URL is "http://www.sprocketcms.com/myapp/admin/users/?edit" and the subdirectory
                // "myapp" is a virtual directory (IIS application) then the SprocketPath would be
                // "admin/users".
                string sprocketPath = null;
                string appPath      = HttpContext.Current.Request.Path.ToLower();

                // check to see if there's a trailing slash and if there isn't, redirect to stick a trailing
                // slash onto the path. This is to keep pathing consistent because otherwise relative paths
                // (such as to images and css files) aren't pathed as expected. We DON'T do this if a form
                // has been posted however, because otherwise we lose the contents of the posted form. It is
                // assumed that if you forget to post to a path with a trailing slash, that once you finish
                // processing the form that you'll redirect off to a secondary page anyway, which means
                // sticking a slash on the end of this URL is unnecessary anyway.
                if (!appPath.EndsWith("/") && !appPath.Contains(".") && HttpContext.Current.Request.Form.Count == 0)
                {
                    HttpContext.Current.Response.Redirect(appPath + "/");
                    HttpContext.Current.Response.End();
                    return;
                }

                // changes (e.g.) "http://www.sprocketcms.com/myapp/admin/users/?edit" into "admin/users"
                SprocketPath.Parse(HttpContext.Current.Request.Url);
                //sprocketPath = appPath.Remove(0, HttpContext.Current.Request.ApplicationPath.Length).Trim('/');
                //SprocketPath.Value = sprocketPath;
                //SprocketPath.Sections = SprocketPath.Value.Split('/');
            }
            HandleFlag handled = new HandleFlag();

            if (OnBeginHttpRequest != null)
            {
                OnBeginHttpRequest(handled);
            }

            if (handled.Handled)
            {
                HttpContext.Current.Response.End();
                return;
            }

            // The SprocketSettings module is one of the modules that handles the OnBeginHttpRequest
            // event. It lets each module check for any .config file errors (or other settings errors)
            // and report them back here. If we get to this point and at least one module has reported
            // a settings error, we show Sprocket's critical error page which has a nice list of
            // error messages that the user can try to rectify.
            if (SprocketSettings.Errors.HasCriticalError)
            {
                ShowErrorPage();
                return;
            }
        }
예제 #2
0
        /// <summary>
        /// This method is called in response to any request where the URL ends with a .ajax
        /// extension, which Sprocket uses to designate an Ajax request from an XmlHttpRequest
        /// call in the browser. The posted data contains information that this method uses to
        /// find the correct ISprocketModule implementation. It then uses reflection to get
        /// the requested method from the module, converts the javascript arguments into native
        /// CLR types and passes them to the method, after which it takes the returned data and
        /// writes it to the output stream ready for the XmlHttpRequest object to complete its
        /// call. Note that data transport uses JSON encoding. See the JSON class in the
        /// Sprocket.System namespace for information.
        /// </summary>
        /// <param name="context">The current HttpContext object.</param>
        internal void ProcessRequest(HttpContext context)
        {
            isAjaxRequest = true;
            System.Diagnostics.Debug.WriteLine("Start of AJAX page request...");
            Dictionary <string, object> responseData = new Dictionary <string, object>();

            try
            {
                // load the post data from the http stream
                byte[] posted = new byte[context.Request.InputStream.Length];
                context.Request.InputStream.Read(posted, 0, posted.Length);

                // interpret the stream as a JSON string and parse it into a dictionary
                string strData = System.Text.Encoding.ASCII.GetString(posted);
                IDictionary <string, object> data = (IDictionary <string, object>)JSON.Parse(strData);

                // extract the base page time stamp
                //pageTimeStamp = new DateTime(long.Parse(data["LoadTimeStamp"].ToString()));
                //System.Diagnostics.Debug.WriteLine("Extracted page time stamp of " + pageTimeStamp.Ticks.ToString());
                //if (OnAjaxRequestTimeStampCheck != null)
                //{
                //    Result result = new Result();
                //    OnAjaxRequestTimeStampCheck(pageTimeStamp, result);
                //    if (!result.Succeeded)
                //        throw new AjaxSessionExpiredException(result.Message);
                //}

                // extract the module and method name
                string fullname;
                try
                {
                    fullname = data["ModuleName"].ToString();
                }
                catch (Exception ex)
                {
                    throw;
                }
                int n = fullname.LastIndexOf(".");
                if (n == -1)
                {
                    throw new AjaxException("Method name specified incorrectly. Expected format ModuleNamespace.MethodName.\nThe following incorrect format was supplied: " + data["ModuleName"]);
                }
                string moduleNamespace = fullname.Substring(0, n);
                string methodName      = fullname.Substring(n + 1, fullname.Length - (n + 1));

                // extract the authentication key
                if (data["AuthKey"].ToString() != WebAuthentication.AuthKeyPlaceholder)
                {
                    authKey = new Guid(data["AuthKey"].ToString());
                }

                // extract the source URL
                SprocketPath.Parse(data["SourceURL"].ToString());

                // extract the arguments
                List <object> parsedArguments = (List <object>)data["MethodArgs"];

                // find and verify the module/method that should handle this request
                ISprocketModule module = Core.Instance[moduleNamespace].Module;
                if (module == null)
                {
                    throw new AjaxException("The specified module \"" + moduleNamespace + "\" was not found.");
                }
                if (Attribute.GetCustomAttribute(module.GetType(), typeof(AjaxMethodHandlerAttribute), false) == null)
                {
                    throw new SprocketException("The specified module is not marked with AjaxMethodHandlerAttribute. (" + data["ModuleName"] + ")");
                }
                MethodInfo info = module.GetType().GetMethod(methodName);
                if (info == null)
                {
                    throw new AjaxException("Failed to find an instance of the specified method. (" + data["ModuleName"] + ")");
                }
                Attribute ajaxMethodAttr = Attribute.GetCustomAttribute(info, typeof(AjaxMethodAttribute));
                if (ajaxMethodAttr == null)
                {
                    throw new AjaxException("Specified method is not marked with AjaxMethodAttribute. (" + data["ModuleName"] + ")");
                }
                AjaxMethodAttribute attr = (AjaxMethodAttribute)ajaxMethodAttr;
                if (attr.RequiresAuthentication)
                {
                    if (!WebAuthentication.IsLoggedIn)
                    {
                        AjaxRequestHandler.AbortAjaxCall("You're not currently logged in. Please refresh the page.");
                    }

                    if (AjaxAuthenticate != null)
                    {
                        Result result = AjaxAuthenticate(info);
                        if (!result.Succeeded)
                        {
                            throw new AjaxException(result.Message);
                        }
                    }
                }

                // get all of the parameters that the method requires
                ParameterInfo[] methodParamInfos = info.GetParameters();

                // funcinfo is a string representation of the method format and is used for displaying meaningful errors
                string funcinfo = data["ModuleName"] + "(";
                if (methodParamInfos.Length > 0)
                {
                    funcinfo += methodParamInfos[0].ParameterType.Name + " " + methodParamInfos[0].Name;
                }
                for (int j = 1; j < methodParamInfos.Length; j++)
                {
                    funcinfo += ", " + methodParamInfos[j].ParameterType.Name + " " + methodParamInfos[j].Name;
                }
                funcinfo += ")";
                if (methodParamInfos.Length != parsedArguments.Count)
                {
                    throw new AjaxException("Method expects " + methodParamInfos.Length + " argument(s) but instead received " + (parsedArguments.Count) + ". Expected format is:\n" + funcinfo);
                }

                // create the parameter array and convert each supplied value to its native type
                object[] prmValuesForMethod = new object[methodParamInfos.Length];
                for (int i = 0; i < prmValuesForMethod.Length; i++)
                {
                    Type t = methodParamInfos[i].ParameterType;
                    try
                    {
                        if (parsedArguments[i] == null)
                        {
                            prmValuesForMethod[i] = null;
                        }
                        else if (t.Name == "Object")
                        {
                            prmValuesForMethod[i] = parsedArguments[i];
                        }
                        else if (t.Name == "DateTime")
                        {
                            prmValuesForMethod[i] = DateTime.Parse(parsedArguments[i].ToString());
                        }
                        else if (t.IsArray || t.IsSubclassOf(typeof(IList)))
                        {
                            int    elementCount = ((List <object>)parsedArguments[i]).Count;
                            Type   arrType      = t.GetElementType().MakeArrayType(elementCount);
                            object arr          = Array.CreateInstance(t.GetElementType(), ((List <object>)parsedArguments[i]).Count);
                            for (int k = 0; k < ((IList <object>)parsedArguments[i]).Count; k++)
                            {
                                ((IList)arr)[k] = ((IList <object>)parsedArguments[i])[k];
                            }
                            prmValuesForMethod[i] = arr;
                        }
                        else if (t.GetInterface("IJSONReader") != null)
                        {
                            object obj = Activator.CreateInstance(t);
                            ((IJSONReader)obj).LoadJSON(parsedArguments[i]);
                            prmValuesForMethod[i] = obj;
                        }
                        else if (t.IsAssignableFrom(typeof(Guid)) || t.IsAssignableFrom(typeof(Guid?)))
                        {
                            prmValuesForMethod[i] = parsedArguments[i] == null ? (Guid?)null : new Guid(parsedArguments[i].ToString());
                        }
                        else if (t.IsAssignableFrom(typeof(long)) || t.IsAssignableFrom(typeof(long?)))
                        {
                            prmValuesForMethod[i] = parsedArguments[i] == null ? (long?)null : long.Parse(parsedArguments[i].ToString());
                        }
                        else
                        {
                            prmValuesForMethod[i] = Convert.ChangeType(parsedArguments[i], t);
                        }
                    }
                    catch (Exception ex)
                    {
                        string err = "Error converting parameter {0} to type {1}. Expected format is:\n{2}\nReceived Value:\n{3}\nException message:\n{4}";
                        throw new AjaxException(string.Format(err, i, methodParamInfos[i].ParameterType.Name, funcinfo, parsedArguments[i], ex));
                    }
                }

                // invoke the method
                if (info.ReturnType == typeof(void))
                {
                    info.Invoke(module, prmValuesForMethod);
                }
                else
                {
                    object returnVal = info.Invoke(module, prmValuesForMethod);
                    responseData["Data"] = returnVal;
                }
                //context.Response.Write(JSON.Encode(responseData));
            }
            catch (Exception e)
            {
                if (!(e is AjaxUserMessageException) && SprocketSettings.GetBooleanValue("CatchExceptions"))
                {
                    if (e.InnerException != null)
                    {
                        throw e.InnerException;
                    }
                    throw e;
                }
                else if (e.InnerException != null)
                {
                    e = e.InnerException;
                }
                responseData["__error"]         = e;
                responseData["__exceptionType"] = e.GetType().FullName;
            }
            if (!responseData.ContainsKey("Data"))
            {
                responseData["Data"] = null;
            }
            //responseData["__timeStamp"] = pageTimeStamp.Ticks;
            context.Response.Write(JSON.Encode(responseData));
        }
예제 #3
0
        /// <summary>
        /// Sprocket calls this method in response to ASP.Net's AcquireRequestState event.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        internal void FireAcquireRequestState(object sender, EventArgs e)
        {
            if (OnRequestStateLoaded != null)             // as always, let the other modules know where we are...
            {
                OnRequestStateLoaded();
            }

            if (HttpContext.Current.Request.Form != null)
            {
                if (HttpContext.Current.Request.Form.Count > 0)
                {
                    foreach (FormPostAction action in formPostActions)
                    {
                        if (action.PostFromPath != null)
                        {
                            if (action.PostFromPath != SprocketPath.ExtractSprocketPath(HttpContext.Current.Request.UrlReferrer.ToString()))
                            {
                                continue;
                            }
                        }

                        if (action.PostToPath != null)
                        {
                            if (action.PostToPath.ToLower() != SprocketPath.Value)
                            {
                                continue;
                            }
                        }

                        if (action.FieldName != null)
                        {
                            string s = HttpContext.Current.Request.Form[action.FieldName];
                            if (s == null)
                            {
                                continue;
                            }
                            if (action.FieldValue != null)
                            {
                                if (s != action.FieldValue)
                                {
                                    continue;
                                }
                            }
                        }

                        action.PostHandler();
                    }
                }
            }

            // this is our flag so that request event handlers can let us know if they handled this request.
            HandleFlag flag = new HandleFlag();

            if (OnLoadRequestedPath != null)
            {
                OnLoadRequestedPath(flag);
                if (flag.Handled)
                {
                    // stop the browser from caching the page
                    // HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);

                    if (OnRequestedPathProcessed != null)
                    {
                        OnRequestedPathProcessed();
                    }

                    // if one of the modules handled the request event, then we can stop
                    // doing stuff now. The OnEndRequest event will still be called though.
                    HttpContext.Current.Response.End();
                    return;
                }
            }

            // if we've reached this point and none of our modules have volunteered to handle
            // the request, we can check to see if the requested path actually exists (gasp!)
            // and if so, serve up that file! This is handy if we insist on using the Standard
            // ASP.Net Page framework (yuck) or want to serve up other things like plain html
            // files.
            if (!flag.Handled && File.Exists(HttpContext.Current.Request.PhysicalPath))
            {
                // here we provide a last chance opportunity to alter the response before the
                // file is served.
                if (OnBeforeLoadExistingFile != null)
                {
                    OnBeforeLoadExistingFile(flag);
                    if (flag.Handled)
                    {
                        HttpContext.Current.Response.End();
                        return;
                    }
                }
                HttpContext.Current.RewritePath(HttpContext.Current.Request.Path);
                return;
            }

            // at this point we know that no file matching the exists, so we can check to see
            // if a directory of the specified name exists. If it does, we can see if there are
            // any default pages inside the folder that should execute. This requires the a key
            // to be configured for appSettings in the Web.config file:
            // <add key="DefaultPageFilenames" value="default.aspx,default.asp,default.htm,index.htm" />
            if (Directory.Exists(HttpContext.Current.Request.PhysicalPath))
            {
                string dpgstr = SprocketSettings.GetValue("DefaultPageFilenames");
                if (dpgstr != null)
                {
                    string[] pgarr = dpgstr.Split(',');
                    foreach (string pgname in pgarr)
                    {
                        string pgpath   = "/" + HttpContext.Current.Request.Path.Trim('/') + "/" + pgname;
                        string physpath = HttpContext.Current.Request.PhysicalPath + "\\" + pgname;
                        if (File.Exists(physpath))
                        {
                            HttpContext.Current.Response.Redirect(pgpath);
                            return;
                        }
                    }
                }
            }

            // if we've reached this point and still havent found anything that wants to handle
            // the current request, we offer up a final chance to respond to this fact...
            if (OnPathNotFound != null)
            {
                OnPathNotFound(flag);
                if (flag.Handled)
                {
                    if (OnRequestedPathProcessed != null)
                    {
                        OnRequestedPathProcessed();
                    }
                    HttpContext.Current.Response.End();
                    return;
                }
            }

            // if we got this far, sorry folks, but you're about to get a boring ASP.Net 404 page.
        }