def write(self, *vals):
     ctx = context.force_epsilon_transition(self.ctx_)
     underlying = self.underlying_
     for val in vals:
         ctx_after, esc_modes, problem = (escaping.esc_mode_for_hole(ctx))
         if problem is not None:
             raise AutoescapeError(problem)
         ctx = ctx_after
         for esc_mode in esc_modes:
             escaper = escaping.SANITIZER_FOR_ESC_MODE[esc_mode]
             val = escaper(val)
         underlying.write(val)
     self.ctx_ = ctx
 def write(self, *vals):
     ctx = context.force_epsilon_transition(self.ctx_)
     underlying = self.underlying_
     for val in vals:
         ctx_after, esc_modes, problem = (
             escaping.esc_mode_for_hole(ctx)
         )
         if problem is not None:
             raise AutoescapeError(problem)
         ctx = ctx_after
         for esc_mode in esc_modes:
             escaper = escaping.SANITIZER_FOR_ESC_MODE[esc_mode]
             val = escaper(val)
         underlying.write(val)
     self.ctx_ = ctx
def esc_mode_for_hole(context_before):
    """
    Given a context in which an untrusted value hole appears, computes the
    escaping modes needed to render that untrusted value safe for interpolation
    and the context after the hole.

    context_before - The input context before the substitution.

    Returns (context after, (escaping_modes...,))
    """
    ctx = context.force_epsilon_transition(context_before)
    state, url_part = context.state_of(ctx), context.url_part_of(ctx)
    esc_modes = [ESC_MODE_FOR_STATE[state]]
    problem = None

    if url_part == context.URL_PART_NONE:
        # Make sure that at the start of a URL, we filter out dangerous
        # protocols.
        if state in (
            context.STATE_URL, context.STATE_CSS_URL, context.STATE_CSSDQ_URL,
            context.STATE_CSSSQ_URL):
            esc_modes = [ESC_MODE_FILTER_URL, ESC_MODE_NORMALIZE_URL]
            ctx = (ctx & ~context.URL_PART_ALL) | context.URL_PART_PRE_QUERY
        elif state in (context.STATE_CSSDQ_STR, context.STATE_CSSSQ_STR):
            esc_modes[:0] = [ESC_MODE_FILTER_URL]
            ctx = (ctx & ~context.URL_PART_ALL) | context.URL_PART_PRE_QUERY
    elif url_part == context.URL_PART_PRE_QUERY:
        if state not in (context.STATE_CSSDQ_STR, context.STATE_CSSSQ_STR):
            esc_modes[0] = ESC_MODE_NORMALIZE_URL
    elif url_part == context.URL_PART_QUERY_OR_FRAG:
        esc_modes[0] = ESC_MODE_ESCAPE_URL
    elif url_part == context.URL_PART_UNKNOWN:
        ctx = context.STATE_ERROR
        problem = 'hole appears in an ambiguous URL context'

    if state == context.STATE_JS:
        ctx = (ctx & ~context.JS_CTX_ALL) | context.JS_CTX_DIV_OP
    elif (state == context.STATE_ATTR_NAME
          and context.attr_type_of(ctx) != context.ATTR_NONE):
        esc_modes[0] = ESC_MODE_FILTER_HTML_ATTR_SUFFIX

    if esc_modes[0] is None:
        ctx = context.STATE_ERROR

    esc_mode = esc_modes[-1]
    delim_type = context.delim_type_of(ctx)
    if delim_type != context.DELIM_NONE:
        # Figure out how to escape the attribute value.
        if esc_mode != ESC_MODE_ESCAPE_HTML_ATTRIBUTE:
            esc_modes.append(ESC_MODE_ESCAPE_HTML_ATTRIBUTE)
        if (context.delim_type_of(context_before) == context.DELIM_NONE
            and delim_type == context.DELIM_SPACE_OR_TAG_END):
            esc_modes.append(ESC_MODE_OPEN_QUOTE)

    last, i = esc_modes[0], 1
    while i < len(esc_modes):
        curr = esc_modes[i]
        # If, for all x, f(g(x)) == g(x), we can skip f.
        if (last, curr) in REDUNDANT_ESC_MODES:
            esc_modes[i:i+1] = []
        else:
            last = curr
            i += 1
    return ctx, tuple(esc_modes), problem
def esc_mode_for_hole(context_before):
    """
    Given a context in which an untrusted value hole appears, computes the
    escaping modes needed to render that untrusted value safe for interpolation
    and the context after the hole.

    context_before - The input context before the substitution.

    Returns (context after, (escaping_modes...,))
    """
    ctx = context.force_epsilon_transition(context_before)
    state, url_part = context.state_of(ctx), context.url_part_of(ctx)
    esc_modes = [ESC_MODE_FOR_STATE[state]]
    problem = None

    if url_part == context.URL_PART_NONE:
        # Make sure that at the start of a URL, we filter out dangerous
        # protocols.
        if state in (context.STATE_URL, context.STATE_CSS_URL,
                     context.STATE_CSSDQ_URL, context.STATE_CSSSQ_URL):
            esc_modes = [ESC_MODE_FILTER_URL, ESC_MODE_NORMALIZE_URL]
            ctx = (ctx & ~context.URL_PART_ALL) | context.URL_PART_PRE_QUERY
        elif state in (context.STATE_CSSDQ_STR, context.STATE_CSSSQ_STR):
            esc_modes[:0] = [ESC_MODE_FILTER_URL]
            ctx = (ctx & ~context.URL_PART_ALL) | context.URL_PART_PRE_QUERY
    elif url_part == context.URL_PART_PRE_QUERY:
        if state not in (context.STATE_CSSDQ_STR, context.STATE_CSSSQ_STR):
            esc_modes[0] = ESC_MODE_NORMALIZE_URL
    elif url_part == context.URL_PART_QUERY_OR_FRAG:
        esc_modes[0] = ESC_MODE_ESCAPE_URL
    elif url_part == context.URL_PART_UNKNOWN:
        ctx = context.STATE_ERROR
        problem = 'hole appears in an ambiguous URL context'

    if state == context.STATE_JS:
        ctx = (ctx & ~context.JS_CTX_ALL) | context.JS_CTX_DIV_OP
    elif (state == context.STATE_ATTR_NAME
          and context.attr_type_of(ctx) != context.ATTR_NONE):
        esc_modes[0] = ESC_MODE_FILTER_HTML_ATTR_SUFFIX

    if esc_modes[0] is None:
        ctx = context.STATE_ERROR

    esc_mode = esc_modes[-1]
    delim_type = context.delim_type_of(ctx)
    if delim_type != context.DELIM_NONE:
        # Figure out how to escape the attribute value.
        if esc_mode != ESC_MODE_ESCAPE_HTML_ATTRIBUTE:
            esc_modes.append(ESC_MODE_ESCAPE_HTML_ATTRIBUTE)
        if (context.delim_type_of(context_before) == context.DELIM_NONE
                and delim_type == context.DELIM_SPACE_OR_TAG_END):
            esc_modes.append(ESC_MODE_OPEN_QUOTE)

    last, i = esc_modes[0], 1
    while i < len(esc_modes):
        curr = esc_modes[i]
        # If, for all x, f(g(x)) == g(x), we can skip f.
        if (last, curr) in REDUNDANT_ESC_MODES:
            esc_modes[i:i + 1] = []
        else:
            last = curr
            i += 1
    return ctx, tuple(esc_modes), problem