예제 #1
0
        public static int Write <T>(T value, ref PreservedBuffer <byte> destination, uint offset = 0u,
                                    MemoryStream temporaryStream = null, CompressionMethod compression = CompressionMethod.DefaultOrNone)
        {
            var buffer = destination.Buffer;

            return(Write(value, ref buffer, offset, temporaryStream));
        }
예제 #2
0
        public HttpRequestHeaders Headers; // yes, naked field - internal type, so not too exposed; allows for "ref" without copy

        public HttpRequest(PreservedBuffer method, PreservedBuffer path, PreservedBuffer httpVersion, Dictionary <string, PreservedBuffer> headers)
        {
            Method      = method;
            Path        = path;
            HttpVersion = httpVersion;
            Headers     = new HttpRequestHeaders(headers);
        }
예제 #3
0
        public static unsafe int Read <T>(PreservedBuffer <byte> source, uint offset, ref T value)
        {
            var fixedMemory = default(FixedMemory <byte>);

            try
            {
                void *pointer;
                if (!source.Buffer.TryGetPointer(out pointer))
                {
                    fixedMemory = source.Fix();
                    ArraySegment <byte> tmpArraySegment;
                    if (fixedMemory.Buffer.TryGetArray(out tmpArraySegment))
                    {
                        pointer = (void *)Marshal.UnsafeAddrOfPinnedArrayElement(tmpArraySegment.Array, tmpArraySegment.Offset + (int)offset);
                    }
                }
                return(Read((IntPtr)pointer, ref value));
            }
            finally
            {
                if (!fixedMemory.Equals(default(FixedMemory <byte>)))
                {
                    fixedMemory.Dispose();
                }
            }
        }
예제 #4
0
        public unsafe static int Write <T>(T value, ref PreservedBuffer <byte> destination, uint offset = 0u,
                                           MemoryStream temporaryStream = null, CompressionMethod compression = CompressionMethod.DefaultOrNone)
        {
            var tmpArraySegment = default(ArraySegment <byte>);
            var fixedMemory     = default(FixedMemory <byte>);

            try
            {
                void *pointer;
                if (!destination.Buffer.TryGetPointer(out pointer))
                {
                    fixedMemory = destination.Fix();
                    if (fixedMemory.Buffer.TryGetArray(out tmpArraySegment))
                    {
                        pointer = (void *)Marshal.UnsafeAddrOfPinnedArrayElement(tmpArraySegment.Array, tmpArraySegment.Offset);
                    }
                }
                var db = new DirectBuffer(tmpArraySegment.Count, pointer);
                return(Write(value, ref db, offset, temporaryStream));
            }
            finally
            {
                if (!fixedMemory.Equals(default(FixedMemory <byte>)))
                {
                    fixedMemory.Dispose();
                }
            }
        }
예제 #5
0
        public static unsafe int Read <T>(PreservedBuffer <byte> source, uint offset, out T value)
        {
            var handle = source.Buffer.Retain(true);

            try
            {
                return(Read((IntPtr)handle.PinnedPointer, out value));
            }
            finally
            {
                handle.Dispose();
            }
        }
        private static object ReadSimpleStringAsync(this ReadableBuffer buffer)
        {
            // Find \n
            ReadCursor     delim;
            ReadableBuffer line;

            if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out line, out delim))
            {
                return(new RedisErrorString("Unable to read line"));
            }
            PreservedBuffer preservedBuffer = line.Preserve();

            // Move the buffer to the rest
            buffer = buffer.Slice(delim).Slice(2);

            return(preservedBuffer);
        }
예제 #7
0
        public static unsafe int Read <T>(PreservedBuffer <byte> source, uint offset, out T value)
        {
            var handle = default(BufferHandle);

            try
            {
                if (!source.Buffer.TryGetPointer(out void *pointer))
                {
                    handle = source.Buffer.Pin();
                    if (source.Buffer.TryGetArray(out ArraySegment <byte> tmpArraySegment))
                    {
                        pointer = (void *)Marshal.UnsafeAddrOfPinnedArrayElement(tmpArraySegment.Array, tmpArraySegment.Offset + (int)offset);
                    }
                }
                return(Read((IntPtr)pointer, out value));
            }
            finally
            {
                handle.Free();
            }
        }
예제 #8
0
        private async Task ProcessSends()
        {
            while (true)
            {
                var result = await _output.ReadAsync();

                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    break;
                }

                var enumerator = buffer.GetEnumerator();

                if (enumerator.MoveNext())
                {
                    var current = enumerator.Current;

                    while (enumerator.MoveNext())
                    {
                        var next = enumerator.Current;

                        await SendAsync(current, endOfMessage : false);

                        current = next;
                    }

                    await PreviousSendingComplete;

                    _sendingBuffer = buffer.Preserve();

                    await SendAsync(current, endOfMessage : true);
                }

                _output.Advance(buffer.End);
            }

            _output.CompleteReader();
        }
        internal static async Task <HttpRequest> ParseHttpRequest(IPipeReader input)
        {
            PreservedBuffer Method = default(PreservedBuffer), Path = default(PreservedBuffer), HttpVersion = default(PreservedBuffer);
            Dictionary <string, PreservedBuffer> Headers = new Dictionary <string, PreservedBuffer>();

            try
            {
                ParsingState _state       = ParsingState.StartLine;
                bool         needMoreData = true;
                while (needMoreData)
                {
                    var read = await input.ReadAsync();

                    var buffer = read.Buffer;

                    var consumed = buffer.Start;
                    needMoreData = true;

                    try
                    {
                        if (buffer.IsEmpty && read.IsCompleted)
                        {
                            throw new EndOfStreamException();
                        }

                        if (_state == ParsingState.StartLine)
                        {
                            // Find \n
                            ReadCursor     delim;
                            ReadableBuffer startLine;
                            if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out startLine, out delim))
                            {
                                continue;
                            }


                            // Move the buffer to the rest
                            buffer = buffer.Slice(delim).Slice(2);

                            ReadableBuffer method;
                            if (!startLine.TrySliceTo((byte)' ', out method, out delim))
                            {
                                throw new Exception();
                            }

                            Method = method.Preserve();

                            // Skip ' '
                            startLine = startLine.Slice(delim).Slice(1);

                            ReadableBuffer path;
                            if (!startLine.TrySliceTo((byte)' ', out path, out delim))
                            {
                                throw new Exception();
                            }

                            Path = path.Preserve();

                            // Skip ' '
                            startLine = startLine.Slice(delim).Slice(1);

                            var httpVersion = startLine;
                            if (httpVersion.IsEmpty)
                            {
                                throw new Exception();
                            }

                            HttpVersion = httpVersion.Preserve();

                            _state   = ParsingState.Headers;
                            consumed = buffer.Start;
                        }

                        // Parse headers
                        // key: value\r\n

                        while (!buffer.IsEmpty)
                        {
                            var ch = Peek(ref buffer);

                            if (ch == -1)
                            {
                                break;
                            }

                            if (ch == '\r')
                            {
                                // Check for final CRLF.
                                buffer = buffer.Slice(1);
                                ch     = Peek(ref buffer);
                                buffer = buffer.Slice(1);

                                if (ch == -1)
                                {
                                    break;
                                }
                                else if (ch == '\n')
                                {
                                    consumed     = buffer.Start;
                                    needMoreData = false;
                                    break;
                                }

                                // Headers don't end in CRLF line.
                                throw new Exception();
                            }

                            var headerName  = default(ReadableBuffer);
                            var headerValue = default(ReadableBuffer);

                            // End of the header
                            // \n
                            ReadCursor     delim;
                            ReadableBuffer headerPair;
                            if (!buffer.TrySliceTo((byte)'\n', out headerPair, out delim))
                            {
                                break;
                            }

                            buffer = buffer.Slice(delim).Slice(1);

                            // :
                            if (!headerPair.TrySliceTo((byte)':', out headerName, out delim))
                            {
                                throw new Exception();
                            }

                            headerName = headerName.TrimStart();
                            headerPair = headerPair.Slice(delim).Slice(1);

                            // \r
                            if (!headerPair.TrySliceTo((byte)'\r', out headerValue, out delim))
                            {
                                // Bad request
                                throw new Exception();
                            }

                            headerValue = headerValue.TrimStart();
                            Headers[ToHeaderKey(ref headerName)] = headerValue.Preserve();

                            // Move the consumed
                            consumed = buffer.Start;
                        }
                    }
                    finally
                    {
                        input.Advance(consumed);
                    }
                }
                var result = new HttpRequest(Method, Path, HttpVersion, Headers);
                Method  = Path = HttpVersion = default(PreservedBuffer);
                Headers = null;
                return(result);
            }
            finally
            {
                Method.Dispose();
                Path.Dispose();
                HttpVersion.Dispose();
                if (Headers != null)
                {
                    foreach (var pair in Headers)
                    {
                        pair.Value.Dispose();
                    }
                }
            }
        }
예제 #10
0
        public ParseResult ParseRequest(ReadableBuffer buffer, out ReadCursor consumed, out ReadCursor examined)
        {
            consumed = buffer.Start;
            examined = buffer.Start;

            if (_state == ParsingState.StartLine)
            {
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out ReadableBuffer startLine, out ReadCursor delim))
                {
                    return(ParseResult.Incomplete);
                }

                // Move the buffer to the rest
                buffer = buffer.Slice(delim).Slice(2);

                if (!startLine.TrySliceTo((byte)' ', out ReadableBuffer method, out delim))
                {
                    return(ParseResult.BadRequest);
                }

                _method = method.Preserve();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                if (!startLine.TrySliceTo((byte)' ', out ReadableBuffer path, out delim))
                {
                    return(ParseResult.BadRequest);
                }

                _path = path.Preserve();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                var httpVersion = startLine;
                if (httpVersion.IsEmpty)
                {
                    return(ParseResult.BadRequest);
                }

                _httpVersion = httpVersion.Preserve();

                _state   = ParsingState.Headers;
                consumed = buffer.Start;
                examined = buffer.Start;
            }

            // Parse headers
            // key: value\r\n

            while (!buffer.IsEmpty)
            {
                var headerValue = default(ReadableBuffer);
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out ReadableBuffer headerPair, out ReadCursor delim))
                {
                    return(ParseResult.Incomplete);
                }

                buffer = buffer.Slice(delim).Slice(2);

                consumed = buffer.Start;
                examined = buffer.Start;

                // End of headers
                if (headerPair.IsEmpty)
                {
                    return(ParseResult.Complete);
                }

                // :
                if (!headerPair.TrySliceTo((byte)':', out ReadableBuffer headerName, out delim))
                {
                    return(ParseResult.BadRequest);
                }

                headerName = headerName.TrimStart();
                headerPair = headerPair.Slice(delim).Slice(1);

                headerValue = headerPair.TrimStart();
                RequestHeaders.SetHeader(ref headerName, ref headerValue);
            }

            return(ParseResult.Incomplete);
        }
예제 #11
0
        public unsafe void Write(
            UvStreamHandle handle,
            ReadableBuffer buffer,
            Action <UvWriteReq, int, object> callback,
            object state)
        {
            try
            {
                // Preserve the buffer for the async call
                _buffer = buffer.Preserve();
                buffer  = _buffer.Buffer;

                int nBuffers = 0;
                if (buffer.IsSingleSpan)
                {
                    nBuffers = 1;
                }
                else
                {
                    foreach (var span in buffer)
                    {
                        nBuffers++;
                    }
                }

                // add GCHandle to keeps this SafeHandle alive while request processing
                _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal));

                var pBuffers = (Uv.uv_buf_t *)_bufs;
                if (nBuffers > BUFFER_COUNT)
                {
                    // create and pin buffer array when it's larger than the pre-allocated one
                    var bufArray = new Uv.uv_buf_t[nBuffers];
                    var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned);
                    _pins.Add(gcHandle);
                    pBuffers = (Uv.uv_buf_t *)gcHandle.AddrOfPinnedObject();
                }

                if (nBuffers == 1)
                {
                    var   memory = buffer.First;
                    void *pointer;
                    if (memory.TryGetPointer(out pointer))
                    {
                        pBuffers[0] = Libuv.buf_init((IntPtr)pointer, memory.Length);
                    }
                    else
                    {
                        throw new InvalidOperationException("Memory needs to be pinned");
                    }
                }
                else
                {
                    int   i = 0;
                    void *pointer;
                    foreach (var memory in buffer)
                    {
                        if (memory.TryGetPointer(out pointer))
                        {
                            pBuffers[i++] = Libuv.buf_init((IntPtr)pointer, memory.Length);
                        }
                        else
                        {
                            throw new InvalidOperationException("Memory needs to be pinned");
                        }
                    }
                }

                _callback = callback;
                _state    = state;
                _uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb);
            }
            catch
            {
                _callback = null;
                _state    = null;
                _buffer.Dispose();
                Unpin(this);
                throw;
            }
        }
예제 #12
0
        public ParseResult ParseRequest(ref ReadableBuffer buffer)
        {
            if (_state == ParsingState.StartLine)
            {
                // Find \n
                ReadCursor delim;
                ReadableBuffer startLine;
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out startLine, out delim))
                {
                    return ParseResult.Incomplete;
                }

                // Move the buffer to the rest
                buffer = buffer.Slice(delim).Slice(2);

                ReadableBuffer method;
                if (!startLine.TrySliceTo((byte)' ', out method, out delim))
                {
                    return ParseResult.BadRequest;
                }

                _method = method.Preserve();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                ReadableBuffer path;
                if (!startLine.TrySliceTo((byte)' ', out path, out delim))
                {
                    return ParseResult.BadRequest;
                }

                _path = path.Preserve();

                // Skip ' '
                startLine = startLine.Slice(delim).Slice(1);

                var httpVersion = startLine;
                if (httpVersion.IsEmpty)
                {
                    return ParseResult.BadRequest;
                }

                _httpVersion = httpVersion.Preserve();

                _state = ParsingState.Headers;
            }

            // Parse headers
            // key: value\r\n

            while (!buffer.IsEmpty)
            {
                var headerName = default(ReadableBuffer);
                var headerValue = default(ReadableBuffer);

                // End of the header
                // \n
                ReadCursor delim;
                ReadableBuffer headerPair;
                if (!buffer.TrySliceTo((byte)'\r', (byte)'\n', out headerPair, out delim))
                {
                    return ParseResult.Incomplete;
                }

                buffer = buffer.Slice(delim).Slice(2);

                // End of headers
                if (headerPair.IsEmpty)
                {
                    return ParseResult.Complete;
                }

                // :
                if (!headerPair.TrySliceTo((byte)':', out headerName, out delim))
                {
                    return ParseResult.BadRequest;
                }

                headerName = headerName.TrimStart();
                headerPair = headerPair.Slice(delim).Slice(1);

                headerValue = headerPair.TrimStart();
                RequestHeaders.SetHeader(ref headerName, ref headerValue);
            }

            return ParseResult.Incomplete;
        }
예제 #13
0
        private async Task ProcessSends()
        {
            while (true)
            {
                var result = await _output.ReadAsync();
                var buffer = result.Buffer;

                if (buffer.IsEmpty && result.IsCompleted)
                {
                    break;
                }

                var enumerator = buffer.GetEnumerator();

                if (enumerator.MoveNext())
                {
                    var current = enumerator.Current;

                    while (enumerator.MoveNext())
                    {
                        var next = enumerator.Current;

                        await SendAsync(current, endOfMessage: false);
                        current = next;
                    }

                    await PreviousSendingComplete;

                    _sendingBuffer = buffer.Preserve();

                    await SendAsync(current, endOfMessage: true);
                }

                _output.Advance(buffer.End);
            }

            _output.CompleteReader();
        }
예제 #14
0
        public unsafe void Write(
            UvStreamHandle handle,
            ReadableBuffer buffer,
            Action<UvWriteReq, int, object> callback,
            object state)
        {
            try
            {
                // Preserve the buffer for the async call
                _buffer = buffer.Preserve();
                buffer = _buffer.Buffer;

                int nBuffers = 0;
                if (buffer.IsSingleSpan)
                {
                    nBuffers = 1;
                }
                else
                {
                    foreach (var span in buffer)
                    {
                        nBuffers++;
                    }
                }

                // add GCHandle to keeps this SafeHandle alive while request processing
                _pins.Add(GCHandle.Alloc(this, GCHandleType.Normal));

                var pBuffers = (Uv.uv_buf_t*)_bufs;
                if (nBuffers > BUFFER_COUNT)
                {
                    // create and pin buffer array when it's larger than the pre-allocated one
                    var bufArray = new Uv.uv_buf_t[nBuffers];
                    var gcHandle = GCHandle.Alloc(bufArray, GCHandleType.Pinned);
                    _pins.Add(gcHandle);
                    pBuffers = (Uv.uv_buf_t*)gcHandle.AddrOfPinnedObject();
                }

                if (nBuffers == 1)
                {
                    var memory = buffer.First;
                    void* pointer;
                    if (memory.TryGetPointer(out pointer))
                    {
                        pBuffers[0] = Libuv.buf_init((IntPtr)pointer, memory.Length);
                    }
                    else
                    {
                        throw new InvalidOperationException("Memory needs to be pinned");
                    }
                }
                else
                {
                    int i = 0;
                    void* pointer;
                    foreach (var memory in buffer)
                    {
                        if (memory.TryGetPointer(out pointer))
                        {
                            pBuffers[i++] = Libuv.buf_init((IntPtr)pointer, memory.Length);
                        }
                        else
                        {
                            throw new InvalidOperationException("Memory needs to be pinned");
                        }
                    }
                }

                _callback = callback;
                _state = state;
                _uv.write(this, handle, pBuffers, nBuffers, _uv_write_cb);
            }
            catch
            {
                _callback = null;
                _state = null;
                _buffer.Dispose();
                Unpin(this);
                throw;
            }
        }