class ClientProps

Copyright
Author

Constants

CP_RULES

Public static constant

Public Class Methods

new(tree) click to toggle source
Calls superclass method PostWalkRules.new
# File ../Src/clientprops.rb, line 34
def initialize (tree)

        # Private constants
        @OPERATOR_EQUALS = "="
        @OPERATOR_NOT_EQUALS = "!="
        @OPERATOR_LESS_THAN = "<"
        @OPERATOR_LESS_THAN_EQUALS = "<="
        @OPERATOR_GREATER_THAN = ">"
        @OPERATOR_GREATER_THAN_EQUALS = ">="
        @USER_AGENT = "ua"

        # Table to replace HTML escape characters from property values in the cookie
        # content.
        @HTML_ESCAPE_CHARACTERS = {
                '&' => '&amp;',
                '"' => '&quot;',
                '<' => '&lt;',
                '>' => '&gt;'
        }
        
        super(tree, CP_RULES)
end

Public Instance Methods

getProperties(detectedProperties, clientProperties, typedValues) click to toggle source

Merge the tree walk properties with the client side properties and run any additional rules based on the client side and tree walk properties. The rules can define replacement or additional values for properties and can also provide a new User-Agent to be used for a second tree walk. This is typically a fake User-Agent mapped to a device that cannot normally be detected such as the various iPhone models.

detectedProperties

The results of the tree walk and UAR, map of property name to value.

clientProperties

The parsed client properties.

typedValues

Whether to return typed values or string values.

return

Associative array of properties or NULL if there are no properties.

# File ../Src/clientprops.rb, line 113
def getProperties(detectedProperties, clientProperties, typedValues)

        if clientProperties.nil?
                return detectedProperties
        end

        # Merge the tree walk properties with the client side properties and run any
        # additional rules based on the client side and tree walk properties. The 
        # rules can define replacement or additional values for properties and can 
        # also provide a new User-Agent to be used for a second tree walk. This is 
        # typically a fake User-Agent mapped to a device that cannot normally be 
        # detected such as the various iPhone models.
        PropsHandler::mergeProperties(detectedProperties, clientProperties)

        # using the merged properties to look up additional rules

        # STEP 1: try and find the rules to run on the UA
        ruleGroups = @branch[@RULE_GROUPS]
        rulesToRun = getRulesToRun(detectedProperties, ruleGroups, typedValues)

        # STEP 2: do second tree walk if necessary and replace/create any new 
        # values based on the rules
        if !rulesToRun.nil?
                
                userAgent = rulesToRun.userAgent
                
                if !userAgent.nil?
                        
                        # use the UA for a second tree walk - note the last param is 
                        # false as we know the UA won't have any dynamic properties
                        # also sought = nil
                        api = DeviceAtlas.new
                        secondTreeWalkProps = api.getProperties(@tree, userAgent, nil, typedValues, nil, false)
                        
                        # merge origProperties in to get any parent properties such as the dynamic properties
                        # 2nd tree walk > first tree walk
                        PropsHandler::mergeProperties(detectedProperties, secondTreeWalkProps)

                        # the client properties still take priority so merge them in again
                        # client props > tree walks
                        PropsHandler::mergeProperties(detectedProperties, clientProperties)

                end
                
                # overlay the new properties
                ruleSet = rulesToRun.ruleSet
                ruleSet.each do |propIdValId|
                        
                        propId = propIdValId[@PROPERTY]
                        propValId = propIdValId[@PROPERTY_VALUE]
                        
                        # get prop and val to set
                        propName = PropsHandler::propertyFromId(@tree, propId)
                        value = PropsHandler::getValue(@tree, propId, propValId, typedValues)
                        
                        # replace/create properties
                        detectedProperties[propName] = value
                        
                end

        end
        
        detectedProperties            
end
parseClientSideProperties(propStr, typedValues) click to toggle source

Parse the client side properties and if typed values is set convert the values to the appropriate type.

propStr

Cookie content with the form:

bjs.webGl:1|bjs.geoLocation:1|sdeviceAspectRatio:16/10|iusableDisplayHeight:1050 The first character of the property name is the type of the value.

typedValues

Whether to return typed values or string values.

# File ../Src/clientprops.rb, line 202
def parseClientSideProperties(propStr, typedValues)
        props = nil
        
        if propStr.nil?
                return props
        end
                
        begin

                propStr = propStr.strip
                propStr = propStr.gsub('"', '')

                props = {}

                doKey = true
                name = ''
                value = ''
                type = 0

                # iterate over the property string looking for properties and values
                numChars = propStr.length - 1

                for i in 0..numChars

                        # Besides we can handle strings as arrays to access to specific positions,
                        # we must consider that method doesn't work in the same way in Ruby 1.8
                        # and 1.9:
                        #  - 1.8: Returns the ASCII code of the character.
                        #  - 1.9: Returns the character.
                        #  
                        # Therefore, if we want to be sure we always get a character, we have to
                        # use the chr() function.


                        c = propStr[i].chr

                        case c
                        when '|'

                                # use our collected items
                                appendPropVal(props, name, value, type, typedValues)

                                # reset for next key/value
                                doKey = true       
                                name = ''
                                value = ''
                                type = 0                                                   

                                next # skip to the next character
                        when ':'
                                doKey = false
                                next # skip to the next character
                        when '"'
                                if i==0 || i==numChars
                                        next # skip any wrapping quotes
                                end
                        end 
        
                        if doKey
                                if type==0 && (c == 'b' || c=='i' || c=='s' || c=='d')
                                        type = c
                                else
                                        name += c.to_s
                                end

                        else
                                value += c.to_s
                        end

                end

                # add the last prop value
                appendPropVal(props, name, value, type, typedValues)

        rescue Exception => ex
                raise(ClientPropertiesException, "Could not decode client properties: " + ex.message)
        end
        
        props
end
propertyTypeCheck(cookie, property, type) click to toggle source

Check if a given property exists with a certain type. This follows the same logic as the Api.propertyTypeCheck() in that it really checks if a property exists and if it has the correct type.

cookie

The cookie string

property

The property to check

type

The type of the property

# File ../Src/clientprops.rb, line 186
def propertyTypeCheck(cookie, property, type)
        res = true
        if !cookie.nil? && !cookie[type+property]
                res = false
        end
        res
end

Protected Instance Methods

initGetMatcherPropertyIds(group, propIds) click to toggle source

Find all the properties that are used for matching. This is needed in case the Api.getProperty() function is called as we need these properties for the rules to work correctly

group

The rule group that can contain a property matcher.

propIds

The set of found property IDs.

return

An updated set of property IDs.

# File ../Src/clientprops.rb, line 65
def initGetMatcherPropertyIds(group, propIds)

        if group[@PROPERTY_MATCHER]
                propertyMatchers = group[@PROPERTY_MATCHER]
                
                propertyMatchers.each do |propertyMatcher|
                        propId = propertyMatcher[@PROPERTY]
                        if !propIds.include?(propId)
                                propIds.push(propId)
                        end
                end

        end
        
        propIds
end
initRuleSets(group) click to toggle source

Prepare the rule set by extracting it from the current group and wrapping it in an ArrayList. This is done to remain compatible with initGetRulePropertyIds()

group

The current parent group.

return

A list of all rule sets.

# File ../Src/clientprops.rb, line 89
def initRuleSets(group)
        # wrap the single rule set in an array list.
        
        item = {}
        item[@RULE_ARR] = group[@RULE_ARR]
        
        ruleSets = []
        ruleSets.push(item)
        
        ruleSets
end