public async Task <HttpResponseMessage> OptionsCallAsync() { return(await DoHandlerAsync("AccountController.OptionsCallAsync", async() => { var request = HttpContextFactory.Current.Request; HttpResponseMessage response; if (request.Headers["Origin"] != null) { DashTrace.TraceInformation("Forwarding real CORS OPTIONS request"); Uri forwardUri = ControllerOperations.ForwardUriToNamespace(request); var forwardRequest = new HttpRequestMessage(HttpMethod.Options, forwardUri); foreach (string key in _corsOptionsHeaders) { forwardRequest.Headers.TryAddWithoutValidation(key, request.Headers[key]); } HttpClient client = new HttpClient(); response = await client.SendAsync(forwardRequest); DashTrace.TraceInformation("CORS OPTIONS response: {0}, {1}", response.StatusCode, response.ReasonPhrase); } else { response = this.Request.CreateResponse(HttpStatusCode.OK); } response.Headers.Add("x-ms-dash-client", "true"); return response; })); }
private async Task <HttpResponseMessage> ForwardRequestHandler(NamespaceBlob namespaceBlob, StorageOperationTypes operation) { // Clone the inbound request var sourceRequest = this.Request; // We always target the primary data account for forwarded messages. If the operation invalidates the replicas, then // separate logic will enqueue the new blob to be replicated. var clonedRequest = new HttpRequestMessage(sourceRequest.Method, ControllerOperations.GetRedirectUri(sourceRequest.RequestUri, sourceRequest.Method.Method, DashConfiguration.GetDataAccountByAccountName(namespaceBlob.PrimaryAccountName), namespaceBlob.Container, namespaceBlob.BlobName, false)); clonedRequest.Version = sourceRequest.Version; foreach (var property in sourceRequest.Properties) { clonedRequest.Properties.Add(property); } foreach (var header in sourceRequest.Headers) { if (!_noCopyHeaders.Contains(header.Key)) { clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value); } } // Depending on the operation, we have to do some fixup to unwind HttpRequestMessage a bit - we also have to fixup some responses switch (operation) { case StorageOperationTypes.GetBlob: case StorageOperationTypes.GetBlobMetadata: case StorageOperationTypes.GetBlobProperties: case StorageOperationTypes.GetBlockList: case StorageOperationTypes.GetPageRanges: case StorageOperationTypes.LeaseBlob: case StorageOperationTypes.SetBlobMetadata: case StorageOperationTypes.SetBlobProperties: case StorageOperationTypes.SnapshotBlob: // Push any headers that are assigned to Content onto the request itself as these operations do not have any body if (sourceRequest.Content != null) { foreach (var header in sourceRequest.Content.Headers) { clonedRequest.Headers.TryAddWithoutValidation(header.Key, header.Value); } } break; default: clonedRequest.Content = sourceRequest.Content; break; } var client = new HttpClient(); var response = await client.SendAsync(clonedRequest, HttpCompletionOption.ResponseHeadersRead); // Fixup response for HEAD requests switch (operation) { case StorageOperationTypes.GetBlobProperties: var content = response.Content; if (response.IsSuccessStatusCode && content != null) { string mediaType = null; string dummyContent = String.Empty; if (content.Headers.ContentType != null) { mediaType = content.Headers.ContentType.MediaType; } // For some reason, a HEAD request requires some content otherwise the Content-Length is set to 0 dummyContent = "A"; response.Content = new StringContent(dummyContent, null, mediaType); foreach (var header in content.Headers) { response.Content.Headers.TryAddWithoutValidation(header.Key, header.Value); } response.Content.Headers.ContentLength = content.Headers.ContentLength; content.Dispose(); } break; } return(response); }