All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openqa.selenium.server.HtmlIdentifier Maven / Gradle / Ivy

Go to download

Selenium automates browsers. That's it! What you do with that power is entirely up to you.

There is a newer version: 3.9.1
Show newest version
package org.openqa.selenium.server;

/*
 * HtmlIdentifier: a module to identify HTML (and in so doing determine whether it should be
 * injected with selenium JavaScript when running in proxy injection mode).
 * 
 * As content arrives from the web server, the selenium server must decide whether it is appropriate
 * to inject the selenium test harness JavaScript into that content.  It determines this by means of
 * logic in HtmlIdentifier, a module Patrick recently added.  This module looks at the suffix (e.g.,
 * .html, .js, etc.), the HTTP content type header field, and the content itself (e.g., it
 * asks questions like 'does it contain ""?').  It applies a series of rules which are used
 * to derive an integer score indicating whether injection is a good idea.
 * 
 * So if you find that proxy injection mode is inappropriately injecting JavaScript into content, or
 * not injecting JavaScript into content which needs it, then it is likely that HtmlIdentifier's rules
 * need to be adjusted.  First, you can diagnose the logic by running the selenium server in
 * debug mode, and looking at the logger output.  In this output you can see how any particular
 * content's score was arrived at.  For example:
 * 
 * HtmlIdentifier.shouldBeInjected("http://www.google.com/webhp", "text/html; charset=UTF-8", "...")
 *   applied rule [extension [html, htm] rule: match=10000]: 0
 *   applied rule [extension [jsp, asp, php, pl] rule: match=100]: 0
 *   applied rule [extension [dll, gif, ico, jpg, jpeg, png, dwr, js] rule: match=-1000]: 0
 *   applied rule [content  -100]: 1000
 *   applied rule [content  -100]: -100
 *   applied rule [content type text/html rule: match=100, failure to match -> -1000]: 100
 *   applied rule [dojo catcher rule: match=-100000]: 0
 *   total : 1000 (should inject)
 * 
 * If you find a case where an incorrect decision is being made, then
 * 
 * 1. add a test case to the HtmlIdentifierTest module to reproduce the problem
 * 2. add rules or adjust HtmlIdentifier's logic to fix the problem
 * 3. run all the tests to be sure that we haven't regressed in scenarios other than your own
 * 4. check it in
 */

import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;

public class HtmlIdentifier {
  static Logger log = Logger.getLogger(HtmlIdentifier.class.getName());
  private static List rules = new ArrayList();
  private static final int INJECTION_THRESHOLD = 200;

  static {
    rules.add(new ExtensionRule(new String[] {"html", "htm"}, 10000));
    rules.add(new ExtensionRule(new String[] {"jsp", "asp", "php", "pl"}, 100));
    // ebay dll contains HTML snippets which fool InjectionHelper. -nas
    rules.add(new ExtensionRule(new String[] {"dll", "js"}, -1000));
    rules.add(new ExtensionRule(new String[] {"gif", "ico", "jpg", "jpeg", "png", "dwr", "swf"},
        -10000));
    rules.add(new ContentRule(",
                                                    // but rather starts with 
    rules.add(new ContentRule("
                                                                           // fragments
    rules.add(new Rule("dojo catcher", -100000, 0) {
      @Override
      public int score(String path, String contentType, String contentPreview) {

        if (path == null) {
          return 0;
        }

        // dojo should never be processed
        if (path.contains("/dojo/")) {
          return -100000;
        }

        return 0;
      }
    });
  }

  public static boolean shouldBeInjected(String path, String contentType, String contentPreview) {
    int score = 0;

    log.fine("shouldBeInjected(\"" + path + "\", \"" + contentType + "\", \"...\")");

    for (Rule rule : rules) {
      int scoreDelta = rule.score(path, contentType, contentPreview);
      log.fine("    applied rule " + rule + ": " + scoreDelta);
      score += scoreDelta;
    }
    boolean shouldInject = (score > INJECTION_THRESHOLD);
    log.fine("    total : " + score + ">" + INJECTION_THRESHOLD + "?  (should " +
        (shouldInject ? "" : "not ") + "inject)");
    return shouldInject;
  }

  static abstract class Rule {
    protected final int missingScore;
    protected final int score;
    protected String name;

    public Rule(String name, int score, int missingScore) {
      this.name = name;
      this.score = score;
      this.missingScore = missingScore;
    }

    abstract int score(String path, String contentType, String contentPreview);

    @Override
    public String toString() {
      return "[" + name + " rule: match=" + score +
          (missingScore == 0 ? "" : (", failure to match -> " + missingScore))
          + "]";
    }
  }

  static class ExtensionRule extends Rule {
    List exts = new ArrayList();

    public ExtensionRule(String ext, int score) {
      super("extension " + ext, score, 0);
      exts.add(ext);
    }

    public ExtensionRule(String[] ext, int score) {
      super(null, score, 0);
      for (String s : ext) {
        exts.add(s);
      }
      name = "extension " + exts;
    }

    @Override
    public int score(String path, String contentType, String contentPreview) {
      if (path == null || !path.contains(".")) {
        return 0;
      }

      for (String ext : exts) {
        if (path.endsWith("." + ext)) {
          return score;
        }
      }

      return 0;
    }
  }

  static class ContentRule extends Rule {
    String contentInLowerCase;

    public ContentRule(String content, int score, int missingScore) {
      super("content " + content, score, missingScore);
      this.contentInLowerCase = content.toLowerCase();
    }

    @Override
    public int score(String path, String contentType, String contentPreview) {
      if (contentPreview == null) {
        return 0;
      }

      if (contentPreview.toLowerCase().contains(contentInLowerCase)) {
        return score;
      }
      return missingScore;
    }
  }

  static class ContentTypeRule extends Rule {
    String type;

    public ContentTypeRule(String type, int score, int missingScore) {
      super("content type " + type, score, missingScore);
      this.type = type;
    }

    @Override
    public int score(String path, String contentType, String contentPreview) {
      if (contentType == null) {
        return 0;
      }

      if (contentType.contains(type)) {
        return score;
      }
      return missingScore;
    }
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy