You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by fs...@apache.org on 2020/08/08 12:32:02 UTC

[jmeter] branch master updated: Implement a new setting to allow the exclusion of embedded URLs

This is an automated email from the ASF dual-hosted git repository.

fschumacher pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/jmeter.git


The following commit(s) were added to refs/heads/master by this push:
     new 0592978  Implement a new setting to allow the exclusion of embedded URLs
0592978 is described below

commit 0592978cb16ff8e7aea3ca96215e01141a78c2cd
Author: Felix Schumacher <fe...@internetallee.de>
AuthorDate: Sun Aug 2 15:25:18 2020 +0200

    Implement a new setting to allow the exclusion of embedded URLs
    
    At the moment we allow only one regular expression to control which URLs will
    be downloaded by the HTTP sampler, when embedded download is enabled.
    
    This can be used to exclude specific URLs, but it is not possible to exclude and allow
    URLs at the same time.
    
    This patch gives the user a second field which can be used to exclude URLs.
    
    Bugzilla Id: 63527
    Closes #607
---
 .../apache/jmeter/resources/messages.properties    |   1 +
 .../apache/jmeter/resources/messages_fr.properties |   1 +
 src/protocol/build.gradle.kts                      |   1 +
 .../protocol/http/config/gui/HttpDefaultsGui.java  |  62 +++++++++++++--------
 .../http/control/gui/HttpTestSampleGui.java        |  52 +++++++++--------
 .../protocol/http/sampler/HTTPSamplerBase.java     |  41 ++++++++++++--
 xdocs/changes.xml                                  |   1 +
 .../http-request-defaults-advanced-tab.png         | Bin 9455 -> 19213 bytes
 .../screenshots/http-request-advanced-tab.png      | Bin 6194 -> 18573 bytes
 xdocs/usermanual/component_reference.xml           |  22 ++++++--
 10 files changed, 123 insertions(+), 58 deletions(-)

diff --git a/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties b/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties
index f598f6f..1ed1d21 100644
--- a/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties
+++ b/src/core/src/main/resources/org/apache/jmeter/resources/messages.properties
@@ -1459,6 +1459,7 @@ web_testing_basic=Basic
 web_testing_advanced=Advanced
 web_testing_concurrent_download=Parallel downloads. Number:
 web_testing_embedded_url_pattern=URLs must match\:
+web_testing_embedded_url_exclude_pattern=URLs must not match\:
 web_testing_retrieve_images=Retrieve All Embedded Resources
 web_testing_retrieve_title=Embedded Resources from HTML Files
 web_testing_source_ip=Source address
diff --git a/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties b/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties
index c43d7d7..cff6458 100644
--- a/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties
+++ b/src/core/src/main/resources/org/apache/jmeter/resources/messages_fr.properties
@@ -1448,6 +1448,7 @@ web_testing_advanced=Avancée
 web_testing_basic=Basique
 web_testing_concurrent_download=Téléchargements en parallèle. Nombre \:
 web_testing_embedded_url_pattern=Les URL à inclure doivent correspondre à \:
+web_testing_embedded_url_exclude_pattern=Les URL à exclure doivent correspondre à \:
 web_testing_retrieve_images=Récupérer les ressources incluses
 web_testing_retrieve_title=Ressources incluses dans les pages HTML
 web_testing_source_ip=Adresse source
diff --git a/src/protocol/build.gradle.kts b/src/protocol/build.gradle.kts
index 8167828..a23f529 100644
--- a/src/protocol/build.gradle.kts
+++ b/src/protocol/build.gradle.kts
@@ -84,6 +84,7 @@ project("http") {
         implementation("org.apache.httpcomponents:httpmime")
         implementation("org.apache.httpcomponents:httpcore")
         implementation("org.brotli:dec")
+        implementation("com.miglayout:miglayout-swing")
         testImplementation(testFixtures(project(":src:testkit-wiremock")))
         testImplementation("com.github.tomakehurst:wiremock-jre8")
     }
diff --git a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/config/gui/HttpDefaultsGui.java b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/config/gui/HttpDefaultsGui.java
index 3e035b5..e97db473 100644
--- a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/config/gui/HttpDefaultsGui.java
+++ b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/config/gui/HttpDefaultsGui.java
@@ -46,7 +46,8 @@ import org.apache.jmeter.testelement.property.IntegerProperty;
 import org.apache.jmeter.testelement.property.StringProperty;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.gui.JFactory;
-import org.apache.jorphan.gui.JLabeledTextField;
+
+import net.miginfocom.swing.MigLayout;
 
 /**
  * GUI for Http Request defaults
@@ -55,14 +56,15 @@ import org.apache.jorphan.gui.JLabeledTextField;
 @TestElementMetadata(labelResource = "url_config_title")
 public class HttpDefaultsGui extends AbstractConfigGui {
 
-    private static final long serialVersionUID = 241L;
+    private static final long serialVersionUID = 242L;
 
     private UrlConfigGui urlConfigGui;
     private JCheckBox retrieveEmbeddedResources;
     private JCheckBox concurrentDwn;
     private JTextField concurrentPool;
     private JCheckBox useMD5;
-    private JLabeledTextField embeddedRE; // regular expression used to match against embedded resource URLs
+    private JTextField embeddedAllowRE; // regular expression used to match against embedded resource URLs to allow
+    private JTextField embeddedExcludeRE; // regular expression used to match against embedded resource URLs to discard
     private JTextField sourceIpAddr; // does not apply to Java implementation
     private JComboBox<String> sourceIpType = new JComboBox<>(HTTPSamplerBase.getSourceTypeList());
     private JTextField proxyScheme;
@@ -131,12 +133,18 @@ public class HttpDefaultsGui extends AbstractConfigGui {
         } else {
             config.removeProperty(HTTPSamplerBase.MD5);
         }
-        if (!StringUtils.isEmpty(embeddedRE.getText())) {
+        if (!StringUtils.isEmpty(embeddedAllowRE.getText())) {
             config.setProperty(new StringProperty(HTTPSamplerBase.EMBEDDED_URL_RE,
-                    embeddedRE.getText()));
+                    embeddedAllowRE.getText()));
         } else {
             config.removeProperty(HTTPSamplerBase.EMBEDDED_URL_RE);
         }
+        if (!StringUtils.isEmpty(embeddedExcludeRE.getText())) {
+            config.setProperty(new StringProperty(HTTPSamplerBase.EMBEDDED_URL_EXCLUDE_RE,
+                    embeddedExcludeRE.getText()));
+        } else {
+            config.removeProperty(HTTPSamplerBase.EMBEDDED_URL_EXCLUDE_RE);
+        }
 
         if(!StringUtils.isEmpty(sourceIpAddr.getText())) {
             config.setProperty(new StringProperty(HTTPSamplerBase.IP_SOURCE,
@@ -170,7 +178,8 @@ public class HttpDefaultsGui extends AbstractConfigGui {
         enableConcurrentDwn(false);
         useMD5.setSelected(false);
         urlConfigGui.clear();
-        embeddedRE.setText(""); // $NON-NLS-1$
+        embeddedAllowRE.setText(""); // $NON-NLS-1$
+        embeddedExcludeRE.setText(""); // $NON-NLS-1$
         sourceIpAddr.setText(""); // $NON-NLS-1$
         sourceIpType.setSelectedIndex(HTTPSamplerBase.SourceType.HOSTNAME.ordinal()); //default: IP/Hostname
         proxyScheme.setText(""); // $NON-NLS-1$
@@ -192,7 +201,8 @@ public class HttpDefaultsGui extends AbstractConfigGui {
         concurrentDwn.setSelected(samplerBase.getPropertyAsBoolean(HTTPSamplerBase.CONCURRENT_DWN));
         concurrentPool.setText(samplerBase.getPropertyAsString(HTTPSamplerBase.CONCURRENT_POOL));
         useMD5.setSelected(samplerBase.getPropertyAsBoolean(HTTPSamplerBase.MD5, false));
-        embeddedRE.setText(samplerBase.getPropertyAsString(HTTPSamplerBase.EMBEDDED_URL_RE, ""));//$NON-NLS-1$
+        embeddedAllowRE.setText(samplerBase.getPropertyAsString(HTTPSamplerBase.EMBEDDED_URL_RE, ""));//$NON-NLS-1$
+        embeddedExcludeRE.setText(samplerBase.getPropertyAsString(HTTPSamplerBase.EMBEDDED_URL_EXCLUDE_RE, ""));//$NON-NLS-1$
         sourceIpAddr.setText(samplerBase.getPropertyAsString(HTTPSamplerBase.IP_SOURCE)); //$NON-NLS-1$
         sourceIpType.setSelectedIndex(
                 samplerBase.getPropertyAsInt(HTTPSamplerBase.IP_SOURCE_TYPE,
@@ -294,22 +304,33 @@ public class HttpDefaultsGui extends AbstractConfigGui {
         });
         concurrentPool = new JTextField(2); // 2 columns size
         concurrentPool.setMinimumSize(new Dimension(10, (int) concurrentPool.getPreferredSize().getHeight()));
-        concurrentPool.setMaximumSize(new Dimension(30, (int) concurrentPool.getPreferredSize().getHeight()));
+        concurrentPool.setMaximumSize(new Dimension(60, (int) concurrentPool.getPreferredSize().getHeight()));
 
-        final JPanel embeddedRsrcPanel = new HorizontalPanel();
+        final JPanel embeddedRsrcPanel = new JPanel(new MigLayout());
         embeddedRsrcPanel.setBorder(BorderFactory.createTitledBorder(
                 JMeterUtils.getResString("web_testing_retrieve_title"))); // $NON-NLS-1$
         embeddedRsrcPanel.add(retrieveEmbeddedResources);
         embeddedRsrcPanel.add(concurrentDwn);
-        embeddedRsrcPanel.add(concurrentPool);
+        embeddedRsrcPanel.add(concurrentPool, "wrap");
+
+        // Embedded URL match regex to allow
+        embeddedAllowRE = addTextFieldWithLabel(embeddedRsrcPanel, JMeterUtils.getResString("web_testing_embedded_url_pattern")); // $NON-NLS-1$
 
-        // Embedded URL match regex
-        embeddedRE = new JLabeledTextField(JMeterUtils.getResString("web_testing_embedded_url_pattern"),20); // $NON-NLS-1$
-        embeddedRsrcPanel.add(embeddedRE);
+        // Embedded URL match regex to exclude
+        embeddedExcludeRE = addTextFieldWithLabel(embeddedRsrcPanel, JMeterUtils.getResString("web_testing_embedded_url_exclude_pattern")); // $NON-NLS-1$
 
         return embeddedRsrcPanel;
     }
 
+    private JTextField addTextFieldWithLabel(JPanel panel, String labelText) {
+        JLabel label = new JLabel(labelText); // $NON-NLS-1$
+        JTextField field = new JTextField(100);
+        label.setLabelFor(field);
+        panel.add(label);
+        panel.add(field, "span");
+        return field;
+    }
+
     protected JPanel createSourceAddrPanel() {
         final JPanel sourceAddrPanel = new HorizontalPanel();
         sourceAddrPanel.setBorder(BorderFactory.createTitledBorder(
@@ -343,17 +364,10 @@ public class HttpDefaultsGui extends AbstractConfigGui {
     }
 
     private void enableConcurrentDwn(final boolean enable) {
-        if (enable) {
-            concurrentDwn.setEnabled(true);
-            embeddedRE.setEnabled(true);
-            if (concurrentDwn.isSelected()) {
-                concurrentPool.setEnabled(true);
-            }
-        } else {
-            concurrentDwn.setEnabled(false);
-            concurrentPool.setEnabled(false);
-            embeddedRE.setEnabled(false);
-        }
+        concurrentDwn.setEnabled(enable);
+        embeddedAllowRE.setEnabled(enable);
+        embeddedExcludeRE.setEnabled(enable);
+        concurrentPool.setEnabled(concurrentDwn.isSelected() && enable);
     }
 
     /**
diff --git a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui.java b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui.java
index b753e72..f7acf2a 100644
--- a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui.java
+++ b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/control/gui/HttpTestSampleGui.java
@@ -43,7 +43,8 @@ import org.apache.jmeter.samplers.gui.AbstractSamplerGui;
 import org.apache.jmeter.testelement.TestElement;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.gui.JFactory;
-import org.apache.jorphan.gui.JLabeledTextField;
+
+import net.miginfocom.swing.MigLayout;
 
 /**
  * HTTP Sampler GUI
@@ -52,14 +53,15 @@ import org.apache.jorphan.gui.JLabeledTextField;
 @TestElementMetadata(labelResource = "web_testing_title")
 public class HttpTestSampleGui extends AbstractSamplerGui {
 
-    private static final long serialVersionUID = 241L;
+    private static final long serialVersionUID = 242L;
 
     private UrlConfigGui urlConfigGui;
     private JCheckBox retrieveEmbeddedResources;
     private JCheckBox concurrentDwn;
     private JTextField concurrentPool;
     private JCheckBox useMD5;
-    private JLabeledTextField embeddedRE; // regular expression used to match against embedded resource URLs
+    private JTextField embeddedAllowRE; // regular expression used to match against embedded resource URLs to allow
+    private JTextField embeddedExcludeRE; // regular expression used to match against embedded resource URLs to exclude
     private JTextField sourceIpAddr; // does not apply to Java implementation
     private JComboBox<String> sourceIpType = new JComboBox<>(HTTPSamplerBase.getSourceTypeList());
     private JTextField proxyScheme;
@@ -96,7 +98,8 @@ public class HttpTestSampleGui extends AbstractSamplerGui {
         concurrentDwn.setSelected(samplerBase.isConcurrentDwn());
         concurrentPool.setText(samplerBase.getConcurrentPool());
         useMD5.setSelected(samplerBase.useMD5());
-        embeddedRE.setText(samplerBase.getEmbeddedUrlRE());
+        embeddedAllowRE.setText(samplerBase.getEmbeddedUrlRE());
+        embeddedExcludeRE.setText(samplerBase.getEmbededUrlExcludeRE());
         if (!isAJP) {
             sourceIpAddr.setText(samplerBase.getIpSource());
             sourceIpType.setSelectedIndex(samplerBase.getIpSourceType());
@@ -136,7 +139,8 @@ public class HttpTestSampleGui extends AbstractSamplerGui {
         samplerBase.setConcurrentDwn(concurrentDwn.isSelected());
         samplerBase.setConcurrentPool(concurrentPool.getText());
         samplerBase.setMD5(useMD5.isSelected());
-        samplerBase.setEmbeddedUrlRE(embeddedRE.getText());
+        samplerBase.setEmbeddedUrlRE(embeddedAllowRE.getText());
+        samplerBase.setEmbeddedUrlExcludeRE(embeddedExcludeRE.getText());
         if (!isAJP) {
             samplerBase.setIpSource(sourceIpAddr.getText());
             samplerBase.setIpSourceType(sourceIpType.getSelectedIndex());
@@ -256,22 +260,33 @@ public class HttpTestSampleGui extends AbstractSamplerGui {
         });
         concurrentPool = new JTextField(2); // 2 column size
         concurrentPool.setMinimumSize(new Dimension(10, (int) concurrentPool.getPreferredSize().getHeight()));
-        concurrentPool.setMaximumSize(new Dimension(30, (int) concurrentPool.getPreferredSize().getHeight()));
+        concurrentPool.setMaximumSize(new Dimension(60, (int) concurrentPool.getPreferredSize().getHeight()));
 
-        final JPanel embeddedRsrcPanel = new HorizontalPanel();
+        final JPanel embeddedRsrcPanel = new JPanel(new MigLayout());
         embeddedRsrcPanel.setBorder(BorderFactory.createTitledBorder(
                 JMeterUtils.getResString("web_testing_retrieve_title"))); // $NON-NLS-1$
         embeddedRsrcPanel.add(retrieveEmbeddedResources);
         embeddedRsrcPanel.add(concurrentDwn);
-        embeddedRsrcPanel.add(concurrentPool);
+        embeddedRsrcPanel.add(concurrentPool, "wrap");
 
         // Embedded URL match regex
-        embeddedRE = new JLabeledTextField(JMeterUtils.getResString("web_testing_embedded_url_pattern"),20); // $NON-NLS-1$
-        embeddedRsrcPanel.add(embeddedRE);
+        embeddedAllowRE = addTextFieldWithLabel(embeddedRsrcPanel, JMeterUtils.getResString("web_testing_embedded_url_pattern")); // $NON-NLS-1$
+
+        // Embedded URL to not match regex
+        embeddedExcludeRE = addTextFieldWithLabel(embeddedRsrcPanel, JMeterUtils.getResString("web_testing_embedded_url_exclude_pattern")); // $NON-NLS-1$
 
         return embeddedRsrcPanel;
     }
 
+    private JTextField addTextFieldWithLabel(JPanel panel, String labelText) {
+        JLabel label = new JLabel(labelText); // $NON-NLS-1$
+        JTextField field = new JTextField(100);
+        label.setLabelFor(field);
+        panel.add(label);
+        panel.add(field, "span");
+        return field;
+    }
+
     /**
      * Create a panel containing the implementation details
      *
@@ -334,7 +349,7 @@ public class HttpTestSampleGui extends AbstractSamplerGui {
         enableConcurrentDwn(false);
         useMD5.setSelected(false);
         urlConfigGui.clear();
-        embeddedRE.setText(""); // $NON-NLS-1$
+        embeddedAllowRE.setText(""); // $NON-NLS-1$
         if (!isAJP) {
             sourceIpAddr.setText(""); // $NON-NLS-1$
             sourceIpType.setSelectedIndex(HTTPSamplerBase.SourceType.HOSTNAME.ordinal()); //default: IP/Hostname
@@ -350,17 +365,10 @@ public class HttpTestSampleGui extends AbstractSamplerGui {
     }
 
     private void enableConcurrentDwn(boolean enable) {
-        if (enable) {
-            concurrentDwn.setEnabled(true);
-            embeddedRE.setEnabled(true);
-            if (concurrentDwn.isSelected()) {
-                concurrentPool.setEnabled(true);
-            }
-        } else {
-            concurrentDwn.setEnabled(false);
-            concurrentPool.setEnabled(false);
-            embeddedRE.setEnabled(false);
-        }
+        concurrentDwn.setEnabled(enable);
+        embeddedAllowRE.setEnabled(enable);
+        embeddedExcludeRE.setEnabled(enable);
+        concurrentPool.setEnabled(concurrentDwn.isSelected() && enable);
     }
 
 
diff --git a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
index b73bf59..a897960 100644
--- a/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
+++ b/src/protocol/http/src/main/java/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
@@ -100,7 +100,7 @@ public abstract class HTTPSamplerBase extends AbstractSampler
     implements TestStateListener, TestIterationListener, ThreadListener, HTTPConstantsInterface,
         Replaceable {
 
-    private static final long serialVersionUID = 242L;
+    private static final long serialVersionUID = 243L;
 
     private static final Logger log = LoggerFactory.getLogger(HTTPSamplerBase.class);
 
@@ -266,6 +266,9 @@ public abstract class HTTPSamplerBase extends AbstractSampler
     // Embedded URLs must match this RE (if provided)
     public static final String EMBEDDED_URL_RE = "HTTPSampler.embedded_url_re"; // $NON-NLS-1$
 
+    // Embedded URLs must not match this RE (if provided)
+    public static final String EMBEDDED_URL_EXCLUDE_RE = "HTTPSampler.embedded_url_exclude_re"; // $NON-NLS-1$
+
     public static final String MONITOR = "HTTPSampler.monitor"; // $NON-NLS-1$
 
     // Store MD5 hash instead of storing response
@@ -1027,6 +1030,17 @@ public abstract class HTTPSamplerBase extends AbstractSampler
     }
 
     /**
+     * @return the regular (as String) expression that embedded URLs must not match
+     */
+    public String getEmbededUrlExcludeRE() {
+        return getPropertyAsString(EMBEDDED_URL_EXCLUDE_RE, "");
+    }
+
+    public void setEmbeddedUrlExcludeRE(String regex) {
+        setProperty(new StringProperty(EMBEDDED_URL_EXCLUDE_RE, regex));
+    }
+
+    /**
      * Populates the provided HTTPSampleResult with details from the Exception.
      * Does not create a new instance, so should not be used directly to add a subsample.
      *
@@ -1349,17 +1363,29 @@ public abstract class HTTPSamplerBase extends AbstractSampler
             res = lContainer;
 
             // Get the URL matcher
-            String re = getEmbeddedUrlRE();
+            String allowRegex = getEmbeddedUrlRE();
             Perl5Matcher localMatcher = null;
-            Pattern pattern = null;
-            if (re.length() > 0) {
+            Pattern allowPattern = null;
+            if (allowRegex.length() > 0) {
                 try {
-                    pattern = JMeterUtils.getPattern(re);
+                    allowPattern = JMeterUtils.getPattern(allowRegex);
                     localMatcher = JMeterUtils.getMatcher();// don't fetch unless pattern compiles
                 } catch (MalformedCachePatternException e) { // NOSONAR
                     log.warn("Ignoring embedded URL match string: {}", e.getMessage());
                 }
             }
+            Pattern excludePattern = null;
+            String excludeRegex = getEmbededUrlExcludeRE();
+            if (excludeRegex.length() > 0) {
+                try {
+                    excludePattern = JMeterUtils.getPattern(excludeRegex);
+                    if (localMatcher != null) {
+                        localMatcher = JMeterUtils.getMatcher();// don't fetch unless pattern compiles
+                    }
+                } catch (MalformedCachePatternException e) { // NOSONAR
+                    log.warn("Ignoring embedded URL exclude string: {}", e.getMessage());
+                }
+            }
 
             // For concurrent get resources
             final List<Callable<AsynSamplerResultHolder>> list = new ArrayList<>();
@@ -1397,7 +1423,10 @@ public abstract class HTTPSamplerBase extends AbstractSampler
                             continue;
                         }
                         // I don't think localMatcher can be null here, but check just in case
-                        if (pattern != null && localMatcher != null && !localMatcher.matches(url.toString(), pattern)) {
+                        if (allowPattern != null && localMatcher != null && !localMatcher.matches(url.toString(), allowPattern)) {
+                            continue; // we have a pattern and the URL does not match, so skip it
+                        }
+                        if (excludePattern != null && localMatcher != null && localMatcher.matches(url.toString(), excludePattern)) {
                             continue; // we have a pattern and the URL does not match, so skip it
                         }
                         try {
diff --git a/xdocs/changes.xml b/xdocs/changes.xml
index c8adf33..cac3efc 100644
--- a/xdocs/changes.xml
+++ b/xdocs/changes.xml
@@ -77,6 +77,7 @@ Summary
 
 <h3>HTTP Samplers and Test Script Recorder</h3>
 <ul>
+    <li><bug>63527</li>Implement a new setting to allow the exclusion of embedded URLs</li>
 </ul>
 
 <h3>Other samplers</h3>
diff --git a/xdocs/images/screenshots/http-config/http-request-defaults-advanced-tab.png b/xdocs/images/screenshots/http-config/http-request-defaults-advanced-tab.png
index 0e85647..6c77fa2 100644
Binary files a/xdocs/images/screenshots/http-config/http-request-defaults-advanced-tab.png and b/xdocs/images/screenshots/http-config/http-request-defaults-advanced-tab.png differ
diff --git a/xdocs/images/screenshots/http-request-advanced-tab.png b/xdocs/images/screenshots/http-request-advanced-tab.png
index e21d134..b620384 100644
Binary files a/xdocs/images/screenshots/http-request-advanced-tab.png and b/xdocs/images/screenshots/http-request-advanced-tab.png differ
diff --git a/xdocs/usermanual/component_reference.xml b/xdocs/usermanual/component_reference.xml
index 7a60c75..d78a5db 100644
--- a/xdocs/usermanual/component_reference.xml
+++ b/xdocs/usermanual/component_reference.xml
@@ -331,10 +331,15 @@ and send HTTP/HTTPS requests for all images, Java applets, JavaScript files, CSS
        Instead, the 32 character MD5 hash of the data is calculated and stored instead.
        This is intended for testing large amounts of data.
        </property>
-        <property name="Embedded URLs must match:" required="No">
+        <property name="URLs must match:" required="No">
         If present, this must be a regular expression that is used to match against any embedded URLs found.
-        So if you only want to download embedded resources from <code>http://example.com/</code>, use the expression:
-        <code>http://example\.com/.*</code>
+        So if you only want to download embedded resources from <code>http://example.invalid/</code>, use the expression:
+        <code>http://example\.invalid/.*</code>
+        </property>
+        <property name="URLs must not match:" required="No">
+        If present, this must be a regular expression that is used to filter out any embedded URLs found.
+        So if you don't want to download PNG or SVG files from any source, use the expression:
+        <code>.*\.(?i:svg|png)</code>
         </property>
         <property name="Use concurrent pool" required="No">Use a pool of concurrent connections to get embedded resources.</property>
         <property name="Size" required="No">Pool size for concurrent connections used to get embedded resources.</property>
@@ -3898,10 +3903,15 @@ and send HTTP/HTTPS requests for all images, Java applets, JavaScript files, CSS
         </property>
         <property name="Use concurrent pool" required="No">Use a pool of concurrent connections to get embedded resources.</property>
         <property name="Size" required="No">Pool size for concurrent connections used to get embedded resources.</property>
-        <property name="Embedded URLs must match:" required="No">
+        <property name="URLs must match:" required="No">
         If present, this must be a regular expression that is used to match against any embedded URLs found.
-        So if you only want to download embedded resources from <code>http://example.com/</code>, use the expression:
-        <code>http://example\.com/.*</code>
+        So if you only want to download embedded resources from <code>http://example.invalid/</code>, use the expression:
+        <code>http://example\.invalid/.*</code>
+        </property>
+        <property name="URLs must not match:" required="No">
+        If present, this must be a regular expression that is used to filter out any embedded URLs found.
+        So if you don't want to download PNG or SVG files from any source, use the expression:
+        <code>.*\.(?i:svg|png)</code>
         </property>
 </properties>
 <note>