class CrossPlane::Analyzer

Constants

CONTEXTS
DIRECTIVES
NGX_ANY_CONF
NGX_CONF_1MORE
NGX_CONF_2MORE
NGX_CONF_ANY
NGX_CONF_BLOCK
NGX_CONF_FLAG
NGX_CONF_NOARGS

bit masks for different directive argument styles

NGX_CONF_TAKE1
NGX_CONF_TAKE12

some helpful argument style aliases

NGX_CONF_TAKE123
NGX_CONF_TAKE1234
NGX_CONF_TAKE13
NGX_CONF_TAKE2
NGX_CONF_TAKE23
NGX_CONF_TAKE3
NGX_CONF_TAKE4
NGX_CONF_TAKE5
NGX_CONF_TAKE6
NGX_CONF_TAKE7
NGX_DIRECT_CONF

bit masks for different directive locations

NGX_EVENT_CONF
NGX_HTTP_LIF_CONF
NGX_HTTP_LMT_CONF
NGX_HTTP_LOC_CONF
NGX_HTTP_MAIN_CONF
NGX_HTTP_SIF_CONF
NGX_HTTP_SRV_CONF
NGX_HTTP_UPS_CONF
NGX_MAIL_MAIN_CONF
NGX_MAIL_SRV_CONF
NGX_MAIN_CONF
NGX_STREAM_MAIN_CONF
NGX_STREAM_SRV_CONF
NGX_STREAM_UPS_CONF

Public Class Methods

new(*args) click to toggle source
# File lib/crossplane/analyzer.rb, line 1871
def initialize(*args)
        args = args[0] || {}
end

Public Instance Methods

analyze(fname, stmt, term, ctx, strict) click to toggle source
# File lib/crossplane/analyzer.rb, line 1885
def analyze(fname, stmt, term, ctx, strict)
        directive = stmt['directive']
        line = stmt['line']

        # if strict and directive isn't recognized then throw error
        if strict and not DIRECTIVES[directive]
                reason = format('unknown directive "%s"', directive)
                raise CrossPlane::NgxParserDirectiveUnknownError.new(fname, line, reason)
        end

        # if we don't know where this directive is allowed and how
        # many arguments it can take then don't bother analyzing it
        if not CONTEXTS[ctx] or not DIRECTIVES[directive]
                return
        end

        args = stmt['args'] || []
        n_args = args.length

        masks = DIRECTIVES[directive]
        ctx_mask = CONTEXTS[ctx]

        # if this directive can't be used in this context then throw an error
        masks = []
        DIRECTIVES[directive].each do |mask|
                if mask & ctx_mask
                        masks.push(mask)
                end
        end

        unless masks.length > 0
                reason = format('"%s" directive is not allowed here', directive)
                raise CrossPlane::NgxParserDirectiveContextError.new(fname, line, reason)
        end

        valid_flag = lambda { |x| return ['on', 'off'].include?(x.downcase) ? true : false }

        # do this in reverse because we only throw errors at the end if no masks
        # are valid, and typically the first bit mask is what the parser expects
        masks.reverse.each do |mask|
                # if the directive isn't a block but should be according to the mask
                if (mask & NGX_CONF_BLOCK > 0) and term != '{'
                        reason = format('directive "%s" has no opening "{"', directive)
                        next
                end

                # if the directive is a block but shouldn't be according to the mask
                if (not mask & NGX_CONF_BLOCK) and term != ';'
                        reason = format('directive "%s" is not terminated by ";"', directive)
                        next
                end

                # use mask to check the directive's arguments
                if ((mask >> n_args & 1 and n_args <= 7) or
                        (mask & NGX_CONF_FLAG and n_args == 1 and valid_flag.call(args[0])) or
                        (mask & NGX_CONF_ANY and n_args >= 0) or
                        (mask & NGX_CONF_1MORE and n_args >= 1) or
                        (mask & NGX_CONF_2MORE and n_args >= 2))
                        return
                elsif (mask & NGX_CONF_FLAG) and (n_args == 1) and not valid_flag.call(args[0])
                        reason = format('invalid value "%s" in "%%s" directive, it must be "on" or "off"', args[0], directive)
                else
                        reason = format('invalid number of arguments in "%s" directive', directive)
                end
        end

        if reason
                raise CrossPlane::NgxParserDirectiveArgumentsError.new(fname, line, reason)
        end
end
enter_block_ctx(stmt, ctx) click to toggle source
# File lib/crossplane/analyzer.rb, line 1875
def enter_block_ctx(stmt, ctx)
         # don't nest because NGX_HTTP_LOC_CONF just means "location block in http"
        if ctx and ctx[0] == 'http' and stmt['directive'] == 'location'
                return ['http', 'location']
        end

        # no other block contexts can be nested like location so just append it
        return ctx + [stmt['directive'],]
end
register_external_directives(directives) click to toggle source
# File lib/crossplane/analyzer.rb, line 1956
def register_external_directives(directives)
        directives.each do |directive, bitmasks|
                if bitmasks
                        DIRECTIVES[directive] = bitmasks
                end
        end
end