1 18 19 package org.apache.jmeter.protocol.http.proxy; 20 21 import java.io.Serializable; 22 import java.util.Collection; 23 import java.util.Enumeration; 24 import java.util.HashSet; 25 import java.util.Iterator; 26 import java.util.LinkedList; 27 import java.util.List; 28 import junit.framework.TestCase; 29 30 import org.apache.jmeter.assertions.ResponseAssertion; 31 import org.apache.jmeter.config.Arguments; 32 import org.apache.jmeter.config.ConfigElement; 33 import org.apache.jmeter.config.ConfigTestElement; 34 import org.apache.jmeter.control.GenericController; 35 import org.apache.jmeter.engine.util.ValueReplacer; 36 import org.apache.jmeter.exceptions.IllegalUserActionException; 37 import org.apache.jmeter.functions.InvalidVariableException; 38 import org.apache.jmeter.gui.GuiPackage; 39 import org.apache.jmeter.gui.tree.JMeterTreeModel; 40 import org.apache.jmeter.gui.tree.JMeterTreeNode; 41 import org.apache.jmeter.protocol.http.control.HeaderManager; 42 import org.apache.jmeter.protocol.http.control.RecordingController; 43 import org.apache.jmeter.protocol.http.sampler.HTTPSampler; 44 import org.apache.jmeter.samplers.SampleEvent; 45 import org.apache.jmeter.samplers.SampleListener; 46 import org.apache.jmeter.samplers.SampleResult; 47 import org.apache.jmeter.testelement.TestElement; 48 import org.apache.jmeter.testelement.TestListener; 49 import org.apache.jmeter.testelement.TestPlan; 50 import org.apache.jmeter.testelement.WorkBench; 51 import org.apache.jmeter.testelement.property.BooleanProperty; 52 import org.apache.jmeter.testelement.property.CollectionProperty; 53 import org.apache.jmeter.testelement.property.IntegerProperty; 54 import org.apache.jmeter.testelement.property.JMeterProperty; 55 import org.apache.jmeter.testelement.property.PropertyIterator; 56 import org.apache.jmeter.threads.ThreadGroup; 57 import org.apache.jmeter.timers.Timer; 58 import org.apache.jmeter.util.JMeterUtils; 59 60 import org.apache.jorphan.logging.LoggingManager; 61 62 import org.apache.log.Logger; 63 64 import org.apache.oro.text.MalformedCachePatternException; 65 import org.apache.oro.text.PatternCacheLRU; 66 import org.apache.oro.text.regex.Pattern; 67 import org.apache.oro.text.regex.Perl5Compiler; 68 import org.apache.oro.text.regex.Perl5Matcher; 69 70 75 public class ProxyControl extends GenericController implements Serializable 76 { 77 transient private static Logger log = LoggingManager.getLoggerForClass(); 78 private Daemon server; 79 public static final int DEFAULT_PORT = 8080; 80 public static final String DEFAULT_PORT_S = 81 Integer.toString(DEFAULT_PORT); private static PatternCacheLRU patternCache = 83 new PatternCacheLRU(1000, new Perl5Compiler()); 84 transient Perl5Matcher matcher; 85 public static final String PORT = "ProxyControlGui.port"; 86 public static final String EXCLUDE_LIST = "ProxyControlGui.exclude_list"; 87 public static final String INCLUDE_LIST = "ProxyControlGui.include_list"; 88 public static final String CAPTURE_HTTP_HEADERS = "ProxyControlGui.capture_http_headers"; 89 public static final String ADD_ASSERTIONS = "ProxyControlGui.add_assertion"; 90 public static final String GROUPING_MODE = "ProxyControlGui.grouping_mode"; 91 public static final String USE_KEEPALIVE = "ProxyControlGui.use_keepalive"; 92 93 public static final int GROUPING_NO_GROUPS = 0; 94 public static final int GROUPING_ADD_SEPARATORS = 1; 95 public static final int GROUPING_IN_CONTROLLERS = 2; 96 public static final int GROUPING_STORE_FIRST_ONLY = 3; 97 98 private long lastTime = 0; private static final long sampleGap = 100 JMeterUtils.getPropDefault("proxy.pause",1000); private boolean addAssertions; 102 private int groupingMode; 103 private boolean useKeepAlive; 104 105 110 private JMeterTreeNode target; 111 112 public ProxyControl() 113 { 114 matcher = new Perl5Matcher(); 115 setPort(DEFAULT_PORT); 116 setExcludeList(new HashSet()); 117 setIncludeList(new HashSet()); 118 setCaptureHttpHeaders(true); } 120 121 public void setPort(int port) 122 { 123 this.setProperty(new IntegerProperty(PORT, port)); 124 } 125 126 public void setPort(String port) 127 { 128 setProperty(PORT,port); 129 } 130 131 public void setCaptureHttpHeaders(boolean capture) 132 { 133 setProperty(new BooleanProperty(CAPTURE_HTTP_HEADERS,capture)); 134 } 135 136 public void setGroupingMode(int grouping) 137 { 138 this.groupingMode= grouping; 139 setProperty(new IntegerProperty(GROUPING_MODE,grouping)); 140 } 141 142 public void setAssertions(boolean b) 143 { 144 addAssertions=b; 145 setProperty(new BooleanProperty(ADD_ASSERTIONS,b)); 146 } 147 148 151 public void setUseKeepAlive(boolean b) 152 { 153 useKeepAlive=b; 154 setProperty(new BooleanProperty(USE_KEEPALIVE,b)); 155 } 156 157 public void setIncludeList(Collection list) 158 { 159 setProperty(new CollectionProperty(INCLUDE_LIST, new HashSet(list))); 160 } 161 public void setExcludeList(Collection list) 162 { 163 setProperty(new CollectionProperty(EXCLUDE_LIST, new HashSet(list))); 164 } 165 166 public String getClassLabel() 167 { 168 return JMeterUtils.getResString("proxy_title"); 169 } 170 171 public int getPort() 172 { 173 return getPropertyAsInt(PORT); 174 } 175 176 public int getDefaultPort() 177 { 178 return DEFAULT_PORT; 179 } 180 181 public boolean getCaptureHttpHeaders() 182 { 183 return getPropertyAsBoolean(CAPTURE_HTTP_HEADERS); 184 } 185 186 public Class getGuiClass() 187 { 188 return org.apache.jmeter.protocol.http.proxy.gui.ProxyControlGui.class; 189 } 190 191 public void addConfigElement(ConfigElement config) 192 {} 193 194 public void startProxy() 195 { 196 notifyTestListenersOfStart(); 197 server = new Daemon(getPort(), this); 198 server.start(); 199 } 200 201 public void addExcludedPattern(String pattern) 202 { 203 getExcludePatterns().addItem(pattern); 204 } 205 206 public CollectionProperty getExcludePatterns() 207 { 208 return (CollectionProperty) getProperty(EXCLUDE_LIST); 209 } 210 211 public void addIncludedPattern(String pattern) 212 { 213 getIncludePatterns().addItem(pattern); 214 } 215 216 public CollectionProperty getIncludePatterns() 217 { 218 return (CollectionProperty) getProperty(INCLUDE_LIST); 219 } 220 221 public void clearExcludedPatterns() 222 { 223 getExcludePatterns().clear(); 224 } 225 226 public void clearIncludedPatterns() 227 { 228 getIncludePatterns().clear(); 229 } 230 231 234 public JMeterTreeNode getTarget() 235 { 236 return target; 237 } 238 239 243 public void setTarget(JMeterTreeNode target) 244 { 245 this.target= target; 246 } 247 248 254 public void deliverSampler( 255 HTTPSampler sampler, 256 TestElement[] subConfigs, 257 SampleResult result) 258 { 259 if (filterUrl(sampler)) 260 { 261 JMeterTreeNode myTarget= findTargetControllerNode(); 262 Collection defaultConfigurations= 263 findApplicableElements(myTarget, ConfigTestElement.class, false); 264 Collection userDefinedVariables = 265 findApplicableElements(myTarget, Arguments.class, true); 266 267 removeValuesFromSampler(sampler, defaultConfigurations); 268 replaceValues(sampler, subConfigs, userDefinedVariables); 269 sampler.setUseKeepAlive(useKeepAlive); 270 sampler.setProperty( 271 TestElement.GUI_CLASS, 272 "org.apache.jmeter.protocol.http.control.gui.HttpTestSampleGui"); 273 274 placeSampler(sampler, subConfigs, myTarget); 275 276 notifySampleListeners(new SampleEvent(result,sampler.getName())); 277 } 278 } 279 280 public void stopProxy() 281 { 282 if (server != null) 283 { 284 server.stopServer(); 285 try 286 { 287 server.join(1000); } 289 catch (InterruptedException e) 290 { 291 } 292 notifyTestListenersOfEnd(); 293 server = null; 294 } 295 } 296 297 private boolean filterUrl(HTTPSampler sampler) 298 { 299 String domain = sampler.getDomain(); 300 if (domain == null || domain.length() == 0) 301 { 302 return false; 303 } 304 305 String url = generateMatchUrl(sampler); 306 CollectionProperty includePatterns = getIncludePatterns(); 307 if (includePatterns.size() > 0) 308 { 309 if (!matchesPatterns(url, includePatterns)) 310 { 311 return false; 312 } 313 } 314 315 CollectionProperty excludePatterns = getExcludePatterns(); 316 if (excludePatterns.size() > 0) 317 { 318 if (matchesPatterns(url, excludePatterns)) 319 { 320 return false; 321 } 322 } 323 324 return true; 325 } 326 327 330 private void addAssertion(JMeterTreeModel model,JMeterTreeNode node) 331 throws IllegalUserActionException 332 { 333 ResponseAssertion ra = new ResponseAssertion(); 334 ra.setProperty(TestElement.GUI_CLASS, 335 "org.apache.jmeter.assertions.gui.AssertionGui"); 336 ra.setName("Check response"); 337 ra.setTestField(ResponseAssertion.RESPONSE_DATA); 338 model.addComponent(ra,node); 339 } 340 341 344 private void addDivider(JMeterTreeModel model,JMeterTreeNode node) 345 throws IllegalUserActionException 346 { 347 GenericController sc = new GenericController(); 348 sc.setProperty(TestElement.GUI_CLASS, 349 "org.apache.jmeter.control.gui.LogicControllerGui"); 350 sc.setName("-------------------"); 351 model.addComponent(sc,node); 352 } 353 354 361 private void addSimpleController( 362 JMeterTreeModel model, 363 JMeterTreeNode node, 364 String name) 365 throws IllegalUserActionException 366 { 367 GenericController sc = new GenericController(); 368 sc.setProperty(TestElement.GUI_CLASS, 369 "org.apache.jmeter.control.gui.LogicControllerGui"); 370 sc.setName(name); 371 model.addComponent(sc,node); 372 } 373 374 383 private void addTimers( 384 JMeterTreeModel model, 385 JMeterTreeNode node, 386 long deltaT) 387 { 388 TestPlan variables= new TestPlan(); 389 variables.addParameter("T", Long.toString(deltaT)); 390 ValueReplacer replacer= new ValueReplacer(variables); 391 JMeterTreeNode mySelf= model.getNodeOf(this); 392 Enumeration children= mySelf.children(); 393 while (children.hasMoreElements()) 394 { 395 JMeterTreeNode templateNode= (JMeterTreeNode)children.nextElement(); 396 if (templateNode.isEnabled()) 397 { 398 TestElement template= templateNode.getTestElement(); 399 if (template instanceof Timer) 400 { 401 TestElement timer= (TestElement)template.clone(); 402 try 403 { 404 replacer.undoReverseReplace(timer); 405 model.addComponent(timer, node); 406 } 407 catch (InvalidVariableException e) 408 { 409 log.error("Program error",e); 412 throw new Error(e.toString()); } catch (IllegalUserActionException e) 414 { 415 log.error("Program error",e); 418 throw new Error(e.toString()); } 420 } 421 } 422 } 423 } 424 425 433 private JMeterTreeNode findFirstNodeOfType(Class type) 434 { 435 JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel(); 436 List nodes = treeModel.getNodesOfType(type); 437 Iterator iter= nodes.iterator(); 438 while (iter.hasNext()) { 439 JMeterTreeNode node= (JMeterTreeNode) iter.next(); 440 if (node.isEnabled()) { 441 return node; 442 } 443 } 444 return null; 445 } 446 447 459 private JMeterTreeNode findTargetControllerNode() 460 { 461 JMeterTreeNode myTarget= getTarget(); 462 if (myTarget != null) return myTarget; 463 myTarget= findFirstNodeOfType(RecordingController.class); 464 if (myTarget != null) return myTarget; 465 myTarget= findFirstNodeOfType(ThreadGroup.class); 466 if (myTarget != null) return myTarget; 467 myTarget= findFirstNodeOfType(WorkBench.class); 468 if (myTarget != null) return myTarget; 469 log.error("Program error: proxy recording target not found."); 470 return null; 471 } 472 473 491 private Collection findApplicableElements( 492 JMeterTreeNode myTarget, 493 Class myClass, 494 boolean ascending) 495 { 496 JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel(); 497 LinkedList elements= new LinkedList(); 498 499 Enumeration enum = treeModel.getNodeOf(this).children(); 501 while (enum.hasMoreElements()) 502 { 503 JMeterTreeNode subNode = 504 (JMeterTreeNode) enum.nextElement(); 505 if (subNode.isEnabled()) 506 { 507 TestElement element= (TestElement)subNode.getUserObject(); 508 if(myClass.isInstance(element)) 509 { 510 if (ascending) elements.addFirst(element); 511 else elements.add(element); 512 } 513 } 514 } 515 516 for (JMeterTreeNode controller= myTarget; 518 controller != null; 519 controller= (JMeterTreeNode)controller.getParent()) 520 { 521 enum = controller.children(); 522 while (enum.hasMoreElements()) 523 { 524 JMeterTreeNode subNode = 525 (JMeterTreeNode) enum.nextElement(); 526 if (subNode.isEnabled()) 527 { 528 TestElement element= (TestElement)subNode.getUserObject(); 529 if (myClass.isInstance(element)) 530 { 531 log.debug("Applicable: "+element.getPropertyAsString(TestElement.NAME)); 532 if (ascending) elements.addFirst(element); 533 else elements.add(element); 534 } 535 536 if (element instanceof TestPlan) 538 { 539 Arguments args= (Arguments) 540 element.getProperty(TestPlan.USER_DEFINED_VARIABLES).getObjectValue(); 541 if (myClass.isInstance(args)) 542 { 543 if (ascending) elements.addFirst(args); 544 else elements.add(args); 545 } 546 } 547 } 548 } 549 } 550 551 return elements; 552 } 553 554 private void placeSampler( 555 HTTPSampler sampler, 556 TestElement[] subConfigs, 557 JMeterTreeNode myTarget) 558 { 559 try 560 { 561 JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel(); 562 563 boolean firstInBatch=false; 564 long now = System.currentTimeMillis(); 565 long deltaT= now - lastTime; 566 if (deltaT > sampleGap){ 567 if (!myTarget.isLeaf() 568 && groupingMode == GROUPING_ADD_SEPARATORS) 569 { 570 addDivider(treeModel, myTarget); 571 } 572 if (groupingMode == GROUPING_IN_CONTROLLERS) 573 { 574 addSimpleController(treeModel, myTarget, sampler.getName()); 575 } 576 firstInBatch=true; } 578 if (lastTime == 0) deltaT= 0; lastTime = now; 580 581 if (groupingMode == GROUPING_STORE_FIRST_ONLY) 582 { 583 if (!firstInBatch) return; 585 sampler.setFollowRedirects(true); 588 sampler.setImageParser(true); 589 } 590 591 if (groupingMode == GROUPING_IN_CONTROLLERS) 592 { 593 for (int i= myTarget.getChildCount()-1; i>=0; i--) 596 { 597 JMeterTreeNode c= (JMeterTreeNode)myTarget.getChildAt(i); 598 if (c.getTestElement() instanceof GenericController) 599 { 600 myTarget= c; 601 break; 602 } 603 } 604 } 605 606 JMeterTreeNode newNode = 607 treeModel.addComponent(sampler, myTarget); 608 609 if(firstInBatch){ 610 if (addAssertions){ 611 addAssertion(treeModel,newNode); 612 } 613 addTimers(treeModel, newNode, deltaT); 614 firstInBatch=false; 615 } 616 617 for (int i = 0; 618 subConfigs != null && i < subConfigs.length; 619 i++) 620 { 621 if (subConfigs[i] instanceof HeaderManager) 622 { 623 subConfigs[i].setProperty( 624 TestElement.GUI_CLASS, 625 "org.apache.jmeter.protocol.http.gui.HeaderPanel"); 626 treeModel.addComponent(subConfigs[i], newNode); 627 } 628 } 629 } 630 catch (IllegalUserActionException e) 631 { 632 JMeterUtils.reportErrorToUser(e.getMessage()); 633 } 634 } 635 636 644 private void removeValuesFromSampler( 645 HTTPSampler sampler, 646 Collection configurations) 647 { 648 for (PropertyIterator props= sampler.propertyIterator(); 649 props.hasNext(); 650 ) 651 { 652 JMeterProperty prop= props.next(); 653 String name= prop.getName(); 654 String value= prop.getStringValue(); 655 656 if (name.equals(TestElement.ENABLED) 658 || name.equals(TestElement.GUI_CLASS) 659 || name.equals(TestElement.NAME) 660 || name.equals(TestElement.TEST_CLASS)) 661 { 662 continue; } 664 665 for (Iterator configs= configurations.iterator(); 666 configs.hasNext(); 667 ) 668 { 669 ConfigTestElement config= (ConfigTestElement)configs.next(); 670 671 String configValue= config.getPropertyAsString(name); 672 673 if (configValue != null && configValue.length() > 0) 674 { 675 if (configValue.equals(value)) sampler.setProperty(name, ""); 676 break; 680 } 681 } 682 } 683 } 684 685 private String generateMatchUrl(HTTPSampler sampler) 686 { 687 StringBuffer buf = new StringBuffer(sampler.getDomain()); 688 buf.append(':'); 689 buf.append(sampler.getPort()); 690 buf.append(sampler.getPath()); 691 if (sampler.getQueryString().length() > 0) 692 { 693 buf.append('?'); 694 buf.append(sampler.getQueryString()); 695 } 696 return buf.toString(); 697 } 698 699 private boolean matchesPatterns(String url, CollectionProperty patterns) 700 { 701 PropertyIterator iter = patterns.iterator(); 702 while (iter.hasNext()) 703 { 704 String item = iter.next().getStringValue(); 705 Pattern pattern = null; 706 try 707 { 708 pattern = 709 patternCache.getPattern( 710 item, 711 Perl5Compiler.READ_ONLY_MASK 712 | Perl5Compiler.SINGLELINE_MASK); 713 if (matcher.matches(url, pattern)) 714 { 715 return true; 716 } 717 } 718 catch (MalformedCachePatternException e) 719 { 720 log.warn("Skipped invalid pattern: " + item, e); 721 } 722 } 723 return false; 724 } 725 726 736 private void replaceValues( 737 TestElement sampler, 738 TestElement[] configs, 739 Collection variables) 740 { 741 ValueReplacer replacer= new ValueReplacer(); 743 for (Iterator vars= variables.iterator(); vars.hasNext(); ) 744 { 745 replacer.addVariables(((Arguments)vars.next()).getArgumentsAsMap()); 746 } 747 748 try 749 { 750 replacer.reverseReplace(sampler); 751 for (int i = 0; i < configs.length; i++) 752 { 753 if (configs[i] != null) 754 { 755 replacer.reverseReplace(configs[i]); 756 } 757 758 } 759 } 760 catch (InvalidVariableException e) 761 { 762 log.warn( 763 "Invalid variables included for replacement into recorded " 764 + "sample", 765 e); 766 } 767 } 768 769 776 private void notifySampleListeners(SampleEvent event) 777 { 778 JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel(); 779 JMeterTreeNode myNode = treeModel.getNodeOf(this); 780 Enumeration enum = myNode.children(); 781 while (enum.hasMoreElements()) 782 { 783 JMeterTreeNode subNode = 784 (JMeterTreeNode) enum.nextElement(); 785 if (subNode.isEnabled()) { 786 TestElement testElement = 787 (TestElement) subNode.getTestElement(); 788 if (testElement instanceof SampleListener) { 789 ((SampleListener)testElement).sampleOccurred(event); 790 } 791 } 792 } 793 } 794 795 799 private void notifyTestListenersOfStart() 800 { 801 JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel(); 802 JMeterTreeNode myNode = treeModel.getNodeOf(this); 803 Enumeration enum = myNode.children(); 804 while (enum.hasMoreElements()) 805 { 806 JMeterTreeNode subNode = 807 (JMeterTreeNode) enum.nextElement(); 808 if (subNode.isEnabled()) { 809 TestElement testElement = 810 (TestElement) subNode.getTestElement(); 811 if (testElement instanceof TestListener) { 812 ((TestListener)testElement).testStarted(); 813 } 814 } 815 } 816 } 817 818 822 private void notifyTestListenersOfEnd() 823 { 824 JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel(); 825 JMeterTreeNode myNode = treeModel.getNodeOf(this); 826 Enumeration enum = myNode.children(); 827 while (enum.hasMoreElements()) 828 { 829 JMeterTreeNode subNode = 830 (JMeterTreeNode) enum.nextElement(); 831 if (subNode.isEnabled()) { 832 TestElement testElement = 833 (TestElement) subNode.getTestElement(); 834 if (testElement instanceof TestListener) { 835 ((TestListener)testElement).testEnded(); 836 } 837 } 838 } 839 } 840 841 public boolean canRemove(){ 842 return null==server; 843 } 844 public static class Test extends TestCase 845 { 846 HTTPSampler sampler; 847 ProxyControl control; 848 849 public Test(String name) 850 { 851 super(name); 852 } 853 public void setUp(){ 854 control = new ProxyControl(); 855 control.addIncludedPattern(".*\\.jsp"); 856 control.addExcludedPattern(".*apache.org.*"); 857 sampler = new HTTPSampler(); 858 } 859 public void testFilter1() throws Exception 860 { 861 sampler.setDomain("jakarta.org"); 862 sampler.setPath("index.jsp"); 863 assertTrue("Should find jakarta.org/index.jsp",control.filterUrl(sampler)); 864 } 865 public void testFilter2() throws Exception 866 { 867 sampler.setPath("index.jsp"); 868 sampler.setDomain("www.apache.org"); 869 assertFalse("Should not match www.apache.org",control.filterUrl(sampler)); 870 } 871 872 public void testFilter3() throws Exception 873 { 874 sampler.setPath("header.gif"); 875 sampler.setDomain("jakarta.org"); 876 assertFalse("Should not match header.gif",control.filterUrl(sampler)); 877 } 878 } 879 } 880
| Popular Tags
|