Beispiel #1
0
 public NameHandler(State s)
 {
     logger     = Log.ForContext <NameHandler>();
     variables  = s.Variables;
     functions  = s.Functions;
     namespaces = s.Namespaces;
 }
Beispiel #2
0
        public static UriBuilder GetRedirectUriBuilder(string method,
                                                       string scheme,
                                                       CloudStorageAccount account,
                                                       string containerName,
                                                       string blobName,
                                                       bool useSas,
                                                       string queryString,
                                                       bool decodeQueryParams = true)
        {
            CloudBlobContainer container = NamespaceHandler.GetContainerByName(account, containerName);
            // Strip any existing SAS query params as we'll replace them with our own SAS calculation
            var queryParams = RequestQueryParameters.Create(queryString, decodeQueryParams);

            SharedAccessSignature.RemoveSasQueryParameters(queryParams);
            if (useSas)
            {
                // Be careful to preserve the URL encoding in the signature
                queryParams.Append(CalculateSASStringForContainer(method, container), false);
            }
            return(new UriBuilder
            {
                Scheme = scheme,
                Host = account.BlobEndpoint.Host,
                Path = PathUtils.CombineContainerAndBlob(containerName, PathUtils.PathEncode(blobName)),
                Query = queryParams.ToString(),
            });
        }
Beispiel #3
0
 /// <summary>
 /// Generic function to redirect a put request for properties of a blob
 /// </summary>
 public static async Task <HandlerResult> BasicBlobAsync(IHttpRequestWrapper requestWrapper, string container, string blob, bool servePrimaryOnly, bool operationCanReplicateBlob)
 {
     return(await WebOperationRunner.DoHandlerAsync("BlobHandler.BasicBlobAsync", async() =>
     {
         var namespaceBlob = await NamespaceHandler.FetchNamespaceBlobAsync(container, blob);
         if (!await namespaceBlob.ExistsAsync())
         {
             return new HandlerResult
             {
                 StatusCode = HttpStatusCode.NotFound,
             };
         }
         string accountName = namespaceBlob.SelectDataAccount(servePrimaryOnly);
         if (operationCanReplicateBlob)
         {
             if (namespaceBlob.IsReplicated ||
                 BlobReplicationHandler.ShouldReplicateBlob(requestWrapper.Headers, container, blob))
             {
                 accountName = namespaceBlob.PrimaryAccountName;
                 await BlobReplicationHandler.EnqueueBlobReplicationAsync(namespaceBlob, false);
             }
         }
         Uri redirect = ControllerOperations.GetRedirectUri(HttpContextFactory.Current.Request,
                                                            DashConfiguration.GetDataAccountByAccountName(accountName),
                                                            namespaceBlob.Container,
                                                            namespaceBlob.BlobName,
                                                            false);
         return HandlerResult.Redirect(requestWrapper, redirect);
     }));
 }
Beispiel #4
0
        public async Task <HttpResponseMessage> DeleteBlob(string container, string blob, string snapshot = null)
        {
            var  requestWrapper  = DashHttpRequestWrapper.Create(this.Request);
            var  headers         = requestWrapper.Headers;
            var  queryParams     = requestWrapper.QueryParameters;
            bool dataBlobDeleted = false;

            return(await DoHandlerAsync(String.Format("BlobController.DeleteBlob: {0}/{1}", container, blob),
                                        async() => await NamespaceHandler.PerformNamespaceOperation(container, blob, async(namespaceBlob) =>
            {
                // We only need to delete the actual blob. We are leaving the namespace entry alone as a sort of cache.
                if (!(await namespaceBlob.ExistsAsync()) || namespaceBlob.IsMarkedForDeletion)
                {
                    return this.CreateResponse(HttpStatusCode.NotFound, headers);
                }
                // Delete the real data blob by forwarding the request onto the data account
                if (!dataBlobDeleted)
                {
                    var forwardedResponse = await ForwardRequestHandler(namespaceBlob, StorageOperationTypes.DeleteBlob);
                    if (!forwardedResponse.IsSuccessStatusCode)
                    {
                        return forwardedResponse;
                    }
                    dataBlobDeleted = true;
                }
                // See if we need to delete any replicas
                if (namespaceBlob.IsReplicated)
                {
                    await BlobReplicationHandler.EnqueueBlobReplicationAsync(namespaceBlob, true, false);
                }
                // Mark the namespace blob for deletion
                await namespaceBlob.MarkForDeletionAsync();
                return this.CreateResponse(HttpStatusCode.Accepted, headers);
            })));
        }
Beispiel #5
0
        public async Task <HttpResponseMessage> PutContainerComp(string container, string comp)
        {
            return(await DoHandlerAsync(String.Format("ContainerController.PutContainerComp: {0}", comp), async() =>
            {
                CloudBlobContainer containerObj = NamespaceHandler.GetContainerByName(DashConfiguration.NamespaceAccount, container);
                HttpResponseMessage errorResponse = await ValidatePreconditions(containerObj);
                if (errorResponse != null)
                {
                    return errorResponse;
                }
                switch (comp.ToLower())
                {
                case "lease":
                    return await SetContainerLease(containerObj);

                case "metadata":
                    return await SetContainerMetadata(containerObj);

                case "acl":
                    return await SetContainerAcl(containerObj);

                default:
                    return new HttpResponseMessage(HttpStatusCode.BadRequest);
                }
            }));
        }
Beispiel #6
0
        static async Task <BlobContainerPublicAccessType> GetContainerPublicAccessAsync(string container)
        {
            // TODO: Plug this potential DoS vector - spurious anonymous requests could drown us here...
            var containerObject = NamespaceHandler.GetContainerByName(DashConfiguration.NamespaceAccount, container);
            var permissions     = await containerObject.GetPermissionsAsync();

            return(permissions.PublicAccess);
        }
Beispiel #7
0
 private async Task <HttpResponseMessage> PutBlobHandler(string container, string blob, IHttpRequestWrapper requestWrapper, StorageOperationTypes operation)
 {
     return(await DoHandlerAsync(String.Format("BlobController.PutBlobHandler: {0} {1}/{2}", operation, container, blob),
                                 async() =>
     {
         var namespaceBlob = await NamespaceHandler.CreateNamespaceBlobAsync(container, blob);
         if (BlobReplicationOperations.DoesOperationTriggerReplication(operation) &&
             BlobReplicationHandler.ShouldReplicateBlob(requestWrapper.Headers, namespaceBlob))
         {
             await BlobReplicationHandler.EnqueueBlobReplicationAsync(namespaceBlob, false);
         }
         return await ForwardRequestHandler(namespaceBlob, operation);
     }));
 }
Beispiel #8
0
 static void CleanupAbortedBlobReplication(ICloudBlob destBlob)
 {
     if (destBlob == null)
     {
         return;
     }
     NamespaceHandler.PerformNamespaceOperation(destBlob.Container.Name, destBlob.Name, async(namespaceBlob) =>
     {
         if (CleanupAbortedBlobReplication(namespaceBlob, destBlob))
         {
             await namespaceBlob.SaveAsync();
             return(true);
         }
         return(false);
     }).Wait();
 }
Beispiel #9
0
        void AssertReplicationWorker(string container, string blobName, string primaryAccount, bool isDeleteReplica)
        {
            // Wait for the messages to be fully enqueued
            Task.Delay(1000).Wait();
            int processed = 0, errors = 0;

            MessageProcessor.ProcessMessageLoop(ref processed, ref errors, 0);
            Assert.AreEqual(0, errors);
            Assert.IsTrue(DashConfiguration.DataAccounts.Count - 1 <= processed);
            foreach (var account in DashConfiguration.DataAccounts
                     .Where(dataAccount => !String.Equals(dataAccount.Credentials.AccountName, primaryAccount, StringComparison.OrdinalIgnoreCase)))
            {
                var dataBlob = NamespaceHandler.GetBlobByName(account, container, blobName);
                Assert.AreEqual(!isDeleteReplica, dataBlob.Exists());
            }
        }
Beispiel #10
0
        public static async Task <HandlerResult> AbortCopyBlobAsync(IHttpRequestWrapper requestWrapper, string destContainer, string destBlob, string copyId)
        {
            return(await WebOperationRunner.DoHandlerAsync("BlobHandler.AbortCopyBlobAsync", async() =>
            {
                var destNamespaceBlob = await NamespaceHandler.FetchNamespaceBlobAsync(destContainer, destBlob);

                var destCloudBlob = NamespaceHandler.GetBlobByName(
                    DashConfiguration.GetDataAccountByAccountName(destNamespaceBlob.PrimaryAccountName),
                    destContainer,
                    destBlob);
                await destCloudBlob.AbortCopyAsync(copyId);
                return new HandlerResult
                {
                    StatusCode = HttpStatusCode.NoContent,
                };
            }));
        }
Beispiel #11
0
        private static async Task <IEnumerable <IListBlobItem> > ChildBlobListAsync(CloudStorageAccount dataAccount,
                                                                                    string container, string prefix, string delimiter, string includeFlags)
        {
            CloudBlobContainer containerObj = NamespaceHandler.GetContainerByName(dataAccount, container);

            if (!String.IsNullOrWhiteSpace(delimiter))
            {
                containerObj.ServiceClient.DefaultDelimiter = delimiter;
            }
            var results = new List <IEnumerable <IListBlobItem> >();
            BlobListingDetails listDetails;

            Enum.TryParse(includeFlags, true, out listDetails);
            string nextMarker = null;

            try
            {
                do
                {
                    var continuationToken = new BlobContinuationToken
                    {
                        NextMarker = nextMarker,
                    };
                    var blobResults = await containerObj.ListBlobsSegmentedAsync(prefix, String.IsNullOrWhiteSpace(delimiter), listDetails, null, continuationToken, null, null);

                    results.Add(blobResults.Results);
                    if (blobResults.ContinuationToken != null)
                    {
                        nextMarker = blobResults.ContinuationToken.NextMarker;
                    }
                    else
                    {
                        nextMarker = null;
                    }
                } while (!String.IsNullOrWhiteSpace(nextMarker));
            }
            catch (StorageException)
            {
                // Silently swallow the exception if we're missing the container for this account
            }

            return(results
                   .SelectMany(segmentResults => segmentResults));
        }
Beispiel #12
0
 static bool FinalizeBlobReplication(string dataAccount, string container, string blobName, bool deleteReplica, ICloudBlob destBlob = null)
 {
     return(NamespaceHandler.PerformNamespaceOperation(container, blobName, async(namespaceBlob) =>
     {
         bool exists = await namespaceBlob.ExistsAsync();
         if (!exists || namespaceBlob.IsMarkedForDeletion)
         {
             // It's ok for a deleted replica not to have a corresponding namespace blob
             if (!deleteReplica)
             {
                 DashTrace.TraceWarning("Replication of blob [{0}] to account [{1}] cannot be completed because the namespace blob either does not exist or is marked for deletion.",
                                        PathUtils.CombineContainerAndBlob(container, blobName),
                                        dataAccount);
                 // Attempt to not leave the replica orphaned
                 if (CleanupAbortedBlobReplication(namespaceBlob, destBlob))
                 {
                     await namespaceBlob.SaveAsync();
                 }
             }
             // Do not attempt retry in this state
             return true;
         }
         string message = "replicated to";
         bool nsDirty = false;
         if (deleteReplica)
         {
             nsDirty = namespaceBlob.RemoveDataAccount(dataAccount);
             message = "dereplicated from";
         }
         else
         {
             nsDirty = namespaceBlob.AddDataAccount(dataAccount);
         }
         if (nsDirty)
         {
             await namespaceBlob.SaveAsync();
             DashTrace.TraceInformation("Blob [{0}] has been successfully {1} account [{2}].",
                                        PathUtils.CombineContainerAndBlob(container, blobName),
                                        message,
                                        dataAccount);
         }
         return true;
     }).Result);
 }
Beispiel #13
0
 /// <summary>
 /// Generic function to forward blob request. Target blob must already exist.
 /// </summary>
 private async Task <HttpResponseMessage> BasicBlobHandler(string container, string blob, IHttpRequestWrapper requestWrapper, StorageOperationTypes operation)
 {
     return(await DoHandlerAsync(String.Format("BlobController.BasicBlobHandler: {0} {1}/{2}", operation, container, blob),
                                 async() =>
     {
         var namespaceBlob = await NamespaceHandler.FetchNamespaceBlobAsync(container, blob);
         if (!await namespaceBlob.ExistsAsync())
         {
             return this.CreateResponse(HttpStatusCode.NotFound, (RequestHeaders)null);
         }
         if (BlobReplicationOperations.DoesOperationTriggerReplication(operation) &&
             (namespaceBlob.IsReplicated ||
              BlobReplicationHandler.ShouldReplicateBlob(requestWrapper.Headers, namespaceBlob)))
         {
             await BlobReplicationHandler.EnqueueBlobReplicationAsync(namespaceBlob, false);
         }
         return await ForwardRequestHandler(namespaceBlob, operation);
     }));
 }
Beispiel #14
0
        static async Task <SharedAccessBlobPolicy> GetStoredPolicyForContainer(string container, string storedPolicyId)
        {
            try
            {
                // TODO: Move this information to cache to mitigate DoS vector
                var containerObject = NamespaceHandler.GetContainerByName(DashConfiguration.NamespaceAccount, container);
                var permissions     = await containerObject.GetPermissionsAsync();

                SharedAccessBlobPolicy retval;
                if (permissions.SharedAccessPolicies.TryGetValue(storedPolicyId, out retval))
                {
                    return(retval);
                }
            }
            catch (StorageException)
            {
            }
            return(null);
        }
Beispiel #15
0
        public State()
        {
            logger = Log.ForContext <State>();

            var origin    = new Context <Shell.Types.IShellData>("ORIGIN");
            var functions = new Context <Shell.Types.Function>("ORIGIN");

            contexts = new List <Tuple <Context <Shell.Types.IShellData>, Context <Shell.Types.Function> > >
            {
                new Tuple <Context <Types.IShellData>, Context <Types.Function> >(origin, functions)
            };

            all_namespaces = new Dictionary <string, Shell.Types.Namespace>();

            this.Variables  = new VariableHandler(this);
            this.Functions  = new FunctionHandler(this);
            this.Namespaces = new NamespaceHandler(this);
            this.Names      = new NameHandler(this);
        }
Beispiel #16
0
 public static async Task <HandlerResult> PutBlobAsync(IHttpRequestWrapper requestWrapper, string container, string blob, bool operationCanReplicateBlob)
 {
     return(await WebOperationRunner.DoHandlerAsync("BlobHandler.PutBlobAsync", async() =>
     {
         var namespaceBlob = await NamespaceHandler.CreateNamespaceBlobAsync(container, blob);
         if (operationCanReplicateBlob)
         {
             if (BlobReplicationHandler.ShouldReplicateBlob(requestWrapper.Headers, container, blob))
             {
                 await BlobReplicationHandler.EnqueueBlobReplicationAsync(namespaceBlob, false);
             }
         }
         Uri redirect = ControllerOperations.GetRedirectUri(HttpContextFactory.Current.Request,
                                                            DashConfiguration.GetDataAccountByAccountName(namespaceBlob.PrimaryAccountName),
                                                            container,
                                                            blob,
                                                            false);
         return HandlerResult.Redirect(requestWrapper, redirect);
     }));
 }
Beispiel #17
0
        public async Task <HttpResponseMessage> GetContainerProperties(string container)
        {
            return(await DoHandlerAsync("ContainerController.GetContainerProperties", async() =>
            {
                CloudBlobContainer containerObj = NamespaceHandler.GetContainerByName(DashConfiguration.NamespaceAccount, container);
                HttpResponseMessage errorResponse = await ValidatePreconditions(containerObj);
                if (errorResponse != null)
                {
                    return errorResponse;
                }
                HttpResponseMessage response = await FormContainerMetadataResponse(containerObj);

                response.Headers.Add("x-ms-lease-status", containerObj.Properties.LeaseStatus.ToString().ToLower());
                response.Headers.Add("x-ms-lease-state", containerObj.Properties.LeaseState.ToString().ToLower());
                //Only add Lease Duration information if the container is leased
                if (containerObj.Properties.LeaseState == LeaseState.Leased)
                {
                    response.Headers.Add("x-ms-lease-duration", containerObj.Properties.LeaseDuration.ToString().ToLower());
                }

                return response;
            }));
        }
Beispiel #18
0
 public AzureMessageQueue(string queueName)
 {
     this.Queue = NamespaceHandler.GetQueueByName(DashConfiguration.NamespaceAccount, queueName);
     this.Queue.CreateIfNotExists();
     this.CurrentMessage = null;
 }
Beispiel #19
0
        public static async Task ImportAccountAsync(string accountName)
        {
            await OperationRunner.DoActionAsync(String.Format("Importing data account: {0}", accountName), async() =>
            {
                // This method will only import the blobs into the namespace. A future task may be
                // to redistribute the blobs to balance the entire virtual account.
                var account = DashConfiguration.GetDataAccountByAccountName(accountName);
                if (account == null)
                {
                    DashTrace.TraceWarning("Failure importing storage account: {0}. The storage account has not been configured as part of this virtual account",
                                           accountName);
                    return;
                }
                // Check if we've already imported this account
                var accountClient     = account.CreateCloudBlobClient();
                var namespaceClient   = DashConfiguration.NamespaceAccount.CreateCloudBlobClient();
                var accountContainers = await ListContainersAsync(accountClient);
                var status            = await AccountStatus.GetAccountStatus(accountName);
                await status.UpdateStatusInformation(AccountStatus.States.Healthy, "Importing storage account: {0} into virtual account", accountName);
                bool alreadyImported = false;
                await GetAccountBlobs(accountClient, async(blobItem) =>
                {
                    var blob          = (ICloudBlob)blobItem;
                    var namespaceBlob = await NamespaceBlob.FetchForBlobAsync(
                        (CloudBlockBlob)NamespaceHandler.GetBlobByName(DashConfiguration.NamespaceAccount, blob.Container.Name, blob.Name, blob.IsSnapshot ? blob.SnapshotTime.ToString() : String.Empty));
                    alreadyImported = await namespaceBlob.ExistsAsync(true) &&
                                      namespaceBlob.DataAccounts.Contains(accountName, StringComparer.OrdinalIgnoreCase);
                    return(false);
                });
                if (alreadyImported)
                {
                    await status.UpdateStatusWarning("Importing storage account: {0} has already been imported. This account cannot be imported again.", accountName);
                    return;
                }
                // Sync the container structure first - add containers in the imported account to the virtual account
                await status.UpdateStatusInformation("Importing storage account: {0}. Synchronizing container structure", accountName);
                int containersAddedCount = 0, containersWarningCount = 0;
                var namespaceContainers  = await ListContainersAsync(namespaceClient);
                await ProcessContainerDifferencesAsync(accountContainers, namespaceContainers, async(newContainerName, accountContainer) =>
                {
                    var createContainerResult = await ContainerHandler.DoForAllContainersAsync(newContainerName,
                                                                                               HttpStatusCode.Created,
                                                                                               async newContainer => await CopyContainer(accountContainer, newContainer),
                                                                                               true,
                                                                                               new[] { account });
                    if (createContainerResult.StatusCode < HttpStatusCode.OK || createContainerResult.StatusCode >= HttpStatusCode.Ambiguous)
                    {
                        await status.UpdateStatusWarning("Importing storage account: {0}. Failed to create container: {1} in virtual account. Details: {2}, {3}",
                                                         accountName,
                                                         newContainerName,
                                                         createContainerResult.StatusCode.ToString(),
                                                         createContainerResult.ReasonPhrase);
                        containersWarningCount++;
                    }
                    else
                    {
                        containersAddedCount++;
                    }
                },
                                                       (newContainerName, ex) =>
                {
                    status.UpdateStatusWarning("Importing storage account: {0}. Error processing container {1}. Details: {2}",
                                               accountName,
                                               newContainerName,
                                               ex.ToString()).Wait();
                    containersWarningCount++;
                });
                // Sync the other way
                await ProcessContainerDifferencesAsync(namespaceContainers, accountContainers, async(newContainerName, namespaceContainer) =>
                {
                    await CopyContainer(namespaceContainer, accountClient.GetContainerReference(newContainerName));
                },
                                                       (newContainerName, ex) =>
                {
                    status.UpdateStatusWarning("Importing storage account: {0}. Error replicating container {1} to imported account. Details: {2}",
                                               accountName,
                                               newContainerName,
                                               ex.ToString()).Wait();
                    containersWarningCount++;
                });
                DashTrace.TraceInformation("Importing storage account: {0}. Synchronized containers structure. {1} containers added to virtual account. {2} failures/warnings.",
                                           accountName,
                                           containersAddedCount,
                                           containersWarningCount);

                // Start importing namespace entries
                await status.UpdateStatusInformation("Importing storage account: {0}. Adding blob entries to namespace", accountName);
                int blobsAddedCount = 0, warningCount = 0, duplicateCount = 0;
                await GetAccountBlobs(accountClient, async(blobItem) =>
                {
                    var blob = (ICloudBlob)blobItem;
                    try
                    {
                        var namespaceBlob = await NamespaceBlob.FetchForBlobAsync(
                            (CloudBlockBlob)NamespaceHandler.GetBlobByName(DashConfiguration.NamespaceAccount, blob.Container.Name, blob.Name, blob.IsSnapshot ? blob.SnapshotTime.ToString() : String.Empty));
                        if (await namespaceBlob.ExistsAsync())
                        {
                            if (!String.Equals(namespaceBlob.PrimaryAccountName, accountName, StringComparison.OrdinalIgnoreCase))
                            {
                                await status.UpdateStatusWarning("Importing storage account: {0}. Adding blob: {1}/{2} would result in a duplicate blob entry. This blob will NOT be imported into the virtual account. Manually add the contents of this blob to the virtual account.",
                                                                 accountName,
                                                                 blob.Container.Name,
                                                                 blob.Name);
                                duplicateCount++;
                            }
                        }
                        else
                        {
                            namespaceBlob.PrimaryAccountName  = accountName;
                            namespaceBlob.Container           = blob.Container.Name;
                            namespaceBlob.BlobName            = blob.Name;
                            namespaceBlob.IsMarkedForDeletion = false;
                            await namespaceBlob.SaveAsync();
                            blobsAddedCount++;
                        }
                    }
                    catch (StorageException ex)
                    {
                        status.UpdateStatusWarning("Importing storage account: {0}. Error importing blob: {0}/{1} into virtual namespace. Details: {3}",
                                                   accountName,
                                                   blob.Container.Name,
                                                   blob.Name,
                                                   ex.ToString()).Wait();
                        warningCount++;
                    }
                    return(true);
                });

                if (status.State < AccountStatus.States.Warning)
                {
                    await status.UpdateStatus(String.Empty, AccountStatus.States.Unknown, TraceLevel.Off);
                }
                DashTrace.TraceInformation("Successfully imported the contents of storage account: '{0}' into the virtual namespace. Blobs added: {1}, duplicates detected: {2}, errors encountered: {3}",
                                           accountName, blobsAddedCount, duplicateCount, warningCount);
            },
                                                ex =>
            {
                var status = AccountStatus.GetAccountStatus(accountName).Result;
                status.UpdateStatusWarning("Error importing storage account: {0} into virtual account. Details: {1}", accountName, ex.ToString()).Wait();
            }, false, true);
        }
Beispiel #20
0
 public static async Task <HandlerResult> CopyBlobAsync(IHttpRequestWrapper requestWrapper, string destContainer, string destBlob, string source)
 {
     return(await WebOperationRunner.DoHandlerAsync(String.Format("BlobHandler.CopyBlobAsync: {0}/{1} from {2}", destContainer, destBlob, source), async() =>
     {
         // source is a naked URI supplied by client
         Uri sourceUri;
         if (Uri.TryCreate(source, UriKind.RelativeOrAbsolute, out sourceUri))
         {
             string sourceContainer = String.Empty;
             string sourceBlobName = String.Empty;
             string sourceQuery = String.Empty;
             BlobType sourceBlobType = BlobType.BlockBlob;
             var requestVersion = requestWrapper.Headers.Value("x-ms-version", StorageServiceVersions.Version_2009_09_19);
             bool processRelativeSource = false;
             if (!sourceUri.IsAbsoluteUri)
             {
                 if (requestVersion >= StorageServiceVersions.Version_2012_02_12)
                 {
                     // 2012-02-12 onwards doesn't accept relative URIs
                     return new HandlerResult
                     {
                         StatusCode = HttpStatusCode.BadRequest,
                     };
                 }
                 // Make sourceUri absolute here because a bunch of Uri functionality fails for relative URIs
                 sourceUri = new Uri(new Uri("http://dummyhost"), sourceUri);
                 processRelativeSource = true;
             }
             if (processRelativeSource ||
                 (String.Equals(sourceUri.Host, requestWrapper.Url.Host, StringComparison.OrdinalIgnoreCase) &&
                  ((sourceUri.IsDefaultPort && requestWrapper.Url.IsDefaultPort) || (sourceUri.Port == requestWrapper.Url.Port))))
             {
                 var segments = PathUtils.GetPathSegments(sourceUri.AbsolutePath);
                 if (processRelativeSource)
                 {
                     // Blob in named container: /accountName/containerName/blobName
                     // Snapshot in named container: /accountName/containerName/blobName?snapshot=<DateTime>
                     // Blob in root container: /accountName/blobName
                     // Snapshot in root container: /accountName/blobName?snapshot=<DateTime>
                     if (!String.Equals(segments.FirstOrDefault(), DashConfiguration.AccountName))
                     {
                         return new HandlerResult
                         {
                             StatusCode = HttpStatusCode.BadRequest,
                             ErrorInformation = new DashErrorInformation
                             {
                                 ErrorCode = "CopyAcrossAccountsNotSupported",
                                 ErrorMessage = "The copy source account and destination account must be the same.",
                             },
                         };
                     }
                     if (segments.Count() == 2)
                     {
                         sourceContainer = "root";
                         sourceBlobName = segments[1];
                     }
                     else if (segments.Count() > 2)
                     {
                         sourceContainer = segments[1];
                         sourceBlobName = PathUtils.CombinePathSegments(segments.Skip(2));
                     }
                 }
                 else
                 {
                     sourceContainer = segments.FirstOrDefault();
                     sourceBlobName = PathUtils.CombinePathSegments(segments.Skip(1));
                 }
             }
             var destNamespaceBlob = await NamespaceHandler.FetchNamespaceBlobAsync(destContainer, destBlob);
             string destAccount = String.Empty;
             if (!String.IsNullOrEmpty(sourceContainer) && !String.IsNullOrEmpty(sourceBlobName))
             {
                 var sourceQueryParams = HttpUtility.ParseQueryString(sourceUri.Query);
                 var sourceNamespaceBlob = await NamespaceHandler.FetchNamespaceBlobAsync(sourceContainer, sourceBlobName, sourceQueryParams["snapshot"]);
                 if (!await sourceNamespaceBlob.ExistsAsync())
                 {
                     // This isn't actually documented (what happens when the source doesn't exist), but by obervation the service emits 404
                     return new HandlerResult
                     {
                         StatusCode = HttpStatusCode.NotFound,
                     };
                 }
                 var sourceCloudContainer = NamespaceHandler.GetContainerByName(
                     DashConfiguration.GetDataAccountByAccountName(sourceNamespaceBlob.PrimaryAccountName), sourceContainer);
                 sourceBlobType = sourceCloudContainer.GetBlobReferenceFromServer(sourceBlobName).BlobType;
                 // This is effectively an intra-account copy which is expected to be atomic. Therefore, even if the destination already
                 // exists, we need to place the destination in the same data account as the source.
                 // If the destination blob already exists, we delete it below to prevent an orphaned data blob
                 destAccount = sourceNamespaceBlob.PrimaryAccountName;
                 var sourceUriBuilder = ControllerOperations.GetRedirectUriBuilder("GET",
                                                                                   requestWrapper.Url.Scheme,
                                                                                   DashConfiguration.GetDataAccountByAccountName(destAccount),
                                                                                   sourceContainer,
                                                                                   sourceBlobName,
                                                                                   false,
                                                                                   String.Empty);
                 sourceUri = sourceUriBuilder.Uri;
             }
             else if (await destNamespaceBlob.ExistsAsync())
             {
                 destAccount = destNamespaceBlob.PrimaryAccountName;
             }
             else
             {
                 destAccount = NamespaceHandler.GetDataStorageAccountForBlob(destBlob).Credentials.AccountName;
             }
             bool replicateDestination = false;
             if (await destNamespaceBlob.ExistsAsync() && destNamespaceBlob.PrimaryAccountName != destAccount)
             {
                 // Delete the existing blob to prevent orphaning it
                 replicateDestination = destNamespaceBlob.IsReplicated;
                 var dataBlob = NamespaceHandler.GetBlobByName(
                     DashConfiguration.GetDataAccountByAccountName(destNamespaceBlob.PrimaryAccountName), destContainer, destBlob);
                 await dataBlob.DeleteIfExistsAsync();
             }
             destNamespaceBlob.PrimaryAccountName = destAccount;
             destNamespaceBlob.Container = destContainer;
             destNamespaceBlob.BlobName = destBlob;
             destNamespaceBlob.IsMarkedForDeletion = false;
             await destNamespaceBlob.SaveAsync();
             // Now that we've got the metadata tucked away - do the actual copy
             var destCloudContainer = NamespaceHandler.GetContainerByName(DashConfiguration.GetDataAccountByAccountName(destAccount), destContainer);
             ICloudBlob destCloudBlob = null;
             if (sourceBlobType == BlobType.PageBlob)
             {
                 destCloudBlob = destCloudContainer.GetPageBlobReference(destBlob);
             }
             else
             {
                 destCloudBlob = destCloudContainer.GetBlockBlobReference(destBlob);
             }
             // Storage client will retry failed copy. Let our clients decide that.
             var copyId = await destCloudBlob.StartCopyFromBlobAsync(sourceUri,
                                                                     AccessCondition.GenerateEmptyCondition(),
                                                                     AccessCondition.GenerateEmptyCondition(),
                                                                     new BlobRequestOptions
             {
                 RetryPolicy = new NoRetry(),
             },
                                                                     new OperationContext());
             // Check if we should replicate the copied destination blob
             if (replicateDestination || BlobReplicationHandler.ShouldReplicateBlob(requestWrapper.Headers, destContainer, destBlob))
             {
                 await BlobReplicationHandler.EnqueueBlobReplicationAsync(destNamespaceBlob, false);
             }
             return new HandlerResult
             {
                 StatusCode = requestVersion >= StorageServiceVersions.Version_2012_02_12 ? HttpStatusCode.Accepted : HttpStatusCode.Created,
                 Headers = new ResponseHeaders(new[]
                 {
                     new KeyValuePair <string, string>("x-ms-copy-id", copyId),
                     new KeyValuePair <string, string>("x-ms-copy-status", destCloudBlob.CopyState.Status == CopyStatus.Success ? "success" : "pending"),
                 })
             };
         }
         return new HandlerResult
         {
             StatusCode = HttpStatusCode.BadRequest,
         };
     }));
 }
 public abstract object Resolve(NestedArgument argument, SourceHandler source,
                                NamespaceHandler scope, ExtensionResolver resolver, Type targettype);