internal static ResponseMessage ToCosmosResponseMessage(this DocumentServiceResponse response, RequestMessage requestMessage) { Debug.Assert(requestMessage != null, nameof(requestMessage)); ResponseMessage cosmosResponse = new ResponseMessage(response.StatusCode, requestMessage); if (response.ResponseBody != null) { cosmosResponse.Content = response.ResponseBody; } if (response.Headers != null) { foreach (string key in response.Headers) { cosmosResponse.Headers.Add(key, response.Headers[key]); } } return(cosmosResponse); }
public override async Task <ResponseMessage> SendAsync( RequestMessage request, CancellationToken cancellationToken) { this.ProcessMessagesAsyncThrew = false; this.SendAsyncCalls++; try { using (new ActivityScope(Guid.NewGuid())) { DocumentServiceResponse response = await base.ProcessMessageAsync(request, cancellationToken); return(response.ToCosmosResponseMessage(request)); } } catch (DocumentClientException) { this.ProcessMessagesAsyncThrew = true; throw; } }
public override async Task <ResponseMessage> SendAsync( RequestMessage request, CancellationToken cancellationToken) { using (new ActivityScope(Guid.NewGuid())) { try { DocumentServiceResponse response = await this.ProcessMessageAsync(request, cancellationToken); Debug.Assert(Trace.CorrelationManager.ActivityId != Guid.Empty, "Trace activity id is missing"); return(response.ToCosmosResponseMessage(request)); } //catch DocumentClientException and exceptions that inherit it. Other exception types happen before a backend request catch (DocumentClientException ex) { Debug.Assert(Trace.CorrelationManager.ActivityId != Guid.Empty, "Trace activity id is missing"); return(ex.ToCosmosResponseMessage(request)); } catch (CosmosException ce) { Debug.Assert(Trace.CorrelationManager.ActivityId != Guid.Empty, "Trace activity id is missing"); return(ce.ToCosmosResponseMessage(request)); } catch (AggregateException ex) { Debug.Assert(Trace.CorrelationManager.ActivityId != Guid.Empty, "Trace activity id is missing"); // TODO: because the SDK underneath this path uses ContinueWith or task.Result we need to catch AggregateExceptions here // in order to ensure that underlying DocumentClientExceptions get propagated up correctly. Once all ContinueWith and .Result // is removed this catch can be safely removed. ResponseMessage errorMessage = AggregateExceptionConverter(ex, request); if (errorMessage != null) { return(errorMessage); } throw; } } }
public async Task TestServerStoreModelWithRequestEventHandler() { EventHandler <SendingRequestEventArgs> sendingRequest; EventHandler <ReceivedResponseEventArgs> receivedResponse; sendingRequest = this.SendingRequestEventHandler; receivedResponse = this.ReceivedRequestEventHandler; ServerStoreModel storeModel = new ServerStoreModel(GetMockStoreClient(), sendingRequest, receivedResponse); using (new ActivityScope(Guid.NewGuid())) { using (DocumentServiceRequest request = DocumentServiceRequest.Create( OperationType.Read, ResourceType.Document, AuthorizationTokenType.PrimaryMasterKey)) { DocumentServiceResponse result = await storeModel.ProcessMessageAsync(request); Assert.IsTrue(request.Headers.Get(newHeaderKey) != null); } } }
private async Task <PartitionAddressInformation> GetAddressesForRangeIdAsync( DocumentServiceRequest request, string collectionRid, string partitionKeyRangeId, bool forceRefresh) { using (DocumentServiceResponse response = await this.GetServerAddressesViaGatewayAsync(request, collectionRid, new[] { partitionKeyRangeId }, forceRefresh)) { FeedResource <Address> addressFeed = response.GetResource <FeedResource <Address> >(); bool inNetworkRequest = this.IsInNetworkRequest(response); IEnumerable <Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> > addressInfos = addressFeed.Where(addressInfo => ProtocolFromString(addressInfo.Protocol) == this.protocol) .GroupBy(address => address.PartitionKeyRangeId, StringComparer.Ordinal) .Select(group => this.ToPartitionAddressAndRange(collectionRid, @group.ToList(), inNetworkRequest)); Tuple <PartitionKeyRangeIdentity, PartitionAddressInformation> result = addressInfos.SingleOrDefault( addressInfo => StringComparer.Ordinal.Equals(addressInfo.Item1.PartitionKeyRangeId, partitionKeyRangeId)); if (result == null) { string errorMessage = string.Format( CultureInfo.InvariantCulture, RMResources.PartitionKeyRangeNotFound, partitionKeyRangeId, collectionRid); throw new PartitionKeyRangeGoneException(errorMessage) { ResourceAddress = collectionRid }; } return(result.Item2); } }
internal async Task <ResponseMessage> ProcessMessageAsync( RequestMessage request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } DocumentServiceRequest serviceRequest = request.ToDocumentServiceRequest(); //TODO: extrace auth into a separate handler string authorization = await((ICosmosAuthorizationTokenProvider)this.client.DocumentClient).GetUserAuthorizationTokenAsync( serviceRequest.ResourceAddress, PathsHelper.GetResourcePath(request.ResourceType), request.Method.ToString(), serviceRequest.Headers, AuthorizationTokenType.PrimaryMasterKey, request.DiagnosticsContext); serviceRequest.Headers[HttpConstants.HttpHeaders.Authorization] = authorization; IStoreModel storeProxy = this.client.DocumentClient.GetStoreProxy(serviceRequest); using (ITrace processMessageAsyncTrace = request.Trace.StartChild( name: $"{storeProxy.GetType().FullName} Transport Request", TraceComponent.Transport, Tracing.TraceLevel.Info)) { using (request.DiagnosticsContext.CreateScope(storeProxy.GetType().FullName)) { DocumentServiceResponse response = request.OperationType == OperationType.Upsert ? await this.ProcessUpsertAsync(storeProxy, serviceRequest, cancellationToken) : await storeProxy.ProcessMessageAsync(serviceRequest, cancellationToken); return(response.ToCosmosResponseMessage(request, processMessageAsyncTrace)); } } }
private async Task <ContainerProperties> ReadCollectionAsync(string collectionLink, CancellationToken cancellationToken, IDocumentClientRetryPolicy retryPolicyInstance) { cancellationToken.ThrowIfCancellationRequested(); using (DocumentServiceRequest request = DocumentServiceRequest.Create( OperationType.Read, ResourceType.Collection, collectionLink, AuthorizationTokenType.PrimaryMasterKey, new DictionaryNameValueCollection())) { request.Headers[HttpConstants.HttpHeaders.XDate] = DateTime.UtcNow.ToString("r"); string payload; string authorizationToken = this.tokenProvider.GetUserAuthorizationToken( request.ResourceAddress, PathsHelper.GetResourcePath(request.ResourceType), HttpConstants.HttpMethods.Get, request.Headers, AuthorizationTokenType.PrimaryMasterKey, out payload); request.Headers[HttpConstants.HttpHeaders.Authorization] = authorizationToken; using (new ActivityScope(Guid.NewGuid())) { if (retryPolicyInstance != null) { retryPolicyInstance.OnBeforeSendRequest(request); } using (DocumentServiceResponse response = await this.storeModel.ProcessMessageAsync(request)) { return(CosmosResource.FromStream <ContainerProperties>(response)); } } } }
public async Task TestJsonParseHandling() { HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, "https://*****:*****@"{ ""id"": ""test"", ""message"": ""Conflict"", ""Code"": ""409""}", encoding: Encoding.Default, mediaType: "application/json"); try { DocumentServiceResponse dsr = await ClientExtensions.ParseResponseAsync(message); } catch (DocumentClientException dce) { Assert.IsNotNull(dce.Message); Assert.AreEqual(HttpStatusCode.Conflict, dce.StatusCode); Assert.AreEqual("Id already exists", dce.StatusDescription); } }
private DocumentFeedResponse <CosmosElement> GetFeedResponse( DocumentServiceRequest documentServiceRequest, DocumentServiceResponse documentServiceResponse) { // Execute the callback an each element of the page // For example just could get a response like this // { // "_rid": "qHVdAImeKAQ=", // "Documents": [{ // "id": "03230", // "_rid": "qHVdAImeKAQBAAAAAAAAAA==", // "_self": "dbs\/qHVdAA==\/colls\/qHVdAImeKAQ=\/docs\/qHVdAImeKAQBAAAAAAAAAA==\/", // "_etag": "\"410000b0-0000-0000-0000-597916b00000\"", // "_attachments": "attachments\/", // "_ts": 1501107886 // }], // "_count": 1 // } // And you should execute the callback on each document in "Documents". MemoryStream memoryStream = new MemoryStream(); documentServiceResponse.ResponseBody.CopyTo(memoryStream); long responseLengthBytes = memoryStream.Length; ReadOnlyMemory <byte> content; if (memoryStream.TryGetBuffer(out ArraySegment <byte> buffer)) { content = buffer; } else { content = memoryStream.ToArray(); } IJsonNavigator jsonNavigator = null; // Use the users custom navigator first. If it returns null back try the // internal navigator. if (this.feedOptions.CosmosSerializationFormatOptions != null) { jsonNavigator = this.feedOptions.CosmosSerializationFormatOptions.CreateCustomNavigatorCallback(content); if (jsonNavigator == null) { throw new InvalidOperationException("The CosmosSerializationOptions did not return a JSON navigator."); } } else { jsonNavigator = JsonNavigator.Create(content); } string resourceName = this.GetRootNodeName(documentServiceRequest.ResourceType); if (!jsonNavigator.TryGetObjectProperty( jsonNavigator.GetRootNode(), resourceName, out ObjectProperty objectProperty)) { throw new InvalidOperationException($"Response Body Contract was violated. QueryResponse did not have property: {resourceName}"); } IJsonNavigatorNode cosmosElements = objectProperty.ValueNode; if (!(CosmosElement.Dispatch( jsonNavigator, cosmosElements) is CosmosArray cosmosArray)) { throw new InvalidOperationException($"QueryResponse did not have an array of : {resourceName}"); } int itemCount = cosmosArray.Count; return(new DocumentFeedResponse <CosmosElement>( cosmosArray, itemCount, documentServiceResponse.Headers, documentServiceResponse.RequestStats, responseLengthBytes)); }
public virtual async Task <AccountProperties> GetDatabaseAccountAsync(HttpRequestMessage requestMessage, CancellationToken cancellationToken = default(CancellationToken)) { AccountProperties databaseAccount = null; // Get the ServiceDocumentResource from the gateway. using (HttpResponseMessage responseMessage = await this.gatewayStoreClient.SendHttpAsync(requestMessage, cancellationToken)) { using (DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(responseMessage)) { databaseAccount = CosmosResource.FromStream <AccountProperties>(documentServiceResponse); } long longValue; IEnumerable <string> headerValues; if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.MaxMediaStorageUsageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.MaxMediaStorageUsageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.CurrentMediaStorageUsageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.MediaStorageUsageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.DatabaseAccountConsumedDocumentStorageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.ConsumedDocumentStorageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.DatabaseAccountProvisionedDocumentStorageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.ProvisionedDocumentStorageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.DatabaseAccountReservedDocumentStorageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.ReservedDocumentStorageInMB = longValue; } } } return(databaseAccount); }
private async Task <FeedResource <Address> > GetServerAddressesViaGatewayAsync( DocumentServiceRequest request, string collectionRid, IEnumerable <string> partitionKeyRangeIds, bool forceRefresh) { string entryUrl = PathsHelper.GeneratePath(ResourceType.Document, collectionRid, true); INameValueCollection addressQuery = new DictionaryNameValueCollection(); addressQuery.Add(HttpConstants.QueryStrings.Url, HttpUtility.UrlEncode(entryUrl)); INameValueCollection headers = new DictionaryNameValueCollection(); if (forceRefresh) { headers.Set(HttpConstants.HttpHeaders.ForceRefresh, bool.TrueString); } if (request.ForceCollectionRoutingMapRefresh) { headers.Set(HttpConstants.HttpHeaders.ForceCollectionRoutingMapRefresh, bool.TrueString); } addressQuery.Add(HttpConstants.QueryStrings.Filter, this.protocolFilter); addressQuery.Add(HttpConstants.QueryStrings.PartitionKeyRangeIds, string.Join(",", partitionKeyRangeIds)); string resourceTypeToSign = PathsHelper.GetResourcePath(ResourceType.Document); headers.Set(HttpConstants.HttpHeaders.XDate, DateTime.UtcNow.ToString("r", CultureInfo.InvariantCulture)); string token = null; try { token = this.tokenProvider.GetUserAuthorizationToken( collectionRid, resourceTypeToSign, HttpConstants.HttpMethods.Get, headers, AuthorizationTokenType.PrimaryMasterKey); } catch (UnauthorizedException) { } if (token == null && request.IsNameBased) { // User doesn't have rid based resource token. Maybe he has name based. string collectionAltLink = PathsHelper.GetCollectionPath(request.ResourceAddress); token = this.tokenProvider.GetUserAuthorizationToken( collectionAltLink, resourceTypeToSign, HttpConstants.HttpMethods.Get, headers, AuthorizationTokenType.PrimaryMasterKey); } headers.Set(HttpConstants.HttpHeaders.Authorization, token); Uri targetEndpoint = UrlUtility.SetQuery(this.addressEndpoint, UrlUtility.CreateQuery(addressQuery)); string identifier = GatewayAddressCache.LogAddressResolutionStart(request, targetEndpoint); using (HttpResponseMessage httpResponseMessage = await this.httpClient.GetAsync(targetEndpoint, headers)) { using (DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(httpResponseMessage)) { GatewayAddressCache.LogAddressResolutionEnd(request, identifier); return(documentServiceResponse.GetResource <FeedResource <Address> >()); } } }
internal DocumentResponse(DocumentServiceResponse response, JsonSerializerSettings settings = null) : base(response) { this.settings = settings; }
internal ResourceResponse(DocumentServiceResponse response, ITypeResolver <TResource> typeResolver = null) : base(response) { this.typeResolver = typeResolver; }
private async Task<DocumentServiceResponse> ProcessUpsertAsync(IStoreModel storeProxy, DocumentServiceRequest serviceRequest, CancellationToken cancellationToken) { DocumentServiceResponse response = await storeProxy.ProcessMessageAsync(serviceRequest, cancellationToken); this.client.DocumentClient.CaptureSessionToken(serviceRequest, response); return response; }
internal ResourceResponseBase(DocumentServiceResponse response) { this.response = response; this.usageHeaders = new Dictionary <string, long>(); this.quotaHeaders = new Dictionary <string, long>(); }
public virtual async Task <CosmosAccountSettings> GetDatabaseAccountAsync(HttpRequestMessage requestMessage) { CosmosAccountSettings databaseAccount = null; // Get the ServiceDocumentResource from the gateway. using (HttpResponseMessage responseMessage = await this.httpClient.SendHttpAsync(requestMessage)) { using (DocumentServiceResponse documentServiceResponse = await ClientExtensions.ParseResponseAsync(responseMessage)) { databaseAccount = documentServiceResponse.GetInternalResource <CosmosAccountSettings>(CosmosAccountSettings.CreateNewInstance); } long longValue; IEnumerable <string> headerValues; if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.MaxMediaStorageUsageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.MaxMediaStorageUsageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.CurrentMediaStorageUsageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.MediaStorageUsageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.DatabaseAccountConsumedDocumentStorageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.ConsumedDocumentStorageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.DatabaseAccountProvisionedDocumentStorageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.ProvisionedDocumentStorageInMB = longValue; } } if (responseMessage.Headers.TryGetValues(HttpConstants.HttpHeaders.DatabaseAccountReservedDocumentStorageInMB, out headerValues) && (headerValues.Count() != 0)) { if (long.TryParse(headerValues.First(), out longValue)) { databaseAccount.ReservedDocumentStorageInMB = longValue; } } } return(databaseAccount); }
private async Task <CollectionRoutingMap> GetRoutingMapForCollectionAsync( string collectionRid, CollectionRoutingMap previousRoutingMap, ITrace trace, IClientSideRequestStatistics clientSideRequestStatistics, CancellationToken cancellationToken) { List <PartitionKeyRange> ranges = new List <PartitionKeyRange>(); string changeFeedNextIfNoneMatch = previousRoutingMap == null ? null : previousRoutingMap.ChangeFeedNextIfNoneMatch; HttpStatusCode lastStatusCode = HttpStatusCode.OK; do { INameValueCollection headers = new StoreRequestNameValueCollection(); headers.Set(HttpConstants.HttpHeaders.PageSize, PageSizeString); headers.Set(HttpConstants.HttpHeaders.A_IM, HttpConstants.A_IMHeaderValues.IncrementalFeed); if (changeFeedNextIfNoneMatch != null) { headers.Set(HttpConstants.HttpHeaders.IfNoneMatch, changeFeedNextIfNoneMatch); } RetryOptions retryOptions = new RetryOptions(); using (DocumentServiceResponse response = await BackoffRetryUtility <DocumentServiceResponse> .ExecuteAsync( () => this.ExecutePartitionKeyRangeReadChangeFeedAsync(collectionRid, headers, trace, clientSideRequestStatistics), new ResourceThrottleRetryPolicy(retryOptions.MaxRetryAttemptsOnThrottledRequests, retryOptions.MaxRetryWaitTimeInSeconds), cancellationToken)) { lastStatusCode = response.StatusCode; changeFeedNextIfNoneMatch = response.Headers[HttpConstants.HttpHeaders.ETag]; FeedResource <PartitionKeyRange> feedResource = response.GetResource <FeedResource <PartitionKeyRange> >(); if (feedResource != null) { ranges.AddRange(feedResource); } } }while (lastStatusCode != HttpStatusCode.NotModified); IEnumerable <Tuple <PartitionKeyRange, ServiceIdentity> > tuples = ranges.Select(range => Tuple.Create(range, (ServiceIdentity)null)); CollectionRoutingMap routingMap; if (previousRoutingMap == null) { // Splits could have happened during change feed query and we might have a mix of gone and new ranges. HashSet <string> goneRanges = new HashSet <string>(ranges.SelectMany(range => range.Parents ?? Enumerable.Empty <string>())); routingMap = CollectionRoutingMap.TryCreateCompleteRoutingMap( tuples.Where(tuple => !goneRanges.Contains(tuple.Item1.Id)), string.Empty, changeFeedNextIfNoneMatch); } else { routingMap = previousRoutingMap.TryCombine(tuples, changeFeedNextIfNoneMatch); } if (routingMap == null) { // Range information either doesn't exist or is not complete. throw new NotFoundException($"{DateTime.UtcNow.ToString("o", CultureInfo.InvariantCulture)}: GetRoutingMapForCollectionAsync(collectionRid: {collectionRid}), Range information either doesn't exist or is not complete."); } return(routingMap); }
internal async Task <ResponseMessage> ProcessMessageAsync( RequestMessage request, CancellationToken cancellationToken) { if (request == null) { throw new ArgumentNullException(nameof(request)); } DocumentServiceRequest serviceRequest = request.ToDocumentServiceRequest(); ClientSideRequestStatisticsTraceDatum clientSideRequestStatisticsTraceDatum = new ClientSideRequestStatisticsTraceDatum(DateTime.UtcNow, request.Trace.Summary); serviceRequest.RequestContext.ClientRequestStatistics = clientSideRequestStatisticsTraceDatum; //TODO: extrace auth into a separate handler string authorization = await((ICosmosAuthorizationTokenProvider)this.client.DocumentClient).GetUserAuthorizationTokenAsync( serviceRequest.ResourceAddress, PathsHelper.GetResourcePath(request.ResourceType), request.Method.ToString(), serviceRequest.Headers, AuthorizationTokenType.PrimaryMasterKey, request.Trace); serviceRequest.Headers[HttpConstants.HttpHeaders.Authorization] = authorization; IStoreModel storeProxy = this.client.DocumentClient.GetStoreProxy(serviceRequest); using (ITrace processMessageAsyncTrace = request.Trace.StartChild( name: $"{storeProxy.GetType().FullName} Transport Request", component: TraceComponent.Transport, level: Tracing.TraceLevel.Info)) { request.Trace = processMessageAsyncTrace; processMessageAsyncTrace.AddDatum("Client Side Request Stats", clientSideRequestStatisticsTraceDatum); DocumentServiceResponse response = null; try { response = await storeProxy.ProcessMessageAsync(serviceRequest, cancellationToken); } catch (DocumentClientException dce) { // Enrich diagnostics context in-case of auth failures if (dce.StatusCode == System.Net.HttpStatusCode.Unauthorized || dce.StatusCode == System.Net.HttpStatusCode.Forbidden) { TimeSpan authProvideLifeSpan = this.client.DocumentClient.cosmosAuthorization.GetAge(); processMessageAsyncTrace.AddDatum("AuthProvider LifeSpan InSec", authProvideLifeSpan.TotalSeconds); } throw; } finally { processMessageAsyncTrace.UpdateRegionContacted(clientSideRequestStatisticsTraceDatum); } ResponseMessage responseMessage = response.ToCosmosResponseMessage( request, serviceRequest.RequestContext.RequestChargeTracker); // Enrich diagnostics context in-case of auth failures if (responseMessage?.StatusCode == System.Net.HttpStatusCode.Unauthorized || responseMessage?.StatusCode == System.Net.HttpStatusCode.Forbidden) { TimeSpan authProvideLifeSpan = this.client.DocumentClient.cosmosAuthorization.GetAge(); processMessageAsyncTrace.AddDatum("AuthProvider LifeSpan InSec", authProvideLifeSpan.TotalSeconds); } return(responseMessage); } }