/// <summary> /// Posts the data of a given data block to the server. /// </summary> private HttpResponseMessage SendDataBlock(HttpClient client, StreamedDataBlock dataBlock) { string actionUri = VfsUris.Default.WriteStreamedDataBlockUri; actionUri = actionUri.ConstructUri(Uris.PatternTransferId, dataBlock.TransferTokenId); actionUri = actionUri.ConstructUri(Uris.PatternBlockNumber, dataBlock.BlockNumber.ToString(CultureInfo.InvariantCulture)); RequestHeaders requestHeader = new RequestHeaders(); //write the HTTP headers VfsHttpHeaders headers = VfsHttpHeaders.Default; requestHeader.Add(headers.TransferId, dataBlock.TransferTokenId); //duplicate transfer ID, might be useful in some scenarios requestHeader.Add(headers.BlockNumber, dataBlock.BlockNumber.ToString()); requestHeader.Add(headers.IsLastBlock, Convert.ToString(dataBlock.IsLastBlock).ToLowerInvariant()); requestHeader.Add(headers.BlockOffset, dataBlock.Offset.ToString()); if (dataBlock.BlockLength.HasValue) { requestHeader.Add(headers.BlockLength, dataBlock.BlockLength.ToString()); } using (dataBlock.Data) { return(client.Send(HttpMethod.POST, actionUri, requestHeader, HttpContent.Create(() => dataBlock.Data))); } }
/// <summary> /// Handles the actual writing of the submitted data to the file system. /// </summary> /// <param name="transfer">The processed transfer.</param> /// <param name="dataBlock">A data block that provides a data stream that /// is written to the file system.</param> protected override void WriteStreamedDataBlockImpl(TTransfer transfer, StreamedDataBlock dataBlock) { TempStream stream = GetCachedTempData(transfer, dataBlock.Offset); //when it comes to reading from the source stream, make sure no limits (block or whole file size) //are exceeded if (!transfer.Token.MaxResourceSize.HasValue) { if (!transfer.Token.MaxBlockSize.HasValue) { //just write the stream - there is no limit dataBlock.WriteTo(stream); } else { //the limit is the maximum block size dataBlock.WriteTo(stream, transfer.Token.MaxBlockSize.Value); } } else { //first we need to make sure we won't go over the max resource size long maxSize = transfer.Token.MaxResourceSize.Value - dataBlock.Offset; if (transfer.Token.MaxBlockSize.HasValue) { //the other limit is the block size - take whatever is smaller maxSize = Math.Min(maxSize, transfer.Token.MaxBlockSize.Value); } //the limit is the maximum block size dataBlock.WriteTo(stream, maxSize); } }
/// <summary> /// Uploads a given data block that contains a chunk of data for an uploaded file. /// </summary> /// <param name="block">The block to be written.</param> /// <exception cref="DataBlockException">If the data block's contents cannot be stored, /// either because it's an invalid number, or because only sequential downloads /// are possible, and the block does not refer to the current download /// position. /// </exception> /// <exception cref="TransferStatusException">If the transfer has already expired.</exception> public void WriteBlock(BufferedDataBlock block) { Ensure.ArgumentNotNull(block, "block"); //switch to streaming MemoryStream stream = new MemoryStream(block.Data); if (block.BlockLength != block.Data.Length) { string msg = "Block number {0} of transfer [{1}] has a buffer of size [{2}] that doesn't match the indicated block size of [{3}]."; msg = String.Format(msg, block.BlockNumber, block.TransferTokenId, block.Data.Length, block.BlockLength); throw new DataBlockException(msg); } var streamingBlock = new StreamedDataBlock { TransferTokenId = block.TransferTokenId, BlockNumber = block.BlockNumber, BlockLength = block.BlockLength, Offset = block.Offset, IsLastBlock = block.IsLastBlock, Data = stream }; WriteBlockStreamed(streamingBlock); }
/// <summary> /// Uploads a given data block that provides a chunk of data for an uploaded file as a stream. /// </summary> /// <param name="block">The block to be written.</param> /// <exception cref="DataBlockException">If the data block's contents cannot be stored, /// either because it's an invalid number, or because only sequential downloads /// are possible, and the block does not refer to the current download /// position. /// </exception> /// <exception cref="TransferStatusException">If the transfer has already expired.</exception> public virtual void WriteBlockStreamed(StreamedDataBlock block) { SecureAction(FileSystemTask.DataBlockUploadRequest, () => OrchestrateBlockWriting(block, WriteStreamedDataBlockImpl), () => String.Format("Could not write strea,ed data block [{0}] for transfer [{1}]", block.BlockNumber, block.TransferTokenId)); }
/// <summary> /// Uploads a given data block that provides a chunk of data for an uploaded file as a stream. /// </summary> /// <param name="block">The block to be written.</param> /// <exception cref="DataBlockException">If the data block's contents cannot be stored, /// either because it's an invalid number, or because only sequential downloads /// are possible, and the block does not refer to the current download /// position. /// </exception> /// <exception cref="TransferStatusException">If the transfer has already expired.</exception> public void WriteBlockStreamed(StreamedDataBlock block) { Ensure.ArgumentNotNull(block, "block"); SecureRequest(FileSystemTask.DataBlockUploadRequest, c => SendDataBlock(c, block), () => String.Format("Could not upload block [{0}] for transfer [{1}].", block.BlockNumber, block.TransferTokenId)); }
/// <summary> /// Parses the received buffer and wraps it into a memory stream. /// </summary> /// <param name="bufferedBlock">A buffered block.</param> private void ParseBuffer(BufferedDataBlock bufferedBlock) { StreamedDataBlock streamedBlock = new StreamedDataBlock { TransferTokenId = bufferedBlock.TransferTokenId, BlockLength = bufferedBlock.BlockLength, BlockNumber = bufferedBlock.BlockNumber, IsLastBlock = bufferedBlock.IsLastBlock, Offset = bufferedBlock.Offset, Data = new MemoryStream(bufferedBlock.Data) }; OutputAction(streamedBlock); }
/// <summary> /// Parses the received buffer and wraps it into a memory stream. /// </summary> /// <param name="bufferedBlock">A buffered block.</param> private void ParseBuffer(BufferedDataBlock bufferedBlock) { StreamedDataBlock streamedBlock = new StreamedDataBlock { TransferTokenId = bufferedBlock.TransferTokenId, BlockLength = bufferedBlock.BlockLength, BlockNumber = bufferedBlock.BlockNumber, IsLastBlock = bufferedBlock.IsLastBlock, Offset = bufferedBlock.Offset, Data = new MemoryStream(bufferedBlock.Data) }; OutputAction(streamedBlock); }
/// <summary> /// Gets a given <see cref="BufferedDataBlock"/> from the currently downloaded /// resource. /// </summary> /// <param name="transferId">Identifies the transfer and resource.</param> /// <param name="blockNumber">The number of the requested block.</param> /// <returns>A data block which contains the data as an in-memory buffer /// (<see cref="BufferedDataBlock.Data"/>).</returns> /// <exception cref="DataBlockException">If the data block cannot be delivered, /// either because it's an invalid number, or because only sequential downloads /// are possible, and the block does not refer to the current download /// position. Check the <see cref="TransmissionCapabilities"/> flag in order /// to get the service's capabilities. /// </exception> /// <exception cref="VirtualResourceNotFoundException">If the resource does /// not exist.</exception> /// <remarks>It's up to the service to resolve a block number to the /// corect piece of data. Simplest case for services that operate on one /// resource or stream is to just make all served /// blocks the same size (apart from the last one, of course), which /// allows to easily calculate the offset of the requested block.</remarks> public BufferedDataBlock ReadBlock(string transferId, long blockNumber) { //read stream StreamedDataBlock block = ReadBlockStreamed(transferId, blockNumber); byte[] buffer = block.Data.ReadIntoBuffer(); return(new BufferedDataBlock { TransferTokenId = transferId, BlockNumber = blockNumber, BlockLength = block.BlockLength, Offset = block.Offset, IsLastBlock = block.IsLastBlock, Data = buffer }); }
public void WriteTo(object entity, IHttpEntity response, string[] codecParameters) { //get the data block to be transferred StreamedDataBlock dataBlock = (StreamedDataBlock)entity; if (HttpContext.Current != null) { //disable buffering HttpContext.Current.Response.BufferOutput = false; if (dataBlock.BlockLength.HasValue) { //only set the content lengths, if we actually know it response.SetHeader("Content-Length", dataBlock.BlockLength.Value.ToString(CultureInfo.InvariantCulture)); } response.SetHeader("Content-Type", MediaType.ApplicationOctetStream.Name); } else { response.ContentLength = dataBlock.BlockLength; response.ContentType = MediaType.ApplicationOctetStream; } //write the HTTP headers VfsHttpHeaders headers = VfsHttpHeaders.Default; response.SetHeader(headers.TransferId, dataBlock.TransferTokenId); response.SetHeader(headers.BlockLength, dataBlock.BlockLength.ToString()); response.SetHeader(headers.BlockNumber, dataBlock.BlockNumber.ToString()); response.SetHeader(headers.IsLastBlock, dataBlock.IsLastBlock.ToString()); response.SetHeader(headers.BlockOffset, dataBlock.Offset.ToString()); using (dataBlock.Data) { //write data to response stream, then close the stream dataBlock.Data.CopyTo(response.Stream); } }
protected override void InitInternal() { base.InitInternal(); InitToken(); byte[] buffer = new byte[10000]; Array.Copy(SourceFileContents, buffer, 10000); BufferedBlock = new BufferedDataBlock { TransferTokenId = Token.TransferId, BlockLength = 10000, Data = buffer }; StreamedBlock = new StreamedDataBlock { TransferTokenId = Token.TransferId, BlockLength = 10000, Data = new ChunkStream(new MemoryStream(SourceFileContents), 10000, 0, false) }; }
private void WriteBlock(string transferId, long blockNumber, Stream input) { //get meta information from headers VfsHttpHeaders headerNames = VfsHttpHeaders.Default; HttpHeaderDictionary headers = Request.Headers; var blockLength = Convert.ToInt32(headers[headerNames.BlockLength]); var isLastBlock = headers.ContainsKey(headerNames.IsLastBlock) ? Convert.ToBoolean(headers[headerNames.IsLastBlock]) : false; var offset = Convert.ToInt64(headers[headerNames.BlockOffset]); StreamedDataBlock block = new StreamedDataBlock { TransferTokenId = transferId, BlockNumber = blockNumber, IsLastBlock = isLastBlock, BlockLength = blockLength, Offset = offset, Data = new NonSeekableStream(input) }; FileSystem.UploadTransfers.WriteBlockStreamed(block); }
protected override void InitInternal() { base.InitInternal(); InitToken(); //read first 10000 bytes byte[] buffer = GetBuffer(10000); BufferedBlock = new BufferedDataBlock { TransferTokenId = Token.TransferId, BlockLength = 10000, Data = buffer }; StreamedBlock = new StreamedDataBlock { TransferTokenId = Token.TransferId, BlockLength = 10000, Data = new ChunkStream(new MemoryStream(buffer), 10000, 0, false) }; }
/// <summary> /// Handles the actual writing of the submitted data to the file system. /// </summary> /// <param name="transfer">The processed transfer.</param> /// <param name="dataBlock">A data block that provides a data stream that /// is written to the file system.</param> protected abstract void WriteStreamedDataBlockImpl(TTransfer transfer, StreamedDataBlock dataBlock);
/// <summary> /// Uploads a given data block that provides a chunk of data for an uploaded file as a stream. /// </summary> /// <param name="block">The block to be written.</param> /// <exception cref="DataBlockException">If the data block's contents cannot be stored, /// either because it's an invalid number, or because only sequential downloads /// are possible, and the block does not refer to the current download /// position. /// </exception> /// <exception cref="TransferStatusException">If the transfer has already expired.</exception> void IFSDataUploadService.WriteDataBlockStreamed(StreamedDataBlock block) { throw new NotImplementedException(); }
/// <summary> /// /// </summary> public void WriteBlockStreamed(StreamedDataBlock block) { throw new NotImplementedException(); }