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

org.openqa.selenium.server.browserlaunchers.DoNotUseProxyPac 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
// Licensed to the Software Freedom Conservancy (SFC) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The SFC licenses this file
// to you 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 org.openqa.selenium.server.browserlaunchers;

import static java.util.Collections.unmodifiableMap;
import static java.util.Collections.unmodifiableSet;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import org.openqa.selenium.WebDriverException;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.Serializable;
import java.io.Writer;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * A representation of a proxy configuration file.
 */
public class DoNotUseProxyPac implements Serializable {
  // Note that we put the dash character at the end of the pattern
  private static final Pattern acceptableShExpPattern =
      Pattern.compile("[\\w\\*\\?:/\\.-]*");

  // Make an effort to preserve the ordering the user asked for.
  private final Set directUrls = new LinkedHashSet();
  private final Map proxiedUrls = new HashMap<>();
  private final Map proxiedRegexUrls = new HashMap<>();
  private final Set directHosts = new LinkedHashSet();
  private final Map proxiedHosts = new HashMap<>();
  // TODO(simon): Is this right? Really?
  private String defaultProxy = ""; // Does nothing. Emulates old behaviour of Selenium
  private URI deriveFrom;

  /**
   * Output the PAC file to the given writer.
   *
   * @param writer Will have config written to it.
   * @throws IOException Should the underlying writer fail.
   */
  public void outputTo(Writer writer) throws IOException {
    appendSuperPac(writer);

    writer.append("function FindProxyForURL(url, host) {\n");

    appendDirectHosts(writer);
    appendProxiedHosts(writer);
    appendDirectUrls(writer);
    appendProxiedUrls(writer);
    appendProxiedRegExUrls(writer);

    appendFallbackToSuperPac(writer);

    if (!"".equals(defaultProxy)) {
      writer.append("  return ").append(defaultProxy).append(";\n");
    }

    writer.append("}\n");
  }

  private void appendSuperPac(Writer writer) throws IOException {
    if (deriveFrom == null) {
      return;
    }

    // TODO(simon): This is going to be a cause of bugs. Should detect encoding of incoming data.
    Reader reader = new InputStreamReader((InputStream) deriveFrom.toURL().getContent());
    StringBuilder content = new StringBuilder();
    for (int i = reader.read(); i != -1; i = reader.read()) {
      content.append((char) i);
    }

    writer.append(content.toString().replace("FindProxyForURL", "originalFindProxyForURL"));
    writer.append("\n");
  }

  private void appendFallbackToSuperPac(Writer writer) throws IOException {
    if (deriveFrom == null) {
      return;
    }

    writer.append("\n")
        .append("  var value = originalFindProxyForURL(host, url);\n")
        .append("  if (value) { return value; }\n\n");
  }

  private void appendDirectHosts(Writer writer) throws IOException {
    for (String host : this.directHosts) {
      writer.append("  if (shExpMatch(host, '")
          .append(host)
          .append("')) { return 'DIRECT'; }\n");
    }
  }

  private void appendProxiedHosts(Writer writer) throws IOException {
    for (Map.Entry entry : proxiedHosts.entrySet()) {
      writer.append("  if (shExpMatch(host, '")
          .append(entry.getKey())
          .append("')) { return 'PROXY ")
          .append(entry.getValue())
          .append("'; }\n");
    }
  }

  private void appendDirectUrls(Writer writer) throws IOException {
    for (String url : this.directUrls) {
      writer.append("  if (shExpMatch(url, '")
          .append(url)
          .append("')) { return 'DIRECT'; }\n");
    }
  }

  private void appendProxiedUrls(Writer writer) throws IOException {
    for (Map.Entry entry : proxiedUrls.entrySet()) {
      writer.append("  if (shExpMatch(url, '")
          .append(entry.getKey())
          .append("')) { return 'PROXY ")
          .append(entry.getValue())
          .append("'; }\n");
    }
  }

  private void appendProxiedRegExUrls(Writer writer) throws IOException {
    for (Map.Entry entry : proxiedRegexUrls.entrySet()) {
      writer.append("  if (")
          .append(entry.getKey())
          .append(".test(url)) { return 'PROXY ")
          .append(entry.getValue())
          .append("'; }\n");
    }
  }

  public ProxyUrlVia map(String outgoingUrl) {
    return new ProxyUrlVia(outgoingUrl);
  }

  public ProxyHostVia mapHost(String hostname) {
    return new ProxyHostVia(hostname);
  }

  public DefaultProxy defaults() {
    return new DefaultProxy();
  }

  public Map asMap() {
    Map toReturn = new HashMap<>();
    if (!directUrls.isEmpty()) {
      toReturn.put("directUrls", unmodifiableSet(directUrls));
    }

    if (!proxiedUrls.isEmpty()) {
      toReturn.put("proxiedUrls", unmodifiableMap(proxiedUrls));
    }

    if (!proxiedRegexUrls.isEmpty()) {
      toReturn.put("proxiedRegexUrls", unmodifiableMap(proxiedRegexUrls));
    }

    if (!directHosts.isEmpty()) {
      toReturn.put("directHosts", unmodifiableSet(directHosts));
    }

    if (!proxiedHosts.isEmpty()) {
      toReturn.put("proxiedHosts", unmodifiableMap(proxiedHosts));
    }

    if (defaultProxy != null && !"".equals(defaultProxy)) {
      toReturn.put("defaultProxy", defaultProxy);
    }

    if (deriveFrom != null) {
      toReturn.put("deriveFrom", deriveFrom.toString());
    }

    return toReturn;
  }

  public static DoNotUseProxyPac fromJson(String text) {
    JsonObject json = new JsonParser().parse(text).getAsJsonObject();
    DoNotUseProxyPac pac = new DoNotUseProxyPac();

    if (json.has("directUrls")) {
      JsonArray allUrls = json.get("directUrls").getAsJsonArray();
      for (int i = 0; i < allUrls.size(); i++) {
        pac.map(allUrls.get(i).getAsString()).toNoProxy();
      }
    }

    if (json.has("directHosts")) {
      JsonArray allHosts = json.get("directHosts").getAsJsonArray();
      for (int i = 0; i < allHosts.size(); i++) {
        pac.mapHost(allHosts.get(i).getAsString()).toNoProxy();
      }
    }

    if (json.has("proxiedHosts")) {
      JsonObject proxied = json.get("proxiedHosts").getAsJsonObject();
      for (Map.Entry entry : proxied.entrySet()) {
        pac.mapHost(entry.getKey()).toProxy(entry.getValue().getAsString());
      }
    }

    if (json.has("proxiedUrls")) {
      JsonObject proxied = json.get("proxiedUrls").getAsJsonObject();
      for (Map.Entry entry : proxied.entrySet()) {
        pac.map(entry.getKey()).toProxy(entry.getValue().getAsString());
      }
    }

    if (json.has("proxiedRegexUrls")) {
      JsonObject proxied = json.get("proxiedRegexUrls").getAsJsonObject();
      for (Map.Entry entry : proxied.entrySet()) {
        pac.map(entry.getKey()).toProxy(entry.getValue().getAsString());
      }
    }

    if (json.has("defaultProxy")) {
      if ("'DIRECT'".equals(json.get("defaultProxy").getAsString())) {
        pac.defaults().toNoProxy();
      } else {
        pac.defaults().toProxy(json.get("defaultProxy").getAsString());
      }
    }

    if (json.has("deriveFrom")) {
      try {
        pac.deriveFrom(new URI(json.get("deriveFrom").getAsString()));
      } catch (URISyntaxException e) {
        throw new WebDriverException(e);
      }
    }

    return pac;
  }

  public DoNotUseProxyPac deriveFrom(URI uri) {
    // Store the uri for now
    this.deriveFrom = uri;
    return this;
  }

  public class ProxyUrlVia {
    private String outgoingUrl;

    private ProxyUrlVia(String outgoingUrl) {
      this.outgoingUrl = outgoingUrl;
    }

    public DoNotUseProxyPac toProxy(String proxyVia) {
      if (isIeIncompatibleRegEx(outgoingUrl)) {
        proxiedRegexUrls.put(outgoingUrl, proxyVia);
      } else {
        proxiedUrls.put(outgoingUrl, proxyVia);
      }
      return DoNotUseProxyPac.this;
    }

    // See: http://support.microsoft.com/kb/274204

    private boolean isIeIncompatibleRegEx(String outgoingUrl) {
      return !acceptableShExpPattern.matcher(outgoingUrl).matches();
    }

    public DoNotUseProxyPac toNoProxy() {
      DoNotUseProxyPac.this.directUrls.add(outgoingUrl);
      return DoNotUseProxyPac.this;
    }
  }

  public class ProxyHostVia {
    private String host;

    private ProxyHostVia(String host) {
      this.host = host;
    }

    public DoNotUseProxyPac toProxy(String proxyVia) {
      proxiedHosts.put(host, proxyVia);
      return DoNotUseProxyPac.this;
    }

    public DoNotUseProxyPac toNoProxy() {
      directHosts.add(host);
      return DoNotUseProxyPac.this;
    }
  }

  public class DefaultProxy {
    public DoNotUseProxyPac toNoProxy() {
      defaultProxy = "'DIRECT'";
      return DoNotUseProxyPac.this;
    }

    public DoNotUseProxyPac toProxy(String proxyVia) {
      defaultProxy = "'PROXY " + proxyVia + "'";
      return DoNotUseProxyPac.this;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy