PerformAutoescapeVisitor.java :  » Google-tech » closure-templates » com » google » template » soy » parsepasses » Java Open Source

Java Open Source » Google tech » closure templates 
closure templates » com » google » template » soy » parsepasses » PerformAutoescapeVisitor.java
/*
 * Copyright 2008 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.google.template.soy.parsepasses;

import com.google.inject.Inject;
import com.google.template.soy.base.IdGenerator;
import com.google.template.soy.base.SoySyntaxException;
import com.google.template.soy.coredirectives.EscapeHtmlDirective;
import com.google.template.soy.coredirectives.NoAutoescapeDirective;
import com.google.template.soy.shared.restricted.SoyPrintDirective;
import com.google.template.soy.soytree.AbstractSoyNodeVisitor;
import com.google.template.soy.soytree.PrintDirectiveNode;
import com.google.template.soy.soytree.PrintNode;
import com.google.template.soy.soytree.SoyFileSetNode;
import com.google.template.soy.soytree.SoyNode;
import com.google.template.soy.soytree.SoyNode.ParentSoyNode;
import com.google.template.soy.soytree.TemplateNode;

import java.util.Map;


/**
 * Visitor for performing autoescape (for templates that have autoescape turned on, ensure there is
 * HTML-escaping on all 'print' nodes).
 *
 * <p> Important: Do not use outside of Soy code (treat as superpackage-private).
 *
 * <p> {@link #exec} should be called on a full parse tree. The directives on 'print' nodes may be
 * modified. There is no return value.
 *
 * @author Kai Huang
 */
public class PerformAutoescapeVisitor extends AbstractSoyNodeVisitor<Void> {


  /** Map of all SoyPrintDirectives (name to directive). */
  private final Map<String, SoyPrintDirective> soyDirectivesMap;

  /** The node id generator for the parse tree. Retrieved from the root SoyFileSetNode. */
  private IdGenerator nodeIdGen;

  /** Whether the current template that we're in has autoescape turned on (during a visit pass). */
  private boolean currTemplateShouldAutoescape;


  /**
   * @param soyDirectivesMap Map of all SoyPrintDirectives (name to directive).
   */
  @Inject
  PerformAutoescapeVisitor(Map<String, SoyPrintDirective> soyDirectivesMap) {
    this.soyDirectivesMap = soyDirectivesMap;
  }


  // -----------------------------------------------------------------------------------------------
  // Implementations for concrete classes.


  @Override protected void visitInternal(SoyFileSetNode node) {
    nodeIdGen = node.getNodeIdGen();
    visitChildren(node);
  }


  @Override protected void visitInternal(TemplateNode node) {
    currTemplateShouldAutoescape = node.shouldAutoescape();
    visitChildren(node);
  }


  @Override protected void visitInternal(PrintNode node) {

    // Traverse the list to (a) record whether we saw any directive that cancels autoescape
    // (including 'noAutoescape' of course) and (b) remove 'noAutoescape' directives.
    boolean shouldCancelAutoescape = false;
    for (PrintDirectiveNode directiveNode : node.getChildren()) {
      SoyPrintDirective directive = soyDirectivesMap.get(directiveNode.getName());
      if (directive == null) {
        throw new SoySyntaxException(
            "Failed to find SoyPrintDirective with name '" + directiveNode.getName() + "'" +
            " (tag " + node.toSourceString() +")");
      }
      if (directive.shouldCancelAutoescape()) {
        shouldCancelAutoescape = true;
        if (directive instanceof NoAutoescapeDirective) {
          node.removeChild(directiveNode);
        }
      }
    }

    // If appropriate, apply autoescape by adding an |escapeHtml directive (should be applied first
    // because other directives may add HTML tags).
    if (currTemplateShouldAutoescape && !shouldCancelAutoescape) {
      PrintDirectiveNode newEscapeHtmlDirectiveNode =
          new PrintDirectiveNode(nodeIdGen.genStringId(), EscapeHtmlDirective.NAME, "");
      node.addChild(0, newEscapeHtmlDirectiveNode);
    }
  }


  // -----------------------------------------------------------------------------------------------
  // Implementations for interfaces.


  @Override protected void visitInternal(SoyNode node) {
    // Nothing to do for non-parent node.
  }


  @Override protected void visitInternal(ParentSoyNode<? extends SoyNode> node) {
    visitChildren(node);
  }

}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.