Ejemplo n.º 1
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        protected override ODataBatchOperationResponseMessage CreateOperationResponseMessageImplementation()
        {
            string responseLine = this.batchStream.ReadFirstNonEmptyLine();

            int statusCode = this.ParseResponseLine(responseLine);

            // Read all headers and create the response message
            ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders();

            if (this.currentContentId == null)
            {
                headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId);
            }

            // In responses we don't need to use our batch URL resolver, since there are no cross referencing URLs
            // so use the URL resolver from the batch message instead.
            // We don't have correlation of changeset boundary between request and response messages in
            // changesets, so use null value for groupId.
            ODataBatchOperationResponseMessage responseMessage = BuildOperationResponseMessage(
                () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this),
                statusCode,
                headers,
                this.currentContentId,
                /*groupId*/ null);

            //// NOTE: Content-IDs for cross referencing are only supported in request messages; in responses
            ////       we allow a Content-ID header but don't process it (i.e., don't add the content ID to the URL resolver).
            this.currentContentId = null;
            return(responseMessage);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation()
        {
            string requestLine = this.batchStream.ReadFirstNonEmptyLine();

            string httpMethod;
            Uri    requestUri;

            this.ParseRequestLine(requestLine, out httpMethod, out requestUri);

            // Read all headers and create the request message
            ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders();

            if (this.batchStream.ChangeSetBoundary != null)
            {
                if (this.currentContentId == null)
                {
                    headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId);

                    if (this.currentContentId == null)
                    {
                        throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader));
                    }
                }
            }
            else if (this.InputContext.MessageReaderSettings.Version <= ODataVersion.V4)
            {
                // For backward compatibility, don't enforce uniqueness of Content-ID
                // in MultipartMixed outside of a changeset
                this.PayloadUriConverter.Reset();
            }

            ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage(
                () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this),
                httpMethod,
                requestUri,
                headers,
                this.currentContentId,
                this.batchStream.ChangeSetBoundary,
                this.dependsOnIdsTracker.GetDependsOnIds(), /*dependsOnIdsValidationRequired*/ false);

            if (this.currentContentId != null)
            {
                this.dependsOnIdsTracker.AddDependsOnId(this.currentContentId);
            }

            this.currentContentId = null;

            return(requestMessage);
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Returns the cached <see cref="ODataBatchOperationRequestMessage"/> for reading the content of an operation
        /// in a batch request.
        /// </summary>
        /// <returns>The message that can be used to read the content of the batch request operation from.</returns>
        protected override ODataBatchOperationRequestMessage CreateOperationRequestMessageImplementation()
        {
            string requestLine = this.batchStream.ReadFirstNonEmptyLine();

            string httpMethod;
            Uri    requestUri;

            this.ParseRequestLine(requestLine, out httpMethod, out requestUri);

            // Read all headers and create the request message
            ODataBatchOperationHeaders headers = this.batchStream.ReadHeaders();

            if (this.batchStream.ChangeSetBoundary != null)
            {
                if (this.currentContentId == null)
                {
                    headers.TryGetValue(ODataConstants.ContentIdHeader, out this.currentContentId);

                    if (this.currentContentId == null)
                    {
                        throw new ODataException(Strings.ODataBatchOperationHeaderDictionary_KeyNotFound(ODataConstants.ContentIdHeader));
                    }
                }
            }

            ODataBatchOperationRequestMessage requestMessage = BuildOperationRequestMessage(
                () => ODataBatchUtils.CreateBatchOperationReadStream(this.batchStream, headers, this),
                httpMethod,
                requestUri,
                headers,
                this.currentContentId,
                this.batchStream.ChangeSetBoundary,
                this.dependsOnIdsTracker.GetDependsOnIds(), /*dependsOnIdsValidationRequired*/ false);

            if (this.currentContentId != null)
            {
                this.dependsOnIdsTracker.AddDependsOnId(this.currentContentId);
            }

            this.currentContentId = null;

            return(requestMessage);
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Reads a line (all bytes until a line resource set) from the underlying stream.
        /// </summary>
        /// <returns>Returns the string that was read from the underlying stream (not including a terminating line resource set), or null if the end of input was reached.</returns>
        private string ReadLine()
        {
            Debug.Assert(this.batchEncoding != null, "Batch encoding should have been established on first call to SkipToBoundary.");
            Debug.Assert(this.lineBuffer != null && this.lineBuffer.Length == LineBufferLength, "Line buffer should have been created.");

            // The number of bytes in the line buffer that make up the line.
            int lineBufferSize = 0;

            // Start with the pre-allocated line buffer array.
            byte[] bytesForString = this.lineBuffer;

            ODataBatchReaderStreamScanResult scanResult = ODataBatchReaderStreamScanResult.NoMatch;

            while (scanResult != ODataBatchReaderStreamScanResult.Match)
            {
                int byteCount, lineEndStartPosition, lineEndEndPosition;
                scanResult = this.BatchBuffer.ScanForLineEnd(out lineEndStartPosition, out lineEndEndPosition);

                switch (scanResult)
                {
                case ODataBatchReaderStreamScanResult.NoMatch:
                    // Copy all the bytes in the BatchBuffer into the result byte[] and then continue
                    byteCount = this.BatchBuffer.NumberOfBytesInBuffer;
                    if (byteCount > 0)
                    {
                        // TODO: [Design] Consider security limits for data being read
                        ODataBatchUtils.EnsureArraySize(ref bytesForString, lineBufferSize, byteCount);
                        Buffer.BlockCopy(this.BatchBuffer.Bytes, this.BatchBuffer.CurrentReadPosition, bytesForString, lineBufferSize, byteCount);
                        lineBufferSize += byteCount;
                    }

                    if (this.underlyingStreamExhausted)
                    {
                        if (lineBufferSize == 0)
                        {
                            // If there's nothing more to pull from the underlying stream, and we didn't read anything
                            // in this invocation of ReadLine(), return null to indicate end of input.
                            return(null);
                        }

                        // Nothing more to read; stop looping
                        scanResult = ODataBatchReaderStreamScanResult.Match;
                        this.BatchBuffer.SkipTo(this.BatchBuffer.CurrentReadPosition + byteCount);
                    }
                    else
                    {
                        this.underlyingStreamExhausted = this.BatchBuffer.RefillFrom(this.multipartMixedBatchInputContext.Stream, /*preserveFrom*/ ODataBatchReaderStreamBuffer.BufferLength);
                    }

                    break;

                case ODataBatchReaderStreamScanResult.PartialMatch:
                    // We found the start of a line end in the buffer but could not verify whether we saw all of it.
                    // This can happen if a line end is represented as \r\n and we found \r at the very last position in the buffer.
                    // In this case we copy the bytes into the result byte[] and continue at the start of the line end; this will guarantee
                    // that the next scan will find the full line end, not find any additional bytes and then skip the full line end.
                    // It is safe to copy the string right here because we will also accept \r as a line end; we are just not sure whether there
                    // will be a subsequent \n.
                    // This can also happen if the last byte in the stream is \r.
                    byteCount = lineEndStartPosition - this.BatchBuffer.CurrentReadPosition;
                    if (byteCount > 0)
                    {
                        ODataBatchUtils.EnsureArraySize(ref bytesForString, lineBufferSize, byteCount);
                        Buffer.BlockCopy(this.BatchBuffer.Bytes, this.BatchBuffer.CurrentReadPosition, bytesForString, lineBufferSize, byteCount);
                        lineBufferSize += byteCount;
                    }

                    if (this.underlyingStreamExhausted)
                    {
                        // Nothing more to read; stop looping
                        scanResult = ODataBatchReaderStreamScanResult.Match;
                        this.BatchBuffer.SkipTo(lineEndStartPosition + 1);
                    }
                    else
                    {
                        this.underlyingStreamExhausted = this.BatchBuffer.RefillFrom(this.multipartMixedBatchInputContext.Stream, /*preserveFrom*/ lineEndStartPosition);
                    }

                    break;

                case ODataBatchReaderStreamScanResult.Match:
                    // We found a line end in the buffer
                    Debug.Assert(lineEndStartPosition >= this.BatchBuffer.CurrentReadPosition, "Line end must be at or after current position.");
                    Debug.Assert(lineEndEndPosition < this.BatchBuffer.CurrentReadPosition + this.BatchBuffer.NumberOfBytesInBuffer, "Line end must finish withing buffer range.");

                    byteCount = lineEndStartPosition - this.BatchBuffer.CurrentReadPosition;
                    if (byteCount > 0)
                    {
                        ODataBatchUtils.EnsureArraySize(ref bytesForString, lineBufferSize, byteCount);
                        Buffer.BlockCopy(this.BatchBuffer.Bytes, this.BatchBuffer.CurrentReadPosition, bytesForString, lineBufferSize, byteCount);
                        lineBufferSize += byteCount;
                    }

                    this.BatchBuffer.SkipTo(lineEndEndPosition + 1);
                    break;

                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.ODataBatchReaderStream_ReadLine));
                }
            }

            Debug.Assert(bytesForString != null, "bytesForString != null");

            return(this.CurrentEncoding.GetString(bytesForString, 0, lineBufferSize));
        }