| 1 38 package com.gargoylesoftware.htmlunit; 39 40 import java.io.BufferedInputStream ; 41 import java.io.ByteArrayOutputStream ; 42 import java.io.File ; 43 import java.io.FileInputStream ; 44 import java.io.IOException ; 45 import java.io.InputStream ; 46 import java.io.OutputStreamWriter ; 47 import java.lang.reflect.Constructor ; 48 import java.net.MalformedURLException ; 49 import java.net.URL ; 50 import java.net.URLConnection ; 51 import java.net.URLStreamHandler ; 52 import java.util.ArrayList ; 53 import java.util.BitSet ; 54 import java.util.Collections ; 55 import java.util.HashMap ; 56 import java.util.HashSet ; 57 import java.util.Iterator ; 58 import java.util.List ; 59 import java.util.Map ; 60 import java.util.Set ; 61 import java.util.Stack ; 62 import java.util.StringTokenizer ; 63 64 import org.org.apache.commons.httpclient.URI; 65 import org.org.apache.commons.httpclient.URIException; 66 import org.org.apache.commons.httpclient.auth.CredentialsProvider; 67 import org.org.apache.commons.httpclient.util.URIUtil; 68 import org.apache.commons.io.FileUtils; 69 import org.apache.commons.io.IOUtils; 70 import org.apache.commons.logging.Log; 71 import org.apache.commons.logging.LogFactory; 72 73 import com.gargoylesoftware.htmlunit.html.BaseFrame; 74 import com.gargoylesoftware.htmlunit.html.FocusableElement; 75 import com.gargoylesoftware.htmlunit.html.HTMLParser; 76 import com.gargoylesoftware.htmlunit.html.HTMLParserListener; 77 import com.gargoylesoftware.htmlunit.html.HtmlPage; 78 import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine; 79 80 98 public class WebClient { 99 100 private WebConnection webConnection_; 101 private boolean printContentOnFailingStatusCode_ = true; 102 private boolean throwExceptionOnFailingStatusCode_ = true; 103 private CredentialsProvider credentialsProvider_ = new DefaultCredentialsProvider(); 104 private final String proxyHost_; 105 private final int proxyPort_; 106 private ScriptEngine scriptEngine_; 107 private boolean javaScriptEnabled_ = true; 108 private String homePage_; 109 private FocusableElement elementWithFocus_; 110 private final Map requestHeaders_ = Collections.synchronizedMap(new HashMap (89)); 111 112 private AlertHandler alertHandler_; 113 private ConfirmHandler confirmHandler_; 114 private PromptHandler promptHandler_; 115 private StatusHandler statusHandler_; 116 117 private BrowserVersion browserVersion_ = BrowserVersion.getDefault(); 118 private boolean isRedirectEnabled_ = true; 119 private PageCreator pageCreator_ = new DefaultPageCreator(); 120 121 private final Set webWindowListeners_ = new HashSet (5); 122 private final List webWindows_ = Collections.synchronizedList(new ArrayList ()); 123 124 private WebWindow currentWindow_ = new TopLevelWindow("", this); 125 private Stack firstWindowStack_ = new Stack (); 126 private int timeout_ = 0; 127 private HTMLParserListener htmlParserListener_; 128 129 private static URLStreamHandler JavaScriptUrlStreamHandler_ 130 = new com.gargoylesoftware.htmlunit.protocol.javascript.Handler(); 131 private static URLStreamHandler AboutUrlStreamHandler_ 132 = new com.gargoylesoftware.htmlunit.protocol.about.Handler(); 133 134 137 public static final URL URL_ABOUT_BLANK; 138 static { 139 URL tmpUrl = null; 140 try { 141 tmpUrl = new URL (null, "about:blank", AboutUrlStreamHandler_); 142 } 143 catch (final MalformedURLException e) { 144 e.printStackTrace(); 146 } 147 URL_ABOUT_BLANK = tmpUrl; 148 } 149 150 private static final WebResponse WEB_RESPONSE_FOR_ABOUT_BLANK = new WebResponse() { 152 public int getStatusCode() { 153 return 200; 154 } 155 public String getStatusMessage() { 156 return "OK"; 157 } 158 public String getContentType() { 159 return "text/html"; 160 } 161 public String getContentAsString() { 162 return ""; 163 } 164 public InputStream getContentAsStream() { 165 return TextUtil.toInputStream(""); 166 } 167 public URL getUrl() { 168 return URL_ABOUT_BLANK; 169 } 170 public List getResponseHeaders() { 171 return Collections.EMPTY_LIST; 172 } 173 public String getResponseHeaderValue(final String key) { 174 return ""; 175 } 176 public long getLoadTimeInMilliSeconds() { 177 return 0; 178 } 179 public byte[] getResponseBody() { 180 return "".getBytes(); 181 } 182 public String getContentCharSet() { 183 return "ISO-8859-1"; 184 } 185 }; 186 187 private ScriptPreProcessor scriptPreProcessor_; 188 private Map activeXObjectMap_ = Collections.EMPTY_MAP; 189 private RefreshHandler refreshHandler_ = new ImmediateRefreshHandler(); 190 private boolean throwExceptionOnScriptError_ = true; 191 192 193 196 public WebClient() { 197 this( BrowserVersion.FULL_FEATURED_BROWSER ); 198 } 199 200 201 205 public WebClient( final BrowserVersion browserVersion ) { 206 Assert.notNull("browserVersion", browserVersion); 207 208 homePage_ = "http://www.gargoylesoftware.com/"; 209 browserVersion_ = browserVersion; 210 proxyHost_ = null; 211 proxyPort_ = 0; 212 try { 213 scriptEngine_ = createJavaScriptEngineIfPossible( this ); 214 } 215 catch( final NoClassDefFoundError e ) { 216 scriptEngine_ = null; 217 } 218 } 219 220 221 227 public WebClient( final BrowserVersion browserVersion, final String proxyHost, final int proxyPort ) { 228 Assert.notNull("browserVersion", browserVersion); 229 Assert.notNull( "proxyHost", proxyHost ); 230 231 homePage_ = "http://www.gargoylesoftware.com/"; 232 browserVersion_ = browserVersion; 233 proxyHost_ = proxyHost; 234 proxyPort_ = proxyPort; 235 try { 236 scriptEngine_ = createJavaScriptEngineIfPossible( this ); 237 } 238 catch( final NoClassDefFoundError e ) { 239 scriptEngine_ = null; 240 } 241 } 242 243 244 250 public static JavaScriptEngine createJavaScriptEngineIfPossible( final WebClient webClient ) { 251 try { 252 Class.forName( "org.mozilla.javascript.Context" ); 253 return new JavaScriptEngine( webClient ); 254 } 255 catch( final ClassNotFoundException e ) { 256 return null; 257 } 258 catch( final NoClassDefFoundError e ) { 259 return null; 260 } 261 } 262 263 264 269 public synchronized WebConnection getWebConnection() { 270 if( webConnection_ == null ) { 271 if( proxyHost_ == null ) { 272 webConnection_ = new HttpWebConnection( this ); 273 } 274 else { 275 webConnection_ = new HttpWebConnection( this, proxyHost_, proxyPort_ ); 276 } 277 } 278 279 return webConnection_; 280 } 281 282 283 291 public void setWebConnection( final WebConnection webConnection ) { 292 Assert.notNull( "webConnection", webConnection ); 293 webConnection_ = webConnection; 294 } 295 296 342 public Page getPage( final WebWindow webWindow, final WebRequestSettings parameters ) 343 throws IOException , FailingHttpStatusCodeException { 344 345 getLog().debug("Get page for window named '" + webWindow.getName() + "', using " + parameters); 346 347 final String protocol = parameters.getURL().getProtocol(); 348 final WebResponse webResponse; 349 if( protocol.equals("javascript") ) { 350 webResponse = makeWebResponseForJavaScriptUrl(webWindow, parameters.getURL()); 351 } 352 else if (protocol.equals("about")) { 353 webResponse = makeWebResponseForAboutUrl(parameters.getURL()); 354 } 355 else if (protocol.equals("file")) { 356 webResponse = makeWebResponseForFileUrl(parameters.getURL()); 357 } 358 else { 359 webResponse = loadWebResponse( 360 parameters.getURL(), 361 parameters.getEncodingType(), 362 parameters.getSubmitMethod(), 363 parameters.getRequestParameters()); 364 } 365 final String contentType = webResponse.getContentType(); 366 final int statusCode = webResponse.getStatusCode(); 367 368 final boolean wasResponseSuccessful = ( statusCode >= 200 && statusCode < 300 ); 369 370 if( printContentOnFailingStatusCode_ && !wasResponseSuccessful) { 371 getLog().info( "statusCode=[" + statusCode 372 + "] contentType=[" + contentType + "]" ); 373 getLog().info( webResponse.getContentAsString() ); 374 } 375 376 loadWebResponseInto(webResponse, webWindow); 377 378 if( getThrowExceptionOnFailingStatusCode() && !wasResponseSuccessful) { 379 throw new FailingHttpStatusCodeException( statusCode, webResponse.getStatusMessage() ); 380 } 381 382 return webWindow.getEnclosedPage(); 383 } 384 385 400 public Page getPage(final WebWindow opener, final String target, final WebRequestSettings params) 401 throws FailingHttpStatusCodeException, IOException { 402 return getPage(openTargetWindow(opener, target, "_self"), params); 403 } 404 405 414 public Page getPage(final URL url) throws IOException , FailingHttpStatusCodeException { 415 return getPage(getCurrentWindow(), new WebRequestSettings(url)); 416 } 417 418 428 public Page getPage(final WebRequestSettings request) throws IOException , 429 FailingHttpStatusCodeException { 430 return getPage(getCurrentWindow(), request); 431 } 432 433 434 451 public Page getPage( 452 final URL url, 453 final SubmitMethod method, 454 final List parameters ) 455 throws 456 IOException , 457 FailingHttpStatusCodeException { 458 459 return getPage( getCurrentWindow(), url, method, parameters ); 460 } 461 462 463 480 public Page getPage( 481 final WebWindow webWindow, 482 final URL url, 483 final SubmitMethod method, 484 final List parameters ) 485 throws 486 IOException , 487 FailingHttpStatusCodeException { 488 final WebRequestSettings settings = new WebRequestSettings(url, method); 489 settings.setRequestParameters(parameters); 490 return getPage(webWindow, settings); 491 } 492 493 494 514 public Page getPage( 515 final WebWindow webWindow, 516 final URL url, 517 final String target, 518 final SubmitMethod method, 519 final List parameters ) 520 throws 521 IOException , 522 FailingHttpStatusCodeException { 523 return getPage(openTargetWindow( webWindow, target, "_self" ), url, 524 method, parameters, getThrowExceptionOnFailingStatusCode()); 525 } 526 527 528 546 public Page getPage( 547 final WebWindow webWindow, 548 final URL url, 549 final FormEncodingType encType, 550 final SubmitMethod method, 551 final List parameters ) 552 throws 553 IOException , 554 FailingHttpStatusCodeException { 555 return getPage(webWindow, url, encType, method, parameters, getThrowExceptionOnFailingStatusCode()); 556 } 557 558 559 578 public Page getPage( 579 final WebWindow webWindow, 580 final URL url, 581 final String target, 582 final FormEncodingType encType, 583 final SubmitMethod method, 584 final List parameters ) 585 throws 586 IOException , 587 FailingHttpStatusCodeException { 588 return getPage(openTargetWindow( webWindow, target, "_self" ), 589 url, encType, method, parameters, 590 getThrowExceptionOnFailingStatusCode()); 591 } 592 593 594 614 public Page getPage( 615 final WebWindow webWindow, 616 final URL url, 617 final SubmitMethod method, 618 final List parameters, 619 final boolean throwExceptionOnFailingStatusCode ) 620 throws 621 IOException , 622 FailingHttpStatusCodeException { 623 final WebRequestSettings settings = new WebRequestSettings(url); 624 settings.setSubmitMethod(method); 625 settings.setRequestParameters(parameters); 626 try { 627 return getPage(webWindow, settings); 628 } 629 catch (final FailingHttpStatusCodeException e) { 630 if (throwExceptionOnFailingStatusCode) { 631 throw e; 632 } 633 else { 634 return webWindow.getEnclosedPage(); 635 } 636 } 637 } 638 639 658 public Page getPage( 659 final WebWindow webWindow, 660 final URL url, 661 final FormEncodingType encType, 662 final SubmitMethod method, 663 final List parameters, 664 final boolean throwExceptionOnFailingStatusCode ) 665 throws 666 IOException , 667 FailingHttpStatusCodeException { 668 final WebRequestSettings params = new WebRequestSettings(url, method); 669 params.setEncodingType(encType); 670 params.setRequestParameters(parameters); 671 672 try { 673 return getPage(webWindow, params); 674 } 675 catch (final FailingHttpStatusCodeException e){ 676 if (throwExceptionOnFailingStatusCode){ 677 throw e; 678 } 679 else { 680 return webWindow.getEnclosedPage(); 681 } 682 } 683 } 684 685 695 public Page loadWebResponseInto( 696 final WebResponse webResponse, final WebWindow webWindow ) 697 throws 698 IOException { 699 700 Assert.notNull("webResponse", webResponse); 701 Assert.notNull("webWindow", webWindow); 702 703 final Page oldPage = webWindow.getEnclosedPage(); 704 if (oldPage != null) { 705 oldPage.cleanUp(); 707 } 708 709 final Page newPage = pageCreator_.createPage( webResponse, webWindow ); 710 711 if (! firstWindowStack_.empty() && firstWindowStack_.peek() == null) { 712 firstWindowStack_.pop(); 713 firstWindowStack_.push(webWindow); 714 } 715 716 newPage.initialize(); 717 718 fireWindowContentChanged( new WebWindowEvent(webWindow, WebWindowEvent.CHANGE, oldPage, newPage) ); 719 return newPage; 720 } 721 722 723 730 public void setPrintContentOnFailingStatusCode( final boolean enabled ) { 731 printContentOnFailingStatusCode_ = enabled; 732 } 733 734 735 742 public boolean getPrintContentOnFailingStatusCode() { 743 return printContentOnFailingStatusCode_; 744 } 745 746 747 754 public void setThrowExceptionOnFailingStatusCode( final boolean enabled ) { 755 throwExceptionOnFailingStatusCode_ = enabled; 756 } 757 758 759 766 public boolean getThrowExceptionOnFailingStatusCode() { 767 return throwExceptionOnFailingStatusCode_; 768 } 769 770 771 777 public void addRequestHeader( final String name, final String value ) { 778 requestHeaders_.put( name, value ); 779 } 780 781 782 788 public void removeRequestHeader( final String name ) { 789 requestHeaders_.remove( name ); 790 } 791 792 793 800 public void setCredentialsProvider( final CredentialsProvider credentialsProvider ) { 801 Assert.notNull( "credentialsProvider", credentialsProvider ); 802 credentialsProvider_ = credentialsProvider; 803 } 804 805 806 811 public CredentialsProvider getCredentialsProvider() { 812 return credentialsProvider_; 813 } 814 815 816 827 public void assertionFailed( final String message ) { 828 try { 829 final Class clazz = junit.framework.AssertionFailedError.class; 830 final Constructor constructor = clazz.getConstructor( new Class []{String .class} ); 831 final Error error = ( Error )constructor.newInstance( new Object []{message} ); 832 throw error; 833 } 834 catch( final Exception e ) { 835 throw new IllegalStateException ( message ); 836 } 837 <
|