void UploadStreamRapid(string path, Stream input, FileInformation fileInformation)
        {
            fileInformation.AddProperties(input, FileProperties.AllBaiduCloudRapidHashes);

            HttpWebRequest request = ConstructRequest(Config.APIList.UploadFileRapid,
                new Dictionary<string, string>
                {
                    ["remote_path"] = path.TrimStart('/'),
                    ["content_length"] = fileInformation.Size.ToString(),
                    ["content_md5"] = fileInformation.MD5,
                    ["slice_md5"] = fileInformation.SliceMD5,
                    ["content_crc32"] = fileInformation.Adler32
                });

            request.GetRequestStream().Close();

            using (var response = request.GetResponse())
            {
                if (!response.GetDictionary().Contains(new KeyValuePair<string, object>("md5", fileInformation.MD5)))
                    throw new Exception("Response is unexpected!");
            }
        }
        void UploadNormal(string path, Stream input, FileInformation fileInformation)
        {
            fileInformation.AddProperties(input, FileProperties.Size | FileProperties.BlockSize);

            input.Seek(0, SeekOrigin.Begin);

            if (BlockInfo == null || BlockInfo.Count == 0)
            {
                BlockInfo = new List<int> { fileInformation.BlockSize.Value };
            }

            int blockIndex = 0;
            int blockLength = 0;
            byte[] buffer = new byte[BlockInfo.Max()];

            if (BlockInfo[0] >= fileInformation.Size)
            {
                blockLength = input.Read(buffer, 0, BlockInfo[0]);
                bool uploadDirectDone = false;
                while (!uploadDirectDone)
                {
                    try
                    {
                        UploadDirect(path, buffer, 0, blockLength);
                        uploadDirectDone = true;
                    }
                    catch (WebException ex)
                    {
                        Console.WriteLine($"Failed once when uploading file {path} with direct upload method.");
                        Console.WriteLine("Exception:");
                        Console.WriteLine(ex);
                        if (ex.Response != null)
                        {
                            Console.WriteLine("Response:");
                            using (var s = new StreamReader(ex.Response.GetResponseStream()))
                            {
                                Console.WriteLine(s.ReadToEnd());
                            }
                        }
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                    catch (ObjectDisposedException ex)
                    {
                        Console.WriteLine($"Failed once when uploading file {path} with direct upload method.");
                        Console.WriteLine("Unexpected ObjectDisposedException:");
                        Console.WriteLine(ex);
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                }
                return;
            }

            List<string> blockIds = new List<string>();

            for (long position = 0; position < fileInformation.Size; position += blockLength)
            {
                blockLength = input.Read(buffer, 0, BlockInfo[blockIndex]);

                bool done = false;
                while (!done)
                {
                    try
                    {
                        blockIds.Add(UploadBlock(buffer, 0, blockLength));
                        done = true;
                    }
                    catch (WebException ex)
                    {
                        Console.WriteLine($"Failed once for file {path}, on block {blockIds.Count}");
                        Console.WriteLine("Exception:");
                        Console.WriteLine(ex);
                        if (ex.Response != null)
                        {
                            Console.WriteLine("Response:");
                            using (var s = new StreamReader(ex.Response.GetResponseStream()))
                            {
                                Console.WriteLine(s.ReadToEnd());
                            }
                        }
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                    catch (ObjectDisposedException ex)
                    {
                        Console.WriteLine($"Failed once for file {path}, on block {blockIds.Count}");
                        Console.WriteLine("Exception:");
                        Console.WriteLine(ex);
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                    catch (UploadBlockException ex)
                    {
                        Console.WriteLine($"Failed once for file {path}, on block {blockIds.Count}");
                        Console.WriteLine("Exception:");
                        Console.WriteLine(ex);
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                }

                if (blockIndex < BlockInfo.Count - 1)
                {
                    // Stay at the last element.
                    blockIndex++;
                }
            }

            bool mergeDone = false;
            while (!mergeDone)
            {
                try
                {
                    MergeBlocks(path, blockIds);
                    mergeDone = true;
                }
                catch (Exception ex)
                {
                    logger.Warn(ex, "Failed when merging");
                    Thread.Sleep(TimeSpan.FromSeconds(10));
                }
            }
        }