Пример #1
0
        private bool RunTemplate(WebData data)
        {
            IDictionary <string, WebTemplate> templates = this.templates;

            if (templates == null)
            {
                return(false);
            }

            string key = Uri.UnescapeDataString(data.Request.DecodedUrl).TrimStart('/');

            if (key == string.Empty)
            {
                key = "index";
            }

            if (!templates.TryGetValue(key, out WebTemplate caveWebTemplate))
            {
                string str = FileSystem.Combine(data.Server.StaticFilesPath, key + ".cwt");
                if (!FileSystem.IsRelative(str, data.Server.StaticFilesPath))
                {
                    throw new WebServerException(WebError.NotFound, 0, string.Format("{0} not found!", key));
                }
                if (!File.Exists(str))
                {
                    return(false);
                }

                templates[key] = caveWebTemplate = new WebTemplate(data.Server, str);
            }
            return(caveWebTemplate.Render(data));
        }
Пример #2
0
        /// <summary>Entry point for explain.</summary>
        /// <param name="data">The data.</param>
        /// <exception cref="WebServerException">Error during explain.</exception>
        public void Explain(WebData data)
        {
            string name = null, type = null;

            try
            {
                if (data.Request.Parameters.Count > 0)
                {
                    if (data.Request.Parameters.TryGetValue("function", out name))
                    {
                        type = "function";
                        ExplainFunction(data, name);
                        return;
                    }
                    if (data.Request.Parameters.TryGetValue("type", out name))
                    {
                        type = "type";
                        ExplainType(data, name);
                        return;
                    }
                }
                ExplainFunctionList(data);
            }
            catch (Exception ex)
            {
                if (ex is WebServerException)
                {
                    throw;
                }

                Trace.TraceError("Error during explain <cyan>{0} <magenta>{1}.", type, name);
                throw new WebServerException(WebError.InternalServerError, 0, "Error during explain {0} {1}.", type, name);
            }
        }
Пример #3
0
        void ExplainStruct(WebData data, Type t)
        {
            var html = new HtmlPageBuilder(data.Request);

            html.Breadcrump.Add(new WebLink()
            {
                Text = t.FullName
            });
            Bootstrap4 content = html.Content;
            var        layout  = RowLayout.CreateTyped(t);

            content.CardOpen($"<h2>Struct {t.Name}<h2><h4>Table {layout.Name}</h4>{layout.FieldCount} Fields, {t.AssemblyQualifiedName}");

            DocumentHtml(content, documentation.GetType(t), t.ToString());
            content.ListGroupOpen();
            int i = 0;

            foreach (FieldProperties field in layout.Fields)
            {
                XNetDocItem doc = documentation.GetField(t, field.Name.ToString());
                FieldHtml(content, i++, field, doc);
            }
            content.ListGroupClose();
            content.CardClose();
            content.AddHtml("&nbsp;");
            var message = WebMessage.Create("Explain " + t.Name, string.Format("Explain struct {0}", t.Name));

            data.Answer = html.ToAnswer(message);
        }
Пример #4
0
        void ExplainEnum(WebData data, Type t)
        {
            var html = new HtmlPageBuilder(data.Request);

            html.Breadcrump.Add(new WebLink()
            {
                Text = t.FullName
            });
            Bootstrap4 content = html.Content;

            content.CardOpenText($"Enum {t.Name}");
            DocumentHtml(content, documentation.GetEnum(t), t.ToString());
            content.ListGroupOpen();
            int i = 0;

            foreach (object value in Enum.GetValues(t))
            {
                XNetDocItem doc = documentation.GetField(t, value.ToString());
                FieldHtml(content, i++, value, doc);
            }
            content.ListGroupClose();
            content.CardClose();
            content.AddHtml("&nbsp;");
            var message = WebMessage.Create("Explain " + t.Name, string.Format("Explain enum {0}", t.Name));

            data.Answer = html.ToAnswer(message);
        }
Пример #5
0
 void SslHandshake()
 {
     if (WebServer.Certificate == null)
     {
         Reader = new DataReader(Stream, newLineMode: NewLineMode.CRLF);
         Writer = new DataWriter(Stream, newLineMode: NewLineMode.CRLF);
         return;
     }
     try
     {
         var sslStream = new SslStream(Stream);
         sslStream.AuthenticateAsServer(WebServer.Certificate);
         Reader = new DataReader(sslStream, newLineMode: NewLineMode.CRLF);
         Writer = new DataWriter(sslStream, newLineMode: NewLineMode.CRLF);
         if (WebServer.PerformanceChecks)
         {
             Trace.TraceInformation("SslHandshake completed. Elapsed {0}.", StopWatch.Elapsed.FormatTime());
         }
     }
     catch (Exception ex)
     {
         if (WebServer.PerformanceChecks)
         {
             Trace.TraceError("SslHandshake <red>error<default> {1}. Elapsed {0}.", StopWatch.Elapsed.FormatTime(), ex);
         }
         var data = new WebData(WebServer, StopWatch);
         data.Result.AddMessage("SslHandshake", WebError.ClientError, $"Http connections are not supported!");
         data.Result.Type             = WebResultType.Html;
         data.Result.CloseAfterAnswer = true;
         SendAnswer(data);
     }
 }
Пример #6
0
 void ExplainFunction(WebData data, string name)
 {
     if (!data.Server.RegisteredPaths.TryGetValue(name, out WebServerMethod function))
     {
         throw new WebServerException(WebError.InvalidParameters, 0, "Unknown function or function not registered!");
     }
     ExplainFunction(data, function);
 }
Пример #7
0
        public void SendAnswer(WebData data)
        {
            if (data.Answer == null)
            {
                if (data.Result == null)
                {
                    throw new Exception("Al least one of Result or Answer has to be set!");
                }

                data.Answer = data.Result.ToAnswer();
                data.Result = null;
            }
            else if (data.Result != null)
            {
                // add all headers present at result to answer.
                foreach (System.Collections.Generic.KeyValuePair <string, string> header in data.Result.Headers)
                {
                    if (!data.Answer.Headers.ContainsKey(header.Key))
                    {
                        data.Answer.Headers[header.Key] = header.Value;
                    }
                }
            }

            data.Answer.Headers["To"] = data.Request.SourceAddress;
            if (!data.Answer.Headers.ContainsKey("Cache-Control"))
            {
                data.Answer.Headers["Cache-Control"] = "no-cache, must-revalidate, post-check=0, pre-check=0";
            }
            if (data.Session != null)
            {
                switch (WebServer.SessionMode)
                {
                case WebServerSessionMode.Cookie:
                    data.Answer.Headers["Session"] = data.Session.ID.ToString();
                    if (WebServer.SessionMode == WebServerSessionMode.Cookie)
                    {
                        data.Answer.Headers["Set-Cookie"] = $"Session={data.Session.ID}; Path=/; Max-Age=" + (int)data.Server.SessionTimeout.TotalSeconds;
                    }

                    break;

                case WebServerSessionMode.SenderID:
                    data.Answer.Headers["Session"] = data.Session.ID.ToString();
                    break;

                case WebServerSessionMode.None: break;

                default: throw new NotImplementedException();
                }
            }
            SendAnswer(data.Answer);
        }
Пример #8
0
        /// <summary>Initializes a new instance of the <see cref="WebServerAuthEventArgs" /> class.</summary>
        public WebServerAuthEventArgs(WebData data)
        {
            Data = data;

            // basic auth ?
            data.Request.Headers.TryGetValue("authorization", out string value);
            if (value != null)
            {
                string[] auth = value.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
                switch (auth[0].ToLower())
                {
                case "basic":
                    string[] parts = Base64.Default.DecodeUtf8(auth[1]).Split(new char[] { ':' }, 2);
                    Username = parts[0];
                    Password = parts[1];
                    AuthType = WebServerAuthType.Basic;
                    return;

                default:
                    throw new NotImplementedException();
                }
            }
        }
Пример #9
0
        void ExplainType(WebData data, string name)
        {
            Type t = AppDom.FindType(name, AppDom.LoadMode.NoException);

            if (t == null)
            {
                throw new WebServerException(WebError.InvalidParameters, 0, string.Format("Type {0} is unknown!", name));
            }

            if (t != null)
            {
                if (t.IsEnum)
                {
                    ExplainEnum(data, t);
                    return;
                }
                if (!t.IsPrimitive && t.IsValueType)
                {
                    ExplainStruct(data, t);
                    return;
                }
            }
            throw new WebServerException(WebError.InvalidOperation, 0, string.Format("Type {0} cannot be explained!", name));
        }
Пример #10
0
        void GetStaticFileListing(WebData data)
        {
            string url     = Uri.UnescapeDataString(data.Request.DecodedUrl).Trim('/');
            string path    = FileSystem.Combine(StaticFilesPath, url);
            var    entries = new List <WebDirectoryEntry>();
            string root    = FileSystem.Combine(path, "..");

            if (FileSystem.IsRelative(root, StaticFilesPath))
            {
                FileSystemInfo info  = new DirectoryInfo(root);
                var            entry = new WebDirectoryEntry()
                {
                    DateTime = info.LastWriteTime,
                    Name     = "..",
                    Type     = WebDirectoryEntryType.Directory,
                    Link     = "/" + url + "/..",
                };
                entries.Add(entry);
            }
            if (FileSystem.IsRelative(path, StaticFilesPath))
            {
                foreach (string dir in Directory.GetDirectories(path))
                {
                    FileSystemInfo info  = new DirectoryInfo(dir);
                    var            entry = new WebDirectoryEntry()
                    {
                        DateTime = info.LastWriteTime,
                        Name     = info.Name,
                        Type     = WebDirectoryEntryType.Directory,
                        Link     = "/" + FileSystem.Combine('/', url, info.Name),
                    };
                    entries.Add(entry);
                }
                foreach (string file in Directory.GetFiles(path))
                {
                    var info  = new FileInfo(file);
                    var entry = new WebDirectoryEntry()
                    {
                        DateTime = info.LastWriteTime,
                        Size     = info.Length,
                        Name     = info.Name,
                        Type     = WebDirectoryEntryType.File,
                        Link     = "/" + FileSystem.Combine('/', url, info.Name),
                    };
                    entries.Add(entry);
                }
            }
            var pb = new HtmlPageBuilder(data.Request);

            pb.Content.CardOpenText($"File Listing:");
            pb.Content.ParagraphText($"{entries.Count} entries");
            pb.Content.TableOpen(new string[] { "Type", "Size", "Name" }, "table-striped table-responsive");
            foreach (WebDirectoryEntry entry in entries)
            {
                pb.Content.TableRowOpen();
                pb.Content.TableHtmlCell(Bootstrap4.GetBadge(entry.Type.ToString(), "badge-default"));
                pb.Content.TableCell(entry.Type == WebDirectoryEntryType.Directory ? string.Empty : entry.Size.FormatBinarySize());
                pb.Content.TableHtmlCell(Bootstrap4.GetLink(entry.Name, entry.Link));
                pb.Content.TableRowClose();
            }
            pb.Content.TableClose();
            pb.Content.CardClose();
            pb.Content.AddHtml("&nbsp;");
            data.Answer = pb.ToAnswer(WebMessage.Create("FileListing", "File listing retrieved."));
        }
Пример #11
0
        void HandleRequest(WebServerClient client, WebData data)
        {
            // add acl headers
            if (Certificate != null)
            {
                data.Result.Headers["Strict-Transport-Security"] = "max-age=604800; includeSubDomains";
            }

            data.Result.Headers["Access-Control-Allow-Headers"] = "Session";
            if (data.Method?.PageAttribute?.AuthType == WebServerAuthType.Basic)
            {
                data.Result.Headers["Access-Control-Allow-Credentials"] = "true";
                data.Result.Headers["Access-Control-Allow-Headers"]    += ", Authorization";
            }
            if (!data.Result.Headers.ContainsKey("Access-Control-Allow-Origin"))
            {
                data.Result.Headers["Access-Control-Allow-Origin"] = string.IsNullOrEmpty(data.Request.Origin) ? "*" : data.Request.Origin;
            }

            if (!data.Result.Headers.ContainsKey("Access-Control-Allow-Methods"))
            {
                data.Result.Headers["Access-Control-Allow-Methods"] = "POST, GET, OPTIONS";
            }

            if (data.Method?.PageAttribute?.AllowHeaders != null)
            {
                data.Result.Headers["Access-Control-Allow-Headers"] += ", " + data.Method.PageAttribute.AllowHeaders;
            }

            if (data.Request.Command == WebCommand.OPTIONS)
            {
                data.Result.AddMessage(data.Method, "Options transfered successfully.");
                client.SendAnswer(data);
                return;
            }

            data.Request.LoadPost(client);

            if (data.Method == null)
            {
                Trace.TraceInformation("Static Request: {0}", data.Request);

                if (StaticRequest != null)
                {
                    var e = new WebPageEventArgs(data);
                    StaticRequest(this, e);
                    if (e.Handled)
                    {
                        client.SendAnswer(data);
                        return;
                    }
                }

                if (EnableTemplates && RunTemplate(data))
                {
                    Trace.TraceInformation("Template: {0} {1}", data.Request, data.Result);
                    client.SendAnswer(data);
                    return;
                }

                // no method - send static file ?
                WebAnswer staticFile = GetStaticFile(data.Request);
                if (staticFile != null)
                {
                    // file present, send answer
                    Trace.TraceInformation("Static file: {0} {1}", data.Request, staticFile);
                    SetStaticCacheTime(staticFile, StaticPathCacheTime);
                    client.SendAnswer(staticFile);
                    return;
                }

                // static path access -> set cache time
                SetStaticCacheTime(data, StaticPathCacheTime);

                // file not present, check special functions
                if (EnableExplain && (data.Request.DecodedUrl.ToLower() == "/explain" || data.Request.DecodedUrl.ToLower() == "/functionlist"))
                {
                    // special page (function list / explain)
                    explain.Explain(data);
                }
                else if (EnableFileListing)
                {
                    // list files
                    GetStaticFileListing(data);
                }
                else
                {
                    // no static -> error
                    data.Result.AddMessage(data.Request.PlainUrl, WebError.NotFound, $"The requested URL {data.Request.DecodedUrl} was not found on this server.");
                }
                client.SendAnswer(data);
                return;
            }

            // invoke method
            CallMethod(data);

            // send answer
            client.SendAnswer(data);
        }
Пример #12
0
        /// <summary>Handles a client stage1 (preparations).</summary>
        /// <remarks>Performs the firewall checks and enters stage2.</remarks>
        internal void HandleClient(WebServerClient client)
        {
            System.Globalization.CultureInfo threadCulture = Thread.CurrentThread.CurrentCulture;
            int threadId            = Thread.CurrentThread.ManagedThreadId;
            WebResultBuilder result = null;

            try
            {
                // callback for connected client
                ClientConnected?.Invoke(this, new WebClientEventArgs(client));

                // do request handling
                int requestNumber = 0;
                if (PerformanceChecks)
                {
                    Trace.TraceInformation(
                        $"HandleClient [{threadId}] <cyan>{client.RemoteEndPoint}<default> ready to receive request. " +
                        $"Elapsed <cyan>{client.StopWatch.Elapsed.FormatTime()}<default>.");
                }
                while (client.IsConnected)
                {
                    result = null;
                    if (PerformanceChecks && requestNumber > 0)
                    {
                        Trace.TraceInformation(
                            $"HandleClient [{threadId}] <cyan>{client.RemoteEndPoint}<default> request <green>{requestNumber}<default> handling completed. " +
                            $"Elapsed <cyan>{client.StopWatch.Elapsed.FormatTime()}<default>.");
                    }

                    // read first request line
                    string firstLine = client.Reader.ReadLine();
                    client.StopWatch.Reset();
                    if (PerformanceChecks)
                    {
                        Trace.TraceInformation(
                            $"HandleClient [{threadId}] <cyan>{client.RemoteEndPoint}<default> start handling request <cyan>{++requestNumber}<default>. " +
                            $"Elapsed <cyan>{client.StopWatch.Elapsed.FormatTime()}<default>.");
                    }

                    // load request
                    var request = WebRequest.Load(this, firstLine, client);

                    // prepare web data object
                    var data = new WebData(request, client.StopWatch);
                    result = data.Result;

                    // update thread culture
                    Thread.CurrentThread.CurrentCulture = data.Request.Culture;

                    // handle request but change some default exceptions to web exceptions
                    try { HandleRequest(client, data); }
                    catch (ObjectDisposedException)
                    {
                        Trace.TraceInformation($"HandleClient [{threadId}] <red>{client.RemoteEndPoint}<default> Connection closed");
                    }
                    catch (InvalidOperationException ex) { throw new WebServerException(ex, WebError.InvalidOperation, 0, ex.Message); }
                    catch (ArgumentException ex) { throw new WebServerException(ex, WebError.InvalidParameters, 0, ex.Message); }
                }
            }
            catch (WebServerException ex)
            {
                Trace.TraceInformation(ex.ToString());
                if (result == null)
                {
                    result = new WebResultBuilder(this);
                }

                result.AddMessage(WebMessage.Create(ex));
                if (ex.Error == WebError.AuthenticationRequired || ex.Error == WebError.InvalidTransactionKey)
                {
                    result.Headers["WWW-Authenticate"] = $"Basic realm=\"{AssemblyVersionInfo.Program.Company} - {AssemblyVersionInfo.Program.Product}\"";
                }
                result.CloseAfterAnswer = true;
                client.SendAnswer(result.ToAnswer());
            }
            catch (SocketException)
            {
                Trace.TraceInformation($"HandleClient [{threadId}] <red>{client.RemoteEndPoint}<default> Connection closed");
                /*client closed connection*/
            }
            catch (EndOfStreamException)
            {
                /*client closed connection*/
                Trace.TraceInformation($"HandleClient [{threadId}] <red>{client.RemoteEndPoint}<default> Connection closed");
            }
            catch (Exception ex)
            {
                if (ex.InnerException is SocketException)
                {
                    Trace.TraceInformation($"HandleClient [{threadId}] <red>{client.RemoteEndPoint}<default> Connection closed");
                    return;
                }

                string supportCode = Base32.Safe.Encode(Environment.TickCount);
                Trace.TraceError("<red>Unhandled Internal Server Error<default> Code {1}\n{0}", ex.ToString(), supportCode);

                if (result == null)
                {
                    result = new WebResultBuilder(this);
                }

                result.AddMessage(ex.Source, WebError.InternalServerError, $"Internal Server Error\nUnexpected result on request.\nPlease contact support!\nSupport Code = {supportCode}");
                result.CloseAfterAnswer = true;
                client.SendAnswer(result.ToAnswer());
            }
            finally
            {
                while (client.IsConnected && client.Reader.Available == 0)
                {
                    Thread.Sleep(1);
                }

                client.Close();
                if (client != null)
                {
                    ClientDisconnected?.Invoke(this, new WebClientEventArgs(client));
                }

                // reset thread culture
                if (Thread.CurrentThread.CurrentCulture != threadCulture)
                {
                    Thread.CurrentThread.CurrentCulture = threadCulture;
                }
            }
        }
Пример #13
0
        /// <summary>Builds the template.</summary>
        /// <param name="data">The data.</param>
        /// <returns>Returns true on success, false otherwise.</returns>
        public bool Render(WebData data)
        {
            if (data.Server != server)
            {
                throw new ArgumentOutOfRangeException(nameof(data.Server));
            }

            { // need reload ?
                DateTime lastChanged = FileSystem.GetLastWriteTimeUtc(FileName);
                if (lastChanged != LastChanged)
                {
                    Reload();
                }
            }

            // do auth and load user session (if any)
            data.Result.SkipMainObject = true;
            data.Result.TransmitLayout = false;

            // call functions
            IDictionary <string, string> templateParameters = data.Request.Parameters;
            var tables = new Set <string>();
            var parameterDescription = new List <WebTemplateParameter>();

            for (int i = 0; i < functions.Length; i++)
            {
                Func function = functions[i];
                parameterDescription.AddRange(function.ParameterDescriptions);
                if (function.NeededParameters.Count > 0)
                {
                    // foreach neededparameters, any parameter is not at tmeplate parameters -> continue
                    if (function.NeededParameters.Where(n => !templateParameters.ContainsKey(n)).Any())
                    {
                        continue;
                    }
                }
                var functionParameters = new Dictionary <string, string>();
                foreach (System.Reflection.ParameterInfo methodParameter in function.Method.Parameters)
                {
                    // lookup function parameter name from function section at template
                    if (!function.Parameters.TryGetValue(methodParameter.Name, out string templateParameterName))
                    {
                        continue;
                    }

                    // parameter name at template could be loaded
                    if (!templateParameters.TryGetValue(templateParameterName, out string parameterValue))
                    {
                        if (!methodParameter.IsOptional)
                        {
                            // no value given and is not optional
                            throw new WebServerException(WebError.InvalidParameters, $"Template error: Missing {methodParameter.Name} is not for function {function} is not set. Define {templateParameterName} at template call!");
                        }
                        continue;
                    }
                    functionParameters[methodParameter.Name] = parameterValue;
                }
                data.Request.Parameters = new ReadOnlyDictionary <string, string>(functionParameters);

                // invoke method
                data.Method = function.Method;
                data.Server.CallMethod(data);
            }

            Stopwatch renderWatch = server.PerformanceChecks ? Stopwatch.StartNew() : null;

            // replace content
            byte[] result = staticData ?? BuildStaticData(content);

            if (renderWatch != null)
            {
                Trace.TraceInformation("Template static data generation took {0}", renderWatch.Elapsed.FormatTime());
            }

            // render data
            {
                data.Result.Type = WebResultType.Json;
                data.Result.AddStructs(parameterDescription);
                WebAnswer answer = data.Result.ToAnswer();
                result = result.ReplaceFirst(Tag, ScriptStart, answer.ContentData, ScriptEnd);
            }

            // set result
            data.Result = null;

            WebMessage message;

            if (data.Method != null)
            {
                message = WebMessage.Create(data.Method, $"Template call <cyan>{data.Request}<default> succeeded.");
            }
            else
            {
                message = WebMessage.Create($"Static {data.Request.PlainUrl}", $"Template call <cyan>{data.Request}<default> succeeded.");
            }

            data.Answer = WebAnswer.Raw(data.Request, message, result, "text/html");
            return(true);
        }
Пример #14
0
        /// <summary>Invokes the method using the specified data.</summary>
        /// <param name="data">The data.</param>
        /// <exception cref="WebServerException">
        /// Could not convert parameter {0} value {1} to type {2}
        /// or
        /// Function {0}\nParameter {1} is missing!.
        /// </exception>
        public void Invoke(WebData data)
        {
            data.Server.OnCheckSession(data);

            // auth required ?
            if (PageAttribute.AuthType != WebServerAuthType.None)
            {
                if (!data.Session.IsAuthenticated())
                {
                    Trace.TraceInformation("{0} {1}: Error call to <red>{2}<default> requires a valid user account. Elapsed {3}", data.Request.SourceAddress, data.Session, data.Request.DecodedUrl, data.Elapsed.FormatTime());
                    data.Result.AddMessage(data.Method, WebError.AuthenticationRequired, $"The requested URL {data.Request.DecodedUrl} requires a valid user account.");
                    if (data.Method?.PageAttribute?.AuthType == WebServerAuthType.Basic)
                    {
                        data.Result.Headers["WWW-Authenticate"] = $"Basic realm=\"{AssemblyVersionInfo.Program.Company} - {AssemblyVersionInfo.Program.Product}\"";
                    }
                    return;
                }
                data.Server.OnCheckAccess(data);
            }

            if (data.Server.VerboseMode)
            {
                Trace.TraceInformation("Request {0} Invoke Method {1}", data.Request, data.Method);
            }

            if (instance is Action <WebData> func)
            {
                func.Invoke(data);
                if (data.Server.VerboseMode)
                {
                    Trace.TraceInformation("{0} {1}: Completed call to <green>{2}<default>. Elapsed {3}", data.Request.SourceAddress, data.Session, Name, data.Elapsed.FormatTime());
                }

                return;
            }

            var usedParameters = new Set <string>(data.Request.Parameters.Keys);
            var parameters     = new ArrayList();

            foreach (ParameterInfo p in Method.GetParameters())
            {
                if (p.ParameterType == typeof(WebData))
                {
                    parameters.Add(data);
                    continue;
                }
                if (data.Request.Parameters.ContainsKey(p.Name))
                {
                    string value = data.Request.Parameters[p.Name];
                    if (value.Trim().Length > 0)
                    {
                        try
                        {
                            parameters.Add(Fields.ConvertValue(p.ParameterType, value, CultureInfo.InvariantCulture));
                        }
                        catch (Exception ex)
                        {
                            throw new WebServerException(ex, WebError.InvalidParameters, 0, string.Format("Could not convert parameter {0} value {1} to type {2}", p.Name, value, p.ParameterType.Name));
                        }
                        continue;
                    }
                }
                if (data.Request.MultiPartFormData != null)
                {
                    if (data.Request.MultiPartFormData.TryGet(p.Name, out WebSinglePart part))
                    {
                        // binary ?
                        if (p.ParameterType == typeof(byte[]))
                        {
                            parameters.Add(part.Content);
                        }
                        else
                        {
                            // no convert from string
                            string value = Encoding.UTF8.GetString(part.Content);
                            parameters.Add(Fields.ConvertValue(p.ParameterType, value, CultureInfo.InvariantCulture));
                        }
                        continue;
                    }
                }
                if (p.IsOptional)
                {
                    try
                    {
#if NET_45
                        if (p.HasDefaultValue)
#endif
                        {
                            parameters.Add(p.DefaultValue);
                            continue;
                        }
                    }
                    catch { Trace.TraceError("Invalid default value at parameter {0}!", p); }
                    parameters.Add(null);
                    continue;
                }
                throw new WebServerException(WebError.InvalidParameters, 0, string.Format("Function {0}\nParameter {1} is missing!", this, p.Name));
            }

            if (!PageAttribute.AllowAnyParameters)
            {
                foreach (string name in Method.GetParameters().Select(p => p.Name))
                {
                    usedParameters.TryRemove(name);
                }
                if (usedParameters.Count > 0)
                {
                    throw new WebServerException(WebError.InvalidParameters, 0, string.Format("Function {0}\nParameter {1} is unknown!", this, usedParameters.First()));
                }
            }

            Method.Invoke(instance, parameters.ToArray());
            if (data.Server.VerboseMode)
            {
                Trace.TraceInformation("{0} {1}: Completed call to <green>{2}<default>. Elapsed {3}", data.Request.SourceAddress, data.Session, Name, data.Elapsed.FormatTime());
            }
        }
Пример #15
0
        void ExplainFunction(WebData data, WebServerMethod function)
        {
            var html = new HtmlPageBuilder(data.Request);
            {
                string   path  = string.Empty;
                string[] parts = function.FullPaths.First().Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                int      last  = parts.Length - 1;
                for (int n = 0; n < parts.Length; n++)
                {
                    path += "/" + parts[n];
                    html.Breadcrump.Add(new WebLink()
                    {
                        Text = parts[n], Link = (n != last) ? $"/Explain?functions={path}" : $"/Explain?function={path}"
                    });
                }
            }

            Bootstrap4        content  = html.Content;
            WebServerAuthType authType = function.PageAttribute?.AuthType ?? WebServerAuthType.None;
            {
                string link = function.FullPaths.First();
                var    head = new Bootstrap4();
                if (authType != WebServerAuthType.None)
                {
                    // head.DivOpen(Bootstrap4.Item.float_right);
                    head.DivOpen(Bootstrap4.Item.float_right);
                    AddBadges(head, function.PageAttribute);
                    head.DivClose(Bootstrap4.Item.float_right);

                    // head.AddHtml("<br/>");
                }
                head.AddHtml("<h2>");
                head.AddHtml(function.Method.Name.SplitCamelCase().Join("&nbsp;"));
                if (function.Parameters.Length > 0)
                {
                    head.AddHtml(" (");
                    head.AddHtml(function.ParameterString());
                    head.AddHtml(")");
                }
                head.AddHtml("</h2>");

                head.DivOpen(Bootstrap4.Item.float_right);
                head.Link("html", link + ".html", "btn btn-sm btn-outline-primary");
                head.Link("json", link + ".json", "btn btn-sm btn-outline-primary");
                head.Link("xml", link + ".xml", "btn btn-sm btn-outline-primary");
                head.Link("plain", link + ".txt", "btn btn-sm btn-outline-primary");
                head.DivClose(Bootstrap4.Item.float_right);

                head.AddHtml(function.Method.DeclaringType.AssemblyQualifiedName);
                content.CardOpen(head.ToString());
            }
            XNetDocItem doc = documentation.GetMethod(function.Method);

            DocumentHtml(content, doc, function.IsAction ? "Generic action" : function.Method.ToString());
            content.ListGroupOpen();
            int i = 0;

            foreach (ParameterInfo parameter in function.Parameters)
            {
                if (parameter.ParameterType == typeof(WebData))
                {
                    continue;
                }

                ParameterHtml(content, i++, parameter, doc);
            }
            content.ListGroupClose();
            content.CardClose();
            content.AddHtml("&nbsp;");
            var message = WebMessage.Create("Explain " + function.Name, string.Format("Explain function {0}", function));

            data.Answer = html.ToAnswer(message);
        }
Пример #16
0
        void ExplainFunctionList(WebData data)
        {
            var html = new HtmlPageBuilder(data.Request);

            IEnumerable <KeyValuePair <string, WebServerMethod> > paths = data.Server.RegisteredPaths;

            if (data.Request.Parameters.TryGetValue("functions", out string functions))
            {
                string   path  = string.Empty;
                string[] parts = functions.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
                for (int n = 0; n < parts.Length; n++)
                {
                    path += "/" + parts[n];
                    html.Breadcrump.Add(new WebLink()
                    {
                        Text = parts[n], Link = $"/Explain?functions={path}"
                    });
                }
                paths = paths.Where(p => p.Key.StartsWith(functions));
            }

            Bootstrap4 content = html.Content;

            content.ListGroupOpen();
            int i = 0;

            ILookup <WebServerMethod, string> lookup = paths.ToLookup(p => p.Value, p => p.Key);

            foreach (IGrouping <WebServerMethod, string> item in lookup)
            {
                WebServerMethod function = item.Key;

                // if (item.Key == "/") continue;
                content.ListGroupItemOpen(i++ % 2 == 0 ? " list-group-item-info" : null);
                XNetDocItem doc = documentation.GetMethod(function.Method);

                content.AddHtml("<div style=\"width:100%\">");
                content.DivOpen(Bootstrap4.Item.row);
                WebServerAuthType authType = function.PageAttribute?.AuthType ?? WebServerAuthType.None;
                if (authType != WebServerAuthType.None)
                {
                    content.DivOpen(Bootstrap4.Item.col, "col-12 col-sm-auto flex-sm-last");
                    AddBadges(content, function.PageAttribute);
                    content.DivClose(Bootstrap4.Item.col);
                }
                content.DivOpen(Bootstrap4.Item.col);
                content.AddHtml("<h4>");
                content.AddHtml(function.Method.Name.SplitCamelCase().Join(" "));
                if (function.Parameters.Length > 0)
                {
                    content.AddHtml(" (");
                    content.AddHtml(function.ParameterString());
                    content.AddHtml(")");
                }
                content.AddHtml("</h4>");
                content.DivClose(Bootstrap4.Item.col);
                content.DivClose(Bootstrap4.Item.row);

                foreach (string path in item)
                {
                    content.DivOpen(Bootstrap4.Item.row);
                    content.DivOpen(Bootstrap4.Item.col);
                    content.Link(path, $"Explain?function={path}");
                    content.DivClose(Bootstrap4.Item.col);

                    content.DivOpen(Bootstrap4.Item.col, "col-12 col-sm-auto");
                    content.Link("html", path + ".html", "btn btn-sm btn-outline-primary");
                    content.Link("json", path + ".json", "btn btn-sm btn-outline-primary");
                    content.Link("xml", path + ".xml", "btn btn-sm btn-outline-primary");
                    content.Link("plain", path + ".txt", "btn btn-sm btn-outline-primary");
                    content.DivClose(Bootstrap4.Item.col);
                    content.DivClose(Bootstrap4.Item.row);
                }

                if (doc?.Summary != null)
                {
                    content.DivOpen(Bootstrap4.Item.row);
                    content.DivOpen(Bootstrap4.Item.col);
                    content.AddHtml("<strong>Description:</strong>");
                    int cdata = doc.Summary.IndexOf("<![CDATA[");
                    if (cdata > -1)
                    {
                        content.Text(doc.Summary.Substring(0, cdata));
                        content.AddHtml("<br/><code>");
                        string code     = doc.Summary.Substring(cdata + 9);
                        int    cdataEnd = code.IndexOf("]]>");
                        content.AddHtml(code.Substring(0, cdata));
                        content.AddHtml("</code>");
                        content.Text(doc.Summary.Substring(cdata + cdataEnd + 9 + 3));
                    }
                    else
                    {
                        content.Text(doc.Summary);
                    }
                    content.DivClose(Bootstrap4.Item.col);
                    content.DivClose(Bootstrap4.Item.row);
                }
                content.AddHtml("</div>");
                content.ListGroupItemClose();
            }
            content.ListGroupClose();
            content.AddHtml("&nbsp;");
            var message = WebMessage.Create("Explain", functions == null ? "Explain functions." : $"Explain {functions} functions.");

            data.Answer = html.ToAnswer(message);
        }