public long ReadPacketSize(byte[] packetData)
        {
            // Attempt an initial parse to get the headers.
            CommandServerPacket packet = new CommandServerPacket();
            CommandServerPacketSerializer.Parse(packet, packetData);

            long length = 0;

            // If the headers contain a content-length variable, use that.
            if (packet.Headers[HttpRequestHeader.ContentLength] != null) {
                // todo Potential issues with content encoding?

                if (long.TryParse(packet.Headers[HttpRequestHeader.ContentLength], out length) == false) {
                    length = packetData.Length;
                }
                else {
                    length += packet.Header.Length;
                }

                // The header/content separator.
                length += 4;
            }

            return length;
        }
        /// <summary>
        /// Takes in a request and does it's best to convert it to a command within Potato for execution.
        /// </summary>
        /// <param name="request">The http request for this command</param>
        /// <returns>The deserialized command or null if an error occured during deserialization</returns>
        public static ICommand DeserializeCommand(CommandServerPacket request) {
            ICommand command = null;

            try {
                switch (request.Headers[HttpRequestHeader.ContentType].ToLower()) {
                    default:
                        command = Core.Shared.Serialization.JsonSerialization.Minimal.Deserialize<Command>(request.Content);
                        break;
                }

                if (command != null) {
                    command.Origin = CommandOrigin.Remote;

                    HttpCommandRequest commandRequest = new HttpCommandRequest() {
                        Content = new List<String>() {
                            request.Header,
                            request.Content
                        },
                        Packets = new List<IPacket>() {
                            request.Packet
                        }
                    };

                    commandRequest.AppendTags(request.Headers);
                    commandRequest.AppendTags(request.Query);

                    command.Request = commandRequest;
                }
            }
            catch {
                command = null;
            }

            return command;
        }
        public IPacketWrapper Deserialize(byte[] packetData)
        {
            CommandServerPacket packet = new CommandServerPacket();

            CommandServerPacketSerializer.Parse(packet, packetData);
            packet.Query = CommandServerPacketSerializer.CombineNameValueCollections(CommandServerPacketSerializer.ParseGet(packet), CommandServerPacketSerializer.ParsePost(packet));

            return packet;
        }
        /// <summary>
        /// Serializes all of the header data to a byte array for transfer.
        /// </summary>
        /// <param name="packet"></param>
        /// <param name="content"></param>
        /// <returns></returns>
        protected byte[] SerializeHeader(CommandServerPacket packet, byte[] content)
        {
            StringBuilder builder = new StringBuilder();

            // Ensure a couple of headers are through..
            packet.Headers[HttpRequestHeader.Connection] = "close";
            packet.Headers[HttpRequestHeader.ContentLength] = content.Length.ToString(CultureInfo.InvariantCulture);

            builder.AppendFormat("HTTP/{0}.{1} {2} {3}\r\n", packet.ProtocolVersion.Major, packet.ProtocolVersion.Minor, (int)packet.StatusCode, packet.StatusCode);
            builder.Append(packet.Headers);
            // Already adds the double new lines.

            return Encoding.UTF8.GetBytes(builder.ToString());
        }
        /// <summary>
        /// Serializes the content to a byte array, optionally compressing it if the client has sent
        /// through that it accepts the encoding.
        /// </summary>
        /// <param name="packet"></param>
        /// <returns></returns>
        protected byte[] SerializeContent(CommandServerPacket packet)
        {
            byte[] data = Encoding.UTF8.GetBytes(packet.Content);

            if (packet.Headers[HttpRequestHeader.ContentEncoding] != null) {
                String contentEncoding = packet.Headers[HttpRequestHeader.ContentEncoding].ToLowerInvariant();

                if (contentEncoding.Contains("gzip") == true) {
                    data = CommandServerPacketSerializer.GzipCompress(data);
                }
                else if (contentEncoding.Contains("deflate") == true) {
                    data = CommandServerPacketSerializer.DeflateCompress(data);
                }
            }

            return data;
        }
        protected static NameValueCollection ParsePost(CommandServerPacket packet)
        {
            NameValueCollection query = new NameValueCollection();

            if (packet.Content != null) {
                query = HttpUtility.ParseQueryString(packet.Content);
            }

            return query;
        }
 protected static NameValueCollection ParseGet(CommandServerPacket packet)
 {
     return HttpUtility.ParseQueryString(packet.Request.Query);
 }
        protected static void Parse(CommandServerPacket packet, byte[] packetData)
        {
            String[] packetStringData = Regex.Split(Encoding.UTF8.GetString(packetData), @"\r\n\r\n");

            packet.Header = packetStringData.FirstOrDefault();

            // Fetch the rest of the content data for later.
            packet.Content = packetStringData.LastOrDefault();

            if (packet.Header != null) {
                string[] headers = packet.Header.Split(new [] {"\r\n"}, StringSplitOptions.RemoveEmptyEntries);

                if (headers.Length > 0) {
                    List<String> status = headers.First().Wordify();

                    var headerValues = packet.Header.Split(new [] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries).Skip(1).ToDictionary(
                        line => (line.Split(new[] { ":" }, 2, StringSplitOptions.RemoveEmptyEntries).FirstOrDefault() ?? "").Trim(),
                        line => (line.Split(new[] { ":" }, 2, StringSplitOptions.RemoveEmptyEntries).LastOrDefault() ?? "").Trim()
                    );

                    if (status.Count == 3 && headerValues.ContainsKey("Host") == true) {
                        packet.Request = new Uri("http://" + headerValues["Host"] + status[1]);
                        packet.Method = status[0];
                        packet.ProtocolVersion = new Version(status[2].Replace("HTTP/", ""));

                        foreach (var header in headerValues) {
                            try {
                                packet.Headers.Set(header.Key, header.Value);
                            }
                            catch {
                                packet.Headers.Set(header.Key, "");
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Serializes the result of the issued command back into the http response for the user.
        /// </summary>
        /// <param name="contentType">The content type to serialize the response to</param>
        /// <param name="response">The existing response packet to be modified with additional data/changes</param>
        /// <param name="result">The result of the command issued in the request</param>
        /// <returns>The existing response packet, modified with the result of the command execution.</returns>
        public static CommandServerPacket CompleteResponsePacket(String contentType, CommandServerPacket response, ICommandResult result) {
            switch (contentType) {
                case Mime.ApplicationJavascript:
                case Mime.TextCss:
                case Mime.TextHtml:
                    response.Headers.Add(HttpRequestHeader.ContentType, contentType);
                    response.Content = result.Now.Content != null ? result.Now.Content.FirstOrDefault() : "";
                    response.StatusCode = HttpStatusCode.OK;
                    break;
                default:
                    response.Headers.Add(HttpRequestHeader.ContentType, Mime.ApplicationJson);

                    using (StringWriter writer = new StringWriter()) {
                        Core.Shared.Serialization.JsonSerialization.Minimal.Serialize(writer, result);

                        response.Content = writer.ToString();
                    }

                    response.StatusCode = HttpStatusCode.OK;
                    break;
            }

            return response;
        }
Beispiel #10
0
        protected virtual void OnPacketReceived(IClient client, CommandServerPacket request)
        {
            var handler = PacketReceived;

            if (handler != null) {
                handler(client, request);
            }
        }
Beispiel #11
0
        /// <summary>
        /// Respondes to a packet, making sure the response matches the request.
        /// We've purposfully allowed direct packets to be sent in case we needed
        /// to deliberately bypass some of these.
        /// </summary>
        /// <param name="sender">The client that received the response.</param>
        /// <param name="request">The original packet received by the listener.</param>
        /// <param name="response">The response to send to the server.</param>
        public void Respond(IClient sender, CommandServerPacket request, CommandServerPacket response)
        {
            response.Method = request.Method;
            response.ProtocolVersion = request.ProtocolVersion;

            if (request.Headers[HttpRequestHeader.AcceptEncoding] != null) {
                String acceptEncoding = request.Headers[HttpRequestHeader.AcceptEncoding].ToLowerInvariant();

                if (acceptEncoding.Contains("gzip") == true) {
                    response.Headers[HttpRequestHeader.ContentEncoding] = "gzip";
                }
                else if (acceptEncoding.Contains("deflate") == true) {
                    response.Headers[HttpRequestHeader.ContentEncoding] = "deflate";
                }
            }

            sender.Send(response);
        }
        /// <summary>
        /// Called when a packet is recieved from the listening command server.
        /// </summary>
        /// <param name="client">The client to send back the response</param>
        /// <param name="request">The request packet recieved</param>
        public void OnPacketReceived(IClient client, CommandServerPacket request) {
            CommandServerPacket response = new CommandServerPacket() {
                Packet = {
                    Type = PacketType.Response,
                    Origin = PacketOrigin.Client,
                },
                ProtocolVersion = request.ProtocolVersion,
                Method = request.Method,
                StatusCode = HttpStatusCode.NotFound,
                Headers = new WebHeaderCollection() {
                    { HttpRequestHeader.Connection, "close" }
                }
            };
            
            ICommand command = CommandServerSerializer.DeserializeCommand(request);

            if (command != null) {
                ICommandResult authentication = this.Authenticate(request, command);

                if (authentication.Success == true) {
                    // If all they wanted to do was check the authentication..
                    if (String.CompareOrdinal(command.Name, CommandType.SecurityAccountAuthenticate.ToString()) == 0 || String.CompareOrdinal(command.Name, CommandType.SecurityAccountAuthenticateToken.ToString()) == 0) {
                        // Success
                        response = CommandServerSerializer.CompleteResponsePacket(CommandServerSerializer.ResponseContentType(command), response, authentication);
                    }
                    else {
                        // Propagate their command
                        ICommandResult result = this.Tunnel(command);

                        response = CommandServerSerializer.CompleteResponsePacket(CommandServerSerializer.ResponseContentType(command), response, result);
                    }
                }
                else {
                    // They are not authorized to login or issue this command.
                    response = CommandServerSerializer.CompleteResponsePacket(CommandServerSerializer.ResponseContentType(command), response, authentication);
                }
            }
            else {
                // Something wrong during deserialization, issue a bad request.
                response.StatusCode = HttpStatusCode.BadRequest;
            }

            this.CommandServerListener.Respond(client, request, response);
        }
        /// <summary>
        /// Authenticate the command given the request information.
        /// </summary>
        /// <remarks>
        ///     <para>This command only checks if the user is authenticated with our system, not if they can execute the command. This is accomplished while executing the command.</para>
        /// </remarks>
        /// <param name="request">The request information</param>
        /// <param name="command">The command to authenticate</param>
        /// <returns>The result of authentication</returns>
        protected ICommandResult Authenticate(CommandServerPacket request, ICommand command) {
            ICommandResult result = null;

            if (String.IsNullOrEmpty(command.Authentication.Username) == false && String.IsNullOrEmpty(command.Authentication.PasswordPlainText) == false) {
                result = this.Shared.Security.Tunnel(CommandBuilder.SecurityAccountAuthenticate(command.Authentication.Username, command.Authentication.PasswordPlainText, this.ExtractIdentifer(request)).SetOrigin(CommandOrigin.Remote));
            }
            else if (command.Authentication.TokenId != Guid.Empty && String.IsNullOrEmpty(command.Authentication.Token) == false) {
                result = this.Shared.Security.Tunnel(CommandBuilder.SecurityAccountAuthenticateToken(command.Authentication.TokenId, command.Authentication.Token, this.ExtractIdentifer(request)).SetOrigin(CommandOrigin.Remote));
            }
            else {
                result = new CommandResult() {
                    Success = false,
                    CommandResultType = CommandResultType.Failed,
                    Message = "Invalid username or password"
                };
            }

            return result;
        }
        /// <summary>
        /// Pulls the identifer out of the request (endpoint address)
        /// </summary>
        /// <param name="request">The request received from the client</param>
        /// <returns>The extracted identifer or an empty string if none exists</returns>
        protected String ExtractIdentifer(CommandServerPacket request) {
            var identifer = "";

            if (request != null && request.Packet != null && request.Packet.RemoteEndPoint != null && request.Packet.RemoteEndPoint.Address != null) {
                identifer = request.Packet.RemoteEndPoint.Address.ToString();
            }

            return identifer;
        }