Gets HTTP request headers.

    :param cosmos_client.CosmosClient cosmos_client:
    :param dict default_headers:
    :param str verb:
    :param str path:
    :param str resource_id:
    :param str resource_type:
    :param dict options:
    :param str partition_key_range_id:

    :return:
        The HTTP request headers.
    :rtype: dict

def GetHeaders(cosmos_client,
               default_headers,
               verb,
               path,
               resource_id,
               resource_type,
               options,
               partition_key_range_id = None):
    """Gets HTTP request headers.

    :param cosmos_client.CosmosClient cosmos_client:
    :param dict default_headers:
    :param str verb:
    :param str path:
    :param str resource_id:
    :param str resource_type:
    :param dict options:
    :param str partition_key_range_id:

    :return:
        The HTTP request headers.
    :rtype: dict
    """
    headers = dict(default_headers)
    options = options or {}

    if cosmos_client._useMultipleWriteLocations:
        headers[http_constants.HttpHeaders.AllowTentativeWrites] = "true"

    pre_trigger_include = options.get('preTriggerInclude')
    if pre_trigger_include:
        headers[http_constants.HttpHeaders.PreTriggerInclude] = (
            pre_trigger_include
            if isinstance(pre_trigger_include, str)
            else (',').join(pre_trigger_include))

    post_trigger_include = options.get('postTriggerInclude')
    if post_trigger_include:
        headers[http_constants.HttpHeaders.PostTriggerInclude] = (
            post_trigger_include
            if isinstance(post_trigger_include, str)
            else (',').join(post_trigger_include))

    if options.get('maxItemCount'):
        headers[http_constants.HttpHeaders.PageSize] = options['maxItemCount']

    access_condition = options.get('accessCondition')
    if access_condition:
        if access_condition['type'] == 'IfMatch':
            headers[http_constants.HttpHeaders.IfMatch] = access_condition['condition']
        else:
            headers[http_constants.HttpHeaders.IfNoneMatch] = access_condition['condition']

    if options.get('indexingDirective'):
        headers[http_constants.HttpHeaders.IndexingDirective] = (
            options['indexingDirective'])

    consistency_level = None
    
    ''' get default client consistency level'''
    default_client_consistency_level = headers.get(http_constants.HttpHeaders.ConsistencyLevel)

    ''' set consistency level. check if set via options, this will 
    override the default '''
    if options.get('consistencyLevel'):
        consistency_level = options['consistencyLevel']
        headers[http_constants.HttpHeaders.ConsistencyLevel] = consistency_level
    elif default_client_consistency_level is not None:
        consistency_level = default_client_consistency_level
        headers[http_constants.HttpHeaders.ConsistencyLevel] = consistency_level

    # figure out if consistency level for this request is session
    is_session_consistency = (consistency_level == documents.ConsistencyLevel.Session)

    # set session token if required
    if is_session_consistency is True and not IsMasterResource(resource_type):
        # if there is a token set via option, then use it to override default
        if options.get('sessionToken'):
            headers[http_constants.HttpHeaders.SessionToken] = options['sessionToken']
        else:
            # check if the client's default consistency is session (and request consistency level is same), 
            # then update from session container
            if default_client_consistency_level == documents.ConsistencyLevel.Session:
                # populate session token from the client's session container
                headers[http_constants.HttpHeaders.SessionToken] = (
                    cosmos_client.session.get_session_token(path))
           
    if options.get('enableScanInQuery'):
        headers[http_constants.HttpHeaders.EnableScanInQuery] = (
            options['enableScanInQuery'])

    if options.get('resourceTokenExpirySeconds'):
        headers[http_constants.HttpHeaders.ResourceTokenExpiry] = (
            options['resourceTokenExpirySeconds'])

    if options.get('offerType'):
        headers[http_constants.HttpHeaders.OfferType] = options['offerType']

    if options.get('offerThroughput'):
        headers[http_constants.HttpHeaders.OfferThroughput] = options['offerThroughput']

    if 'partitionKey' in options:
        # if partitionKey value is Undefined, serialize it as {} to be consistent with other SDKs
        if options.get('partitionKey') is documents.Undefined:
            headers[http_constants.HttpHeaders.PartitionKey] = [{}]
        # else serialize using json dumps method which apart from regular values will serialize None into null
        else:
            headers[http_constants.HttpHeaders.PartitionKey] = json.dumps([options['partitionKey']])

    if options.get('enableCrossPartitionQuery'):
        headers[http_constants.HttpHeaders.EnableCrossPartitionQuery] = options['enableCrossPartitionQuery']

    if options.get('populateQueryMetrics'):
        headers[http_constants.HttpHeaders.PopulateQueryMetrics] = options['populateQueryMetrics']

    if cosmos_client.master_key:
        headers[http_constants.HttpHeaders.XDate] = (
            datetime.datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT'))

    if cosmos_client.master_key or cosmos_client.resource_tokens:
        authorization = auth.GetAuthorizationHeader(cosmos_client,
                                        verb,
                                        path,
                                        resource_id,
                                        IsNameBased(resource_id),
                                        resource_type,
                                        headers)
        # urllib.quote throws when the input parameter is None
        if authorization:
            # -_.!~*'() are valid characters in url, and shouldn't be quoted.
            authorization = urllib_quote(authorization, '-_.!~*\'()')
        headers[http_constants.HttpHeaders.Authorization] = authorization

    if verb == 'post' or verb == 'put':
        if not headers.get(http_constants.HttpHeaders.ContentType):
            headers[http_constants.HttpHeaders.ContentType] = runtime_constants.MediaTypes.Json

    if not headers.get(http_constants.HttpHeaders.Accept):
        headers[http_constants.HttpHeaders.Accept] = runtime_constants.MediaTypes.Json

    if partition_key_range_id is not None:
        headers[http_constants.HttpHeaders.PartitionKeyRangeID] = partition_key_range_id

    if options.get('enableScriptLogging'):
        headers[http_constants.HttpHeaders.EnableScriptLogging] = options['enableScriptLogging']

    if options.get('offerEnableRUPerMinuteThroughput'):
        headers[http_constants.HttpHeaders.OfferIsRUPerMinuteThroughputEnabled] = options['offerEnableRUPerMinuteThroughput']

    if options.get('disableRUPerMinuteUsage'):
        headers[http_constants.HttpHeaders.DisableRUPerMinuteUsage] = options['disableRUPerMinuteUsage']

    if options.get('changeFeed') is True:
        # On REST level, change feed is using IfNoneMatch/ETag instead of continuation.
        if_none_match_value = None
        if options.get('continuation'):
            if_none_match_value = options['continuation']
        elif options.get('isStartFromBeginning') and options['isStartFromBeginning'] == False:
            if_none_match_value = '*'
        if if_none_match_value:
            headers[http_constants.HttpHeaders.IfNoneMatch] = if_none_match_value
        headers[http_constants.HttpHeaders.AIM] = http_constants.HttpHeaders.IncrementalFeedHeaderValue
    else:
        if options.get('continuation'):
            headers[http_constants.HttpHeaders.Continuation] = (options['continuation'])

    if options.get('populatePartitionKeyRangeStatistics'):
            headers[http_constants.HttpHeaders.PopulatePartitionKeyRangeStatistics] = options['populatePartitionKeyRangeStatistics']

    if options.get('populateQuotaInfo'):
            headers[http_constants.HttpHeaders.PopulateQuotaInfo] = options['populateQuotaInfo']

    return headers