コード例 #1
0
ファイル: Connection.cs プロジェクト: whitestone7/PTVS
        internal static async Task <JObject> ReadPacketAsJObject(ProtocolReader reader)
        {
            var line = await ReadPacket(reader).ConfigureAwait(false);

            if (line == null)
            {
                return(null);
            }

            string  message = "";
            JObject packet  = null;

            try {
                // JObject.Parse is more strict than JsonConvert.DeserializeObject<JObject>,
                // the latter happily deserializes malformed json.
                packet = JObject.Parse(line);
            } catch (JsonSerializationException ex) {
                message = ": " + ex.Message;
            } catch (JsonReaderException ex) {
                message = ": " + ex.Message;
            }

            if (packet == null)
            {
                throw new InvalidDataException("Failed to parse packet" + message);
            }

            return(packet);
        }
コード例 #2
0
        /// <summary>
        /// Reads a single message from the protocol buffer.  First reads in any headers until a blank
        /// line is received.  Then reads in the body of the message.  The headers must include a Content-Length
        /// header specifying the length of the body.
        /// </summary>
        private static async Task <string> ReadPacket(ProtocolReader reader)
        {
            Dictionary <string, string> headers = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            string line;

            while ((line = await reader.ReadHeaderLineAsync().ConfigureAwait(false)) != null)
            {
                if (String.IsNullOrEmpty(line))
                {
                    // end of headers for this request...
                    break;
                }
                var split = line.Split(_headerSeparator, 2);
                if (split.Length != 2)
                {
                    // Probably getting an error message, so read all available text
                    var error = line;
                    try {
                        // Encoding is uncertain since this is malformed
                        error += Encoding.UTF8.GetString(await reader.ReadToEndAsync());
                    } catch (ArgumentException) {
                    }
                    throw new InvalidDataException("Malformed header, expected 'name: value'" + Environment.NewLine + error);
                }
                headers[split[0]] = split[1];
            }

            if (line == null)
            {
                return(null);
            }

            string contentLengthStr;
            int    contentLength;

            if (!headers.TryGetValue(Headers.ContentLength, out contentLengthStr))
            {
                throw new InvalidDataException("Content-Length not specified on request");
            }

            if (!Int32.TryParse(contentLengthStr, out contentLength) || contentLength < 0)
            {
                throw new InvalidDataException("Invalid Content-Length: " + contentLengthStr);
            }

            var contentBinary = await reader.ReadContentAsync(contentLength);

            if (contentBinary.Length != contentLength)
            {
                throw new InvalidDataException(string.Format("Content length does not match Content-Length header. Expected {0} bytes but read {1} bytes.", contentLength, contentBinary.Length));
            }

            try {
                var text = Encoding.UTF8.GetString(contentBinary);
                return(text);
            } catch (ArgumentException ex) {
                throw new InvalidDataException("Content is not valid UTF-8.", ex);
            }
        }
コード例 #3
0
ファイル: Connection.cs プロジェクト: pmshenoy/PTVS
        /// <summary>
        /// Returns a task which will process incoming messages.  This can be started on another thread or
        /// in whatever form of synchronization context you like.  StartProcessing is a convenience helper
        /// for starting this running asynchronously using Task.Run.
        /// </summary>
        /// <returns></returns>
        public async Task ProcessMessages()
        {
            try {
                var reader = new ProtocolReader(_reader);
                while (true)
                {
                    var packet = await ReadPacketAsJObject(reader);

                    if (packet == null)
                    {
                        break;
                    }

                    var type = packet["type"].ToObject <string>();
                    switch (type)
                    {
                    case PacketType.Request: {
                        var seq = packet["seq"].ToObject <int?>();
                        if (seq == null)
                        {
                            throw new InvalidDataException("Request is missing seq attribute");
                        }
                        await ProcessRequest(packet, seq);
                    }
                    break;

                    case PacketType.Response:
                        ProcessResponse(packet);
                        break;

                    case PacketType.Event:
                        ProcessEvent(packet);
                        break;

                    case PacketType.Error:
                        ProcessError(packet);
                        break;

                    default:
                        throw new InvalidDataException("Bad packet type: " + type ?? "<null>");
                    }
                }
            } catch (InvalidDataException ex) {
                // UNDONE: Skipping assert to see if that fixes broken tests
                //Debug.Assert(false, "Terminating ProcessMessages loop due to InvalidDataException", ex.Message);
                // TODO: unsure that it makes sense to do this, but it maintains existing behavior
                await WriteError(ex.Message);
            } catch (OperationCanceledException) {
            } catch (ObjectDisposedException) {
            }

            _basicLog.WriteLine("ProcessMessages ended");
        }
コード例 #4
0
ファイル: Connection.cs プロジェクト: serg32m/PTVS
        /// <summary>
        /// Reads a single message from the protocol buffer.  First reads in any headers until a blank
        /// line is received.  Then reads in the body of the message.  The headers must include a Content-Length
        /// header specifying the length of the body.
        /// </summary>
        private static async Task <string> ReadPacket(ProtocolReader reader)
        {
            var    headers = new Dictionary <string, string>(StringComparer.OrdinalIgnoreCase);
            var    lines   = new List <string>();
            string line;

            while ((line = await reader.ReadHeaderLineAsync().ConfigureAwait(false)) != null)
            {
                lines.Add(line ?? "(null)");
                if (String.IsNullOrEmpty(line))
                {
                    if (headers.Count == 0)
                    {
                        continue;
                    }
                    // end of headers for this request...
                    break;
                }
                var split = line.Split(_headerSeparator, 2);
                if (split.Length != 2)
                {
                    // Probably getting an error message, so read all available text
                    var error = line;
                    try {
                        // Encoding is uncertain since this is malformed
                        error += TextEncoding.GetString(await reader.ReadToEndAsync());
                    } catch (ArgumentException) {
                    }
                    throw new InvalidDataException("Malformed header, expected 'name: value'" + Environment.NewLine + error);
                }
                headers[split[0]] = split[1];
            }

            if (line == null)
            {
                return(null);
            }

            string contentLengthStr;
            int    contentLength;

            if (!headers.TryGetValue(Headers.ContentLength, out contentLengthStr))
            {
                // HACK: Attempting to find problem with message content
                Console.Error.WriteLine("Content-Length not specified on request. Lines follow:");
                foreach (var l in lines)
                {
                    Console.Error.WriteLine($"> {l}");
                }
                Console.Error.Flush();
                throw new InvalidDataException("Content-Length not specified on request");
            }

            if (!Int32.TryParse(contentLengthStr, out contentLength) || contentLength < 0)
            {
                throw new InvalidDataException("Invalid Content-Length: " + contentLengthStr);
            }

            var contentBinary = await reader.ReadContentAsync(contentLength);

            if (contentBinary.Length == 0 && contentLength > 0)
            {
                // The stream was closed, so let's abort safely
                return(null);
            }
            if (contentBinary.Length != contentLength)
            {
                throw new InvalidDataException(string.Format("Content length does not match Content-Length header. Expected {0} bytes but read {1} bytes.", contentLength, contentBinary.Length));
            }

            try {
                var text = TextEncoding.GetString(contentBinary);
                return(text);
            } catch (ArgumentException ex) {
                throw new InvalidDataException("Content is not valid UTF-8.", ex);
            }
        }