コード例 #1
0
ファイル: FakeInput.cs プロジェクト: friesencr/dragonfly
 public FakeInput()
 {
     Baton = new Baton
                 {
                     Buffer = new ArraySegment<byte>(new byte[1024], 0, 0),
                 };
     WaitHandle = new ManualResetEvent(false);
     Encoding = Encoding.UTF8;
 }
コード例 #2
0
ファイル: Frame.cs プロジェクト: friesencr/dragonfly
        public bool Consume(Baton baton, Action callback, Action<Exception> fault)
        {
            for (; ; )
            {
                switch (_mode)
                {
                    case Mode.StartLine:
                        if (baton.RemoteIntakeFin)
                        {
                            _mode = Mode.Terminated;
                            return false;
                        }

                        if (!TakeStartLine(baton))
                        {
                            return false;
                        }

                        _mode = Mode.MessageHeader;
                        break;

                    case Mode.MessageHeader:
                        if (baton.RemoteIntakeFin)
                        {
                            _mode = Mode.Terminated;
                            return false;
                        }

                        var endOfHeaders = false;
                        while (!endOfHeaders)
                        {
                            if (!TakeMessageHeader(baton, out endOfHeaders))
                                return false;
                        }

                        var resumeBody = HandleExpectContinue(callback);
                        _messageBody = MessageBody.For(
                            _httpVersion,
                            _headers,
                            () =>
                            {
                                if (!Consume(baton, resumeBody, fault))
                                    resumeBody.Invoke();
                            });
                        _keepAlive = _messageBody.RequestKeepAlive;
                        _mode = Mode.MessageBody;
                        Execute();
                        return true;

                    case Mode.MessageBody:
                        return _messageBody.Consume(baton, callback, fault);

                    case Mode.Terminated:
                        return false;
                }
            }
        }
コード例 #3
0
ファイル: BatonTests.cs プロジェクト: friesencr/dragonfly
        public void SkipAdvancesBuffer()
        {
            // Arrange
            var baton = new Baton {Buffer = "xxhello world".ToArraySegment()};
            baton.Skip(2);

            // Act
            baton.Skip(5);

            // Assert
            Assert.Equal(6, baton.Buffer.Count);
            Assert.Equal(" world", baton.Buffer.ToString(Encoding.Default));
        }
コード例 #4
0
ファイル: BatonTests.cs プロジェクト: friesencr/dragonfly
        public void AvailableBufferBringsOffsetBackToZeroIfOccupiedSegmentIsZeroLength()
        {
            // Arrange
            var baton = new Baton { Buffer = "xxhello worldxx".ToArraySegment() };
            baton.Buffer = new ArraySegment<byte>(baton.Buffer.Array, 2, 0);

            // Act
            var buffer = baton.Available(0);

            // Assert
            Assert.Equal(15, buffer.Count);
            Assert.Equal("xxhello worldxx", buffer.ToString(Encoding.Default));
        }
コード例 #5
0
ファイル: BatonTests.cs プロジェクト: friesencr/dragonfly
        public void AvailableBufferReturnsAreaThatIsUnused()
        {
            // Arrange
            var baton = new Baton { Buffer = "xxhello worldxx".ToArraySegment() };
            baton.Buffer = new ArraySegment<byte>(baton.Buffer.Array, 2, 5);

            // Act
            var buffer = baton.Available(0);

            // Assert
            Assert.Equal(8, buffer.Count);
            Assert.Equal(" worldxx", buffer.ToString(Encoding.Default));
        }
コード例 #6
0
ファイル: Connection.cs プロジェクト: friesencr/dragonfly
        public void Execute()
        {
            _trace.Event(TraceEventType.Start, TraceMessage.Connection);

            _baton = new Baton
                         {
                             Buffer = new ArraySegment<byte>(new byte[1024], 0, 0)
                         };

            _fault = ex =>
                         {
                             Debug.WriteLine(ex.Message);
                         };

            _socketReceiveAsyncEventArgs = new SocketAsyncEventArgs();
            _socketReceiveAsyncEventArgs.SetBuffer(new byte[0], 0, 0);
            _socketReceiveAsyncEventArgs.Completed +=
                (_, __) =>
                {
                    try
                    {
                        Go(false);
                    }
                    catch (Exception ex)
                    {
                        _fault(ex);
                    }
                };

            _frameConsumeCallback =
                () =>
                {
                    try
                    {
                        Go(false);
                    }
                    catch (Exception ex)
                    {
                        _fault(ex);
                    }
                };
            try
            {
                _socket.Blocking = false;
                Go(true);
            }
            catch (Exception ex)
            {
                _fault(ex);
            }
        }
コード例 #7
0
ファイル: BatonTests.cs プロジェクト: friesencr/dragonfly
        public void TakeAdvancesBufferAndReturnsTakenSegment()
        {
            // Arrange
            var baton = new Baton { Buffer = "xxhello world".ToArraySegment() };
            baton.Skip(2);

            // Act
            var taken = baton.Take(5);

            // Assert
            Assert.Equal(6, baton.Buffer.Count);
            Assert.Equal(" world", baton.Buffer.ToString(Encoding.Default));
            Assert.Equal(5, taken.Count);
            Assert.Equal("hello", taken.ToString(Encoding.Default));
        }
コード例 #8
0
ファイル: BatonTests.cs プロジェクト: friesencr/dragonfly
        public void ExtendCausesArraySegmentToIncludeMoreBytesAtTheEnd()
        {
            // Arrange
            var baton = new Baton { Buffer = "xxhello worldxx".ToArraySegment() };
            baton.Buffer = new ArraySegment<byte>(baton.Buffer.Array, 2, 5);

            // Act
            var before = baton.Buffer.ToString(Encoding.Default);
            baton.Extend(5);
            var after = baton.Buffer.ToString(Encoding.Default);

            // Assert
            Assert.Equal("hello", before);
            Assert.Equal("hello worl", after);
            Assert.Equal(2, baton.Buffer.Offset);
            Assert.Equal(10, baton.Buffer.Count);
        }
コード例 #9
0
ファイル: Strat4.cs プロジェクト: friesencr/dragonfly
 public override bool TakeMessageHeader(Baton baton, out bool endOfHeaders)
 {
     endOfHeaders = false;
     var text = Encoding.Default.GetString(baton.Buffer.Array, baton.Buffer.Offset, baton.Buffer.Count);
     var lines = text.Split(new[] { "\r\n" }, StringSplitOptions.None);
     foreach (var line in lines)
     {
         if (line == "")
         {
             endOfHeaders = true;
             break;
         }
         var colonIndex = line.IndexOf(':');
         AddRequestHeader(line.Substring(0, colonIndex), line.Substring(colonIndex + 1));
     }
     return false;
 }
コード例 #10
0
ファイル: Program.cs プロジェクト: friesencr/dragonfly
        static void Main(string[] args)
        {
            var datas = File.ReadAllText("Headers.txt")
                .Split(new[] { "\r\n\r\n" }, StringSplitOptions.RemoveEmptyEntries)
                .Select(chunk => Encoding.Default.GetBytes(chunk + "\r\n\r\nAll of the data"))
                .ToArray();

            for (; ; )
            {
                var samples = Enumerable.Range(0, 10);

                var measures = Strats()
                    .Select(s => new
                    {
                        Strat = s,
                        Stopwatch = samples
                            .Select(x => new Stopwatch())
                            .ToArray()
                    }).ToArray();

                Console.WriteLine("Starting");
                foreach (var sample in samples)
                {
                    foreach (var data in datas)
                    {
                        foreach (var measure in measures)
                        {
                            Action after = () => { };
                            measure.Stopwatch[sample].Start();
                            foreach (var loop in Enumerable.Range(0, 10000))
                            {
                                var strat = measure.Strat();

                                var baton = new Baton
                                                {
                                                    Buffer = new ArraySegment<byte>(data),
                                                    RemoteIntakeFin = false,
                                                };
                                var endOfHeaders = false;
                                while (!endOfHeaders)
                                {
                                    if (!strat.TakeMessageHeader(baton, out endOfHeaders))
                                    {
                                        break;
                                    }
                                }

                                if (loop == 0 && sample == 0)
                                {
                                    after = () =>
                                                {
                                                    Console.WriteLine("{0}", strat.GetType().Name);
                                                    foreach (var kv in strat.Headers)
                                                    {
                                                        Console.WriteLine("  {0}: {1}", kv.Key, kv.Value);
                                                    }
                                                };
                                }
                            }
                            measure.Stopwatch[sample].Stop();
                            after();
                        }
                    }
                }

                foreach (var measure in measures)
                {

                    Console.WriteLine(
                        "{0} {1}\r\n  {2}",
                        measure.Strat().GetType().Name,
                        measure.Stopwatch
                            .Aggregate(TimeSpan.Zero, (a, b) => a.Add(b.Elapsed)),
                        measure.Stopwatch
                            .Select(x => x.ElapsedTicks)
                            .OrderBy(x => x)
                            .Aggregate("", (a, b) => a + " " + b));
                }
                Console.WriteLine("Done");
                Console.ReadLine();
            }
        }
コード例 #11
0
ファイル: MessageBody.cs プロジェクト: friesencr/dragonfly
 public abstract bool Consume(Baton baton, Action callback, Action<Exception> fault);
コード例 #12
0
ファイル: MessageBody.cs プロジェクト: friesencr/dragonfly
            public override bool Consume(Baton baton, Action callback, Action<Exception> fault)
            {
                if (baton.RemoteIntakeFin)
                {
                    LocalIntakeFin = true;
                    _subscriber.Complete();
                    return false;
                }

                var consumed = baton.Take(baton.Buffer.Count);

                return _subscriber.Next(consumed, callback);
            }
コード例 #13
0
ファイル: MessageBody.cs プロジェクト: friesencr/dragonfly
            public override bool Consume(Baton baton, Action callback, Action<Exception> fault)
            {
                var consumeLength = Math.Min(_neededLength, baton.Buffer.Count);
                _neededLength -= consumeLength;

                var consumed = baton.Take(consumeLength);

                if (_neededLength != 0)
                {
                    // TODO: if check baton.Complete==true && neededlength != 0 then remote socket closed early
                    return _subscriber.Next(consumed, callback);
                }

                LocalIntakeFin = true;

                if (consumed.Count != 0)
                {
                    var delayed = _subscriber.Next(
                        consumed,
                        () =>
                        {
                            _subscriber.Complete();
                            callback();
                        });
                    if (delayed)
                    {
                        return true;
                    }
                    _subscriber.Complete();
                    return false;
                }

                _subscriber.Complete();
                return false;
            }
コード例 #14
0
ファイル: MessageBody.cs プロジェクト: friesencr/dragonfly
            private static bool TakeChunkedLine(Baton baton, ref int chunkSizeOut)
            {
                var remaining = baton.Buffer;
                if (remaining.Count < 2) return false;
                var ch0 = remaining.Array[remaining.Offset];
                var chunkSize = 0;
                var mode = 0;
                for (var index = 0; index != remaining.Count - 1; ++index)
                {
                    var ch1 = remaining.Array[remaining.Offset + index + 1];

                    if (mode == 0)
                    {
                        if (ch0 >= '0' && ch0 <= '9')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - '0');
                        }
                        else if (ch0 >= 'A' && ch0 <= 'F')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                        }
                        else if (ch0 >= 'a' && ch0 <= 'f')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                        }
                        else
                        {
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                        }
                        mode = 1;
                    }
                    else if (mode == 1)
                    {
                        if (ch0 >= '0' && ch0 <= '9')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - '0');
                        }
                        else if (ch0 >= 'A' && ch0 <= 'F')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('A' - 10));
                        }
                        else if (ch0 >= 'a' && ch0 <= 'f')
                        {
                            chunkSize = chunkSize * 0x10 + (ch0 - ('a' - 10));
                        }
                        else if (ch0 == ';')
                        {
                            mode = 2;
                        }
                        else if (ch0 == '\r' && ch1 == '\n')
                        {
                            baton.Skip(index + 2);
                            chunkSizeOut = chunkSize;
                            return true;
                        }
                        else
                        {
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                        }
                    }
                    else if (mode == 2)
                    {
                        if (ch0 == '\r' && ch1 == '\n')
                        {
                            baton.Skip(index + 2);
                            chunkSizeOut = chunkSize;
                            return true;
                        }
                        else
                        {
                            // chunk-extensions not currently parsed
                        }
                    }

                    ch0 = ch1;
                }
                return false;
            }
コード例 #15
0
ファイル: MessageBody.cs プロジェクト: friesencr/dragonfly
            public override bool Consume(Baton baton, Action callback, Action<Exception> fault)
            {
                for (; ; )
                {
                    switch (_mode)
                    {
                        case Mode.ChunkSizeLine:
                            var chunkSize = 0;
                            if (!TakeChunkedLine(baton, ref chunkSize))
                            {
                                return false;
                            }

                            _neededLength = chunkSize;
                            if (chunkSize == 0)
                            {
                                _mode = Mode.Complete;
                                LocalIntakeFin = true;
                                _subscriber.Complete();
                                return false;
                            }
                            _mode = Mode.ChunkData;
                            break;

                        case Mode.ChunkData:
                            if (_neededLength == 0)
                            {
                                _mode = Mode.ChunkDataCRLF;
                                break;
                            }
                            if (baton.Buffer.Count == 0)
                            {
                                return false;
                            }

                            var consumeLength = Math.Min(_neededLength, baton.Buffer.Count);
                            _neededLength -= consumeLength;
                            var consumed = baton.Take(consumeLength);

                            var paused = _subscriber.Next(
                                consumed,
                                () =>
                                {
                                    try
                                    {
                                        if (!Consume(baton, callback, fault))
                                            callback();
                                    }
                                    catch (Exception ex)
                                    {
                                        fault(ex);
                                    }
                                });
                            if (paused)
                            {
                                return true;
                            }
                            break;

                        case Mode.ChunkDataCRLF:
                            if (baton.Buffer.Count < 2)
                                return false;
                            var crlf = baton.Take(2);
                            if (crlf.Array[crlf.Offset] != '\r' ||
                                crlf.Array[crlf.Offset + 1] != '\n')
                            {
                                throw new NotImplementedException("INVALID REQUEST FORMAT");
                            }
                            _mode = Mode.ChunkSizeLine;
                            break;

                        default:
                            throw new NotImplementedException("INVALID REQUEST FORMAT");
                    }
                }
            }
コード例 #16
0
ファイル: Strat.cs プロジェクト: friesencr/dragonfly
 public abstract bool TakeMessageHeader(Baton baton, out bool endOfHeaders);
コード例 #17
0
ファイル: Frame.cs プロジェクト: friesencr/dragonfly
        private bool TakeStartLine(Baton baton)
        {
            var remaining = baton.Buffer;
            if (remaining.Count < 2) return false;
            var firstSpace = -1;
            var secondSpace = -1;
            var questionMark = -1;
            var ch0 = remaining.Array[remaining.Offset];
            for (var index = 0; index != remaining.Count - 1; ++index)
            {
                var ch1 = remaining.Array[remaining.Offset + index + 1];
                if (ch0 == '\r' && ch1 == '\n')
                {
                    if (secondSpace == -1)
                    {
                        throw new InvalidOperationException("INVALID REQUEST FORMAT");
                    }
                    _method = GetString(remaining, 0, firstSpace);
                    _requestUri = GetString(remaining, firstSpace + 1, secondSpace);
                    if (questionMark == -1)
                    {
                        _path = _requestUri;
                        _queryString = string.Empty;
                    }
                    else
                    {
                        _path = GetString(remaining, firstSpace + 1, questionMark);
                        _queryString = GetString(remaining, questionMark + 1, secondSpace);
                    }
                    _httpVersion = GetString(remaining, secondSpace + 1, index);
                    baton.Skip(index + 2);
                    return true;
                }

                if (ch0 == ' ' && firstSpace == -1)
                {
                    firstSpace = index;
                }
                else if (ch0 == ' ' && firstSpace != -1 && secondSpace == -1)
                {
                    secondSpace = index;
                }
                else if (ch0 == '?' && firstSpace != -1 && questionMark == -1 && secondSpace == -1)
                {
                    questionMark = index;
                }
                ch0 = ch1;
            }
            return false;
        }
コード例 #18
0
ファイル: Strat5.cs プロジェクト: friesencr/dragonfly
        public unsafe override bool TakeMessageHeader(Baton baton, out bool endOfHeaders)
        {
            var remaining = baton.Buffer;
            endOfHeaders = false;
            if (remaining.Count < 2) return false;
            var ch0 = remaining.Array[remaining.Offset];
            var ch1 = remaining.Array[remaining.Offset + 1];
            if (ch0 == '\r' && ch1 == '\n')
            {
                endOfHeaders = true;
                baton.Skip(2);
                return true;
            }

            if (remaining.Count < 3) return false;
            var wrappedHeaders = false;
            var colonIndex = -1;
            var valueStartIndex = -1;
            var valueEndIndex = -1;
            var indexEnd = remaining.Count - 2;
            fixed (byte* pch = remaining.Array)
            {
                var scan = pch + remaining.Offset + 2;
                for (var index = 0; index != indexEnd; ++index)
                {
                    var ch2 = *scan++;
                    if (ch0 == '\r' &&
                        ch1 == '\n' &&
                        ch2 != ' ' &&
                        ch2 != '\t')
                    {
                        var name = Encoding.Default.GetString(remaining.Array, remaining.Offset, colonIndex);
                        var value = "";
                        if (valueEndIndex != -1)
                            value = Encoding.Default.GetString(remaining.Array, remaining.Offset + valueStartIndex, valueEndIndex - valueStartIndex);
                        if (wrappedHeaders)
                            value = value.Replace("\r\n", " ");
                        AddRequestHeader(name, value);
                        baton.Skip(index + 2);
                        return true;
                    }
                    if (colonIndex == -1 && ch0 == ':')
                    {
                        colonIndex = index;
                    }
                    else if (colonIndex != -1 &&
                        ch0 != ' ' &&
                        ch0 != '\t' &&
                        ch0 != '\r' &&
                        ch0 != '\n')
                    {
                        if (valueStartIndex == -1)
                            valueStartIndex = index;
                        valueEndIndex = index + 1;
                    }
                    else if (!wrappedHeaders &&
                        ch0 == '\r' &&
                        ch1 == '\n' &&
                        (ch2 == ' ' ||
                        ch2 == '\t'))
                    {
                        wrappedHeaders = true;
                    }

                    ch0 = ch1;
                    ch1 = ch2;
                }
            }
            return false;
        }
コード例 #19
0
ファイル: Strat0.cs プロジェクト: friesencr/dragonfly
 public override bool TakeMessageHeader(Baton baton, out bool endOfHeaders)
 {
     endOfHeaders = false;
     return false;
 }