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 } 838 839 840 845 public ScriptEngine getScriptEngine() { 846 if( javaScriptEnabled_ == true ) { 847 return scriptEngine_; 848 } 849 else { 850 return null; 851 } 852 } 853 854 855 860 public void setScriptEngine( final ScriptEngine engine ) { 861 scriptEngine_ = engine; 862 } 863 864 865 870 public void setJavaScriptEnabled( final boolean isEnabled ) { 871 javaScriptEnabled_ = isEnabled; 872 } 873 874 875 880 public boolean isJavaScriptEnabled() { 881 return javaScriptEnabled_ && scriptEngine_ != null; 882 } 883 884 885 889 public String getHomePage() { 890 return homePage_; 891 } 892 893 894 898 public void setHomePage(String homePage) { 899 homePage_ = homePage; 900 } 901 902 903 907 public void setAlertHandler( final AlertHandler alertHandler ) { 908 alertHandler_ = alertHandler; 909 } 910 911 912 916 public AlertHandler getAlertHandler() { 917 return alertHandler_; 918 } 919 920 921 925 public void setConfirmHandler( final ConfirmHandler handler ) { 926 confirmHandler_ = handler; 927 } 928 929 930 934 public ConfirmHandler getConfirmHandler() { 935 return confirmHandler_; 936 } 937 938 939 943 public void setPromptHandler( final PromptHandler handler ) { 944 promptHandler_ = handler; 945 } 946 947 948 952 public PromptHandler getPromptHandler() { 953 return promptHandler_; 954 } 955 956 957 961 public void setStatusHandler( final StatusHandler statusHandler ) { 962 statusHandler_ = statusHandler; 963 } 964 965 966 970 public StatusHandler getStatusHandler() { 971 return statusHandler_; 972 } 973 974 978 public BrowserVersion getBrowserVersion() { 979 return browserVersion_; 980 } 981 982 983 988 public WebWindow getCurrentWindow() { 989 return currentWindow_; 990 } 991 992 993 998 public void setCurrentWindow( final WebWindow window ) { 999 Assert.notNull("window", window); 1000 currentWindow_ = window; 1001 } 1002 1003 1004 1009 public WebWindow popFirstWindow() { 1010 return (WebWindow)firstWindowStack_.pop(); 1011 } 1012 1013 1014 1017 public void pushClearFirstWindow() { 1018 firstWindowStack_.push(null); 1019 } 1020 1021 1022 1027 public void addWebWindowListener( final WebWindowListener listener ) { 1028 Assert.notNull("listener", listener); 1029 webWindowListeners_.add(listener); 1030 } 1031 1032 1033 1037 public void removeWebWindowListener( final WebWindowListener listener ) { 1038 Assert.notNull("listener", listener); 1039 webWindowListeners_.remove(listener); 1040 } 1041 1042 1043 private void fireWindowContentChanged( final WebWindowEvent event ) { 1044 final Iterator iterator = new ArrayList (webWindowListeners_).iterator(); 1045 while( iterator.hasNext() ) { 1046 final WebWindowListener listener = (WebWindowListener)iterator.next(); 1047 listener.webWindowContentChanged(event); 1048 } 1049 } 1050 1051 1052 private void fireWindowOpened( final WebWindowEvent event ) { 1053 final Iterator iterator = new ArrayList (webWindowListeners_).iterator(); 1054 while( iterator.hasNext() ) { 1055 final WebWindowListener listener = (WebWindowListener)iterator.next(); 1056 listener.webWindowOpened(event); 1057 } 1058 } 1059 1060 1061 private void fireWindowClosed( final WebWindowEvent event ) { 1062 final Iterator iterator = new ArrayList (webWindowListeners_).iterator(); 1063 while( iterator.hasNext() ) { 1064 final WebWindowListener listener = (WebWindowListener)iterator.next(); 1065 listener.webWindowClosed(event); 1066 } 1067 } 1068 1069 1077 public WebWindow openWindow( final URL url, final String windowName ) { 1078 Assert.notNull("windowName", windowName); 1079 return openWindow( url, windowName, getCurrentWindow() ); 1080 } 1081 1082 1083 1092 public WebWindow openWindow( final URL url, final String windowName, final WebWindow opener ) { 1093 final WebWindow window = openTargetWindow( opener, windowName, "_blank" ); 1094 if( url != null ) { 1095 try { 1096 getPage(window, url, SubmitMethod.GET, Collections.EMPTY_LIST); 1097 } 1098 catch( final IOException e ) { 1099 getLog().error("Error when loading content into window", e); 1100 } 1101 } 1102 return window; 1103 } 1104 1105 1106 1117 private WebWindow openTargetWindow( 1118 final WebWindow opener, final String windowName, final String defaultName) { 1119 1120 Assert.notNull("opener", opener); 1121 Assert.notNull("defaultName", defaultName); 1122 1123 String windowToOpen = windowName; 1124 if( windowToOpen == null || windowToOpen.length() == 0 ) { 1125 windowToOpen = defaultName; 1126 } 1127 1128 WebWindow webWindow = null; 1129 if( windowToOpen.equals("_self") ) { 1130 webWindow = opener; 1131 windowToOpen = ""; 1132 } 1133 else if( windowToOpen.equals("_parent") ) { 1134 webWindow = opener.getParentWindow(); 1135 windowToOpen = ""; 1136 } 1137 else if( windowToOpen.equals("_top") ) { 1138 webWindow = opener.getTopWindow(); 1139 windowToOpen = ""; 1140 } 1141 else if( windowToOpen.equals("_blank") ) { 1142 windowToOpen = ""; 1144 } 1145 else if( windowToOpen.length() != 0 ) { 1146 try { 1147 webWindow = getWebWindowByName(windowToOpen); 1148 } 1149 catch( final WebWindowNotFoundException e ) { 1150 } 1152 } 1153 1154 if( webWindow == null ) { 1155 webWindow = new TopLevelWindow(windowToOpen, this); 1156 fireWindowOpened( new WebWindowEvent(webWindow, WebWindowEvent.OPEN, null, null) ); 1157 } 1158 1159 if( webWindow instanceof TopLevelWindow && webWindow != opener.getTopWindow() ) { 1160 ((TopLevelWindow)webWindow).setOpener(opener); 1161 } 1162 1163 return webWindow; 1164 } 1165 1166 1167 1172 public void setRedirectEnabled( final boolean enabled ) { 1173 isRedirectEnabled_ = enabled; 1174 } 1175 1176 1177 1182 public boolean isRedirectEnabled() { 1183 return isRedirectEnabled_; 1184 } 1185 1186 1187 1193 public void setPageCreator( final PageCreator pageCreator ) { 1194 Assert.notNull("pageCreator", pageCreator); 1195 pageCreator_ = pageCreator; 1196 } 1197 1198 1199 1204 public PageCreator getPageCreator() { 1205 return pageCreator_; 1206 } 1207 1208 1209 1216 public WebWindow getWebWindowByName( final String name ) throws WebWindowNotFoundException { 1217 Assert.notNull("name", name); 1218 1219 final Iterator iterator = webWindows_.iterator(); 1220 while( iterator.hasNext() ) { 1221 final WebWindow webWindow = (WebWindow)iterator.next(); 1222 if( webWindow.getName().equals(name) ) { 1223 return webWindow; 1224 } 1225 } 1226 1227 throw new WebWindowNotFoundException(name); 1228 } 1229 1230 1231 1236 public void registerWebWindow( final WebWindow webWindow ) { 1237 Assert.notNull("webWindow", webWindow); 1238 webWindows_.add(webWindow); 1239 } 1240 1241 1242 1247 public void deregisterWebWindow( final WebWindow webWindow ) { 1248 Assert.notNull("webWindow", webWindow); 1249 webWindows_.remove(webWindow); 1250 1251 if( currentWindow_ == webWindow ) { 1252 if( webWindows_.size() == 0 ) { 1253 currentWindow_ = new TopLevelWindow("", this); 1255 } 1256 else { 1257 currentWindow_ = (WebWindow)webWindows_.get(0); 1258 } 1259 } 1260 fireWindowClosed(new WebWindowEvent(webWindow, WebWindowEvent.CLOSE, webWindow.getEnclosedPage(), null)); 1261 } 1262 1263 1264 1268 protected final Log getLog() { 1269 return LogFactory.getLog(getClass()); 1270 } 1271 1272 1273 private static URL makeUrl( final String urlString ) throws MalformedURLException { 1274 Assert.notNull("urlString", urlString); 1275 1276 if( TextUtil.startsWithIgnoreCase(urlString, "javascript:") ) { 1277 return new URL (null, urlString, JavaScriptUrlStreamHandler_); 1278 } 1279 else if (TextUtil.startsWithIgnoreCase(urlString,"about:")){ 1280 return new URL (null, urlString, AboutUrlStreamHandler_); 1281 } 1282 else { 1283 return new URL (urlString); 1284 } 1285 } 1286 1287 1288 1301 public static URL expandUrl( final URL baseUrl, final String relativeUrl ) 1302 throws MalformedURLException { 1303 1304 String parseUrl = relativeUrl; 1305 if (parseUrl == null) { 1306 parseUrl = ""; 1307 } 1308 1309 final int schemeIndex = parseUrl.indexOf(":"); 1311 if( schemeIndex != -1 ) { 1312 boolean isProtocolSpecified = true; 1313 for( int i=0; i<schemeIndex; i++ ) { 1314 if( Character.isLetter(parseUrl.charAt(i)) == false ) { 1315 isProtocolSpecified = false; 1316 break; 1317 } 1318 } 1319 if( isProtocolSpecified == true ) { 1320 return makeUrl( parseUrl); 1321 } 1322 } 1323 1324 if( parseUrl.startsWith("//") ) { 1326 return makeUrl(baseUrl.getProtocol()+":"+parseUrl); 1327 } 1328 1329 final int fragmentIndex = parseUrl.lastIndexOf("#"); 1331 if( fragmentIndex != -1 ) { 1332 parseUrl = parseUrl.substring(0, fragmentIndex); 1333 } 1334 1335 1336 String stringQuery = null; 1338 final int queryIndex = parseUrl.lastIndexOf("?"); 1339 if( queryIndex != -1 ) { 1340 stringQuery = parseUrl.substring(queryIndex); 1341 parseUrl = parseUrl.substring(0, queryIndex); 1342 } 1343 1344 String stringParameters = null; 1346 final int parametersIndex = parseUrl.lastIndexOf(";"); 1347 if( parametersIndex != -1 ) { 1348 stringParameters = parseUrl.substring(parametersIndex); 1349 parseUrl = parseUrl.substring(0, parametersIndex); 1350 } 1351 1352 final List tokens = new ArrayList (); 1354 final String stringToTokenize; 1355 if( parseUrl.trim().length() == 0 ) { 1356 stringToTokenize = baseUrl.getPath(); 1357 } 1358 else if( parseUrl.startsWith("/") ) { 1359 stringToTokenize = parseUrl; 1360 } 1361 else { 1362 String path = baseUrl.getPath(); 1363 if( !path.endsWith("/") && parseUrl.length() != 0) { 1364 path += "/.."; 1365 } 1366 stringToTokenize = path+"/"+parseUrl; 1367 } 1368 1369 final String pathToTokenize = stringToTokenize; 1370 final StringTokenizer tokenizer = new StringTokenizer (pathToTokenize, "/"); 1371 while( tokenizer.hasMoreTokens() ) { 1372 tokens.add( tokenizer.nextToken() ); 1373 } 1374 1375 for( int i=0; i<tokens.size(); i++ ) { 1376 final String oneToken = (String )tokens.get(i); 1377 if( oneToken.length() == 0 || oneToken.equals(".") ) { 1378 tokens.remove(i--); 1379 } 1380 else if( oneToken.equals("..") ) { 1381 tokens.remove(i--); 1382 if( i >= 0 ) { 1383 tokens.remove(i--); 1384 } 1385 } 1386 } 1387 1388 final StringBuffer buffer = new StringBuffer (); 1389 buffer.append( baseUrl.getProtocol() ); 1390 buffer.append( "://" ); 1391 buffer.append( baseUrl.getHost() ); 1392 final int port = baseUrl.getPort(); 1393 if( port != -1 ) { 1394 buffer.append( ":" ); 1395 buffer.append( port ); 1396 } 1397 1398 final Iterator iterator = tokens.iterator(); 1399 while( iterator.hasNext() ) { 1400 buffer.append("/"); 1401 buffer.append(iterator.next()); 1402 } 1403 1404 if( pathToTokenize.endsWith("/") ) { 1405 buffer.append("/"); 1406 } 1407 1408 if (stringParameters != null) { 1409 buffer.append(stringParameters); 1410 } 1411 if (stringQuery != null) { 1412 buffer.append(stringQuery); 1413 } 1414 final String newUrlString = buffer.toString(); 1415 return makeUrl( newUrlString ); 1416 } 1417 1418 private WebResponse makeWebResponseForAboutUrl(final URL url) { 1419 if (!url.toExternalForm().substring("about:".length()).equalsIgnoreCase("blank")){ 1420 throw new IllegalArgumentException ( 1421 url.toExternalForm()+"is not supported, only about:blank is supported now."); 1422 } 1423 return WEB_RESPONSE_FOR_ABOUT_BLANK; 1424 } 1425 1426 1435 private WebResponse makeWebResponseForFileUrl(final URL url) throws IOException { 1436 final File file = FileUtils.toFile(url); 1437 1438 final String encoding = (new OutputStreamWriter (new ByteArrayOutputStream ())).getEncoding(); 1440 final String str = FileUtils.readFileToString(file, encoding); 1441 final String contentType = guessContentType(file); 1442 1443 return new WebResponse() { 1444 public int getStatusCode() { 1445 return 200; 1446 } 1447 public String getStatusMessage() { 1448 return "OK"; 1449 } 1450 public String getContentType() { 1451 return contentType; 1452 } 1453 public String getContentAsString() { 1454 return str; 1455 } 1456 public InputStream getContentAsStream() { 1457 return TextUtil.toInputStream(str); 1458 } 1459 public URL getUrl() { 1460 return url; 1461 } 1462 public List getResponseHeaders() { 1463 return Collections.EMPTY_LIST; 1464 } 1465 public String getResponseHeaderValue(final String key) { 1466 return ""; 1467 } 1468 public long getLoadTimeInMilliSeconds() { 1469 return 0; 1470 } 1471 public byte[] getResponseBody() { 1472 return str.getBytes(); 1473 } 1474 public String getContentCharSet() { 1475 return encoding; 1476 } 1477 }; 1478 } 1479 1480 1488 public String guessContentType(final File file) { 1489 String contentType = null; 1490 InputStream inputStream = null; 1491 try { 1492 inputStream = new BufferedInputStream (new FileInputStream (file)); 1493 contentType = URLConnection.guessContentTypeFromStream(inputStream); 1494 } 1495 catch (final IOException e) { 1496 } 1498 finally { 1499 IOUtils.closeQuietly(inputStream); 1500 } 1501 1502 if (contentType == null) { 1503 contentType = URLConnection.guessContentTypeFromName(file.getName()); 1504 } 1505 if (contentType == null) { 1506 contentType = "application/octet-stream"; 1507 } 1508 1509 return contentType; 1510 } 1511 1512 private WebResponse makeWebResponseForJavaScriptUrl( final WebWindow webWindow, final URL url ) { 1513 if (!(webWindow instanceof BaseFrame.FrameWindow)) { 1514 throw new IllegalArgumentException ( 1515 "javascript urls can only be used to load content into frames and iframes"); 1516 } 1517 1518 final BaseFrame.FrameWindow frameWindow = (BaseFrame.FrameWindow) webWindow; 1519 final HtmlPage enclosingPage = frameWindow.getEnclosingPage(); 1520 final ScriptResult scriptResult = enclosingPage.executeJavaScriptIfPossible( 1521 url.toExternalForm(), "javascript url", false, null ); 1522 1523 final String contentString = scriptResult.getJavaScriptResult().toString(); 1524 return new StringWebResponse(contentString); 1525 } 1526 1527 1536 public final WebResponse loadWebResponse( 1537 final URL url, final SubmitMethod method, final List parameters) 1538 throws 1539 IOException { 1540 final WebRequestSettings wrs= new WebRequestSettings(url, method); 1541 wrs.setRequestParameters(parameters); 1542 return loadWebResponse(wrs); 1543 } 1544 1545 1555 public final WebResponse loadWebResponse( 1556 final URL url, final FormEncodingType encType, final SubmitMethod method, final List parameters) 1557 throws 1558 IOException { 1559 final WebRequestSettings wrs = new WebRequestSettings(url, method); 1560 wrs.setEncodingType(encType); 1561 wrs.setRequestParameters(parameters); 1562 return loadWebResponse(wrs); 1563 } 1564 1570 public final WebResponse loadWebResponse(final WebRequestSettings webRequestSettings) 1571 throws 1572 IOException { 1573 final URL url = webRequestSettings.getURL(); 1574 final SubmitMethod method = webRequestSettings.getSubmitMethod(); 1575 final List parameters = webRequestSettings.getRequestParameters(); 1576 1577 Assert.notNull("url", url); 1578 Assert.notNull("method", method); 1579 Assert.notNull("parameters", parameters); 1580 1581 getLog().debug("Load response for " + url.toExternalForm()); 1582 1583 final URL fixedUrl = encodeUrl(url); 1586 webRequestSettings.setURL(fixedUrl); 1587 1588 final WebResponse webResponse = getWebConnection().getResponse(webRequestSettings); 1589 final int statusCode = webResponse.getStatusCode(); 1590 1591 if( statusCode >= 301 && statusCode <=307 && isRedirectEnabled() ) { 1592 URL newUrl = null; 1593 String locationString = null; 1594 try { 1595 locationString = webResponse.getResponseHeaderValue("Location"); 1596 if( locationString != null ) { 1597 final int indexOfComma = locationString.indexOf(','); 1600 if( indexOfComma >= 0) { 1601 newUrl = expandUrl( fixedUrl, locationString.substring(0, indexOfComma)); 1602 } 1603 else { 1604 newUrl = expandUrl( fixedUrl, locationString); 1605 } 1606 } 1607 } 1608 catch( final MalformedURLException e ) { 1609 getLog().warn("Got a redirect status code ["+statusCode+" " 1610 +webResponse.getStatusMessage() 1611 +"] but the location is not a valid url ["+locationString+"]"); 1612 } 1613 getLog().debug("Got a redirect status code ["+statusCode 1614 +"] new location=["+locationString+"]"); 1615 if( webResponse.getUrl().toExternalForm().equals(locationString) ) { 1616 getLog().warn("Got a redirect but the location is the same as the page we just loaded [" 1617 +locationString+"]"); 1618 } 1619 else if( newUrl == null ) { 1620 } 1622 else if( ( statusCode == 301 || statusCode == 307 ) 1623 && method.equals(SubmitMethod.GET) ) { 1624 1625 final WebRequestSettings wrs = new WebRequestSettings(newUrl); 1626 wrs.setRequestParameters(parameters); 1627 return loadWebResponse(wrs); 1628 } 1629 else if( statusCode == 302 || statusCode == 303 ) { 1630 final WebRequestSettings wrs = new WebRequestSettings(newUrl); 1631 return loadWebResponse(wrs); 1632 } 1633 } 1634 1635 return webResponse; 1636 } 1637 1638 1646 protected URL encodeUrl(final URL url) throws MalformedURLException , URIException { 1647 final String str = url.toExternalForm(); 1649 final int queryStart = url.toExternalForm().indexOf('?'); 1650 if (queryStart != -1) { 1651 final String query; 1653 final int anchorStart = str.indexOf('#'); 1654 if (anchorStart < queryStart) { 1655 query = str.substring(queryStart); 1656 } 1657 else { 1658 query = str.substring(queryStart, anchorStart); 1659 } 1660 1661 final BitSet partiallyEncodedQuery = new BitSet (256); 1664 partiallyEncodedQuery.set('%'); 1665 partiallyEncodedQuery.or(URI.allowed_query); 1666 final String fixedQuery = URIUtil.encode(query, partiallyEncodedQuery); 1667 if (query.equals(fixedQuery)) { 1668 return url; 1669 } 1670 else { 1671 final StringBuffer newUrl = new StringBuffer (str); 1672 newUrl.replace(queryStart, queryStart + query.length(), fixedQuery); 1673 return new URL (newUrl.toString()); 1674 } 1675 } 1676 else { 1677 return url; 1678 } 1679 1680 } 1681 1682 1690 public boolean moveFocusFromElement( final FocusableElement oldElement ) { 1691 if (oldElement != null && elementWithFocus_ == oldElement) { 1692 final String onBlurHandler = oldElement.getAttributeValue("onblur"); 1693 if( onBlurHandler.length() != 0 ) { 1694 final HtmlPage currentPage = oldElement.getPage(); 1695 final Page newPage = currentPage.executeJavaScriptIfPossible( 1696 onBlurHandler, "OnBlur handler", true, oldElement).getNewPage(); 1697 1698 if( currentPage != newPage ) { 1701 elementWithFocus_ = null; 1702 return false; 1703 } 1704 } 1705 elementWithFocus_ = null; 1706 return true; 1707 } 1708 return false; 1709 } 1710 1711 1712 1724 public boolean moveFocusToElement( final FocusableElement newElement ) { 1725 1726 if( newElement == null ) { 1727 throw new IllegalArgumentException ("Cannot move focus to null"); 1728 } 1729 1730 if( elementWithFocus_ == newElement ) { 1731 return true; 1733 } 1734 1735 if( elementWithFocus_ != null && elementWithFocus_.getPage() == newElement.getPage()) { 1737 elementWithFocus_.blur(); 1738 } 1739 1740 final String onFocusHandler = newElement.getAttributeValue("onfocus"); 1741 if( onFocusHandler.length() != 0 ) { 1742 final HtmlPage currentPage = newElement.getPage(); 1743 final Page newPage = currentPage.executeJavaScriptIfPossible( 1744 onFocusHandler, "OnFocus handler", true, newElement).getNewPage(); 1745 1746 if( currentPage != newPage ) { 1749 elementWithFocus_ = null; 1750 return false; 1751 } 1752 } 1753 1754 elementWithFocus_ = newElement; 1755 return true; 1756 } 1757 1758 1759 1765 public FocusableElement getElementWithFocus() { 1766 return elementWithFocus_; 1767 } 1768 1769 1773 public List getWebWindows() { 1774 return Collections.unmodifiableList(webWindows_); 1775 } 1776 1777 1782 public void setRefreshHandler( final RefreshHandler handler ) { 1783 if( handler == null ) { 1784 refreshHandler_ = new ImmediateRefreshHandler(); 1785 } 1786 else { 1787 refreshHandler_ = handler; 1788 } 1789 } 1790 1791 1795 public RefreshHandler getRefreshHandler() { 1796 return refreshHandler_; 1797 } 1798 1799 1803 public void setScriptPreProcessor( final ScriptPreProcessor scriptPreProcessor ) { 1804 scriptPreProcessor_ = scriptPreProcessor; 1805 } 1806 1807 1808 1812 public ScriptPreProcessor getScriptPreProcessor() { 1813 return scriptPreProcessor_; 1814 } 1815 1816 1823 public void setActiveXObjectMap( final Map activeXObjectMap ) { 1824 activeXObjectMap_ = activeXObjectMap; 1825 } 1826 1827 1828 1832 public Map getActiveXObjectMap() { 1833 return activeXObjectMap_; 1834 } 1835 1836 1845 public void setHTMLParserListener(final HTMLParserListener listener) { 1846 htmlParserListener_ = listener; 1847 } 1848 1849 1853 public HTMLParserListener getHTMLParserListener() { 1854 return htmlParserListener_; 1855 } 1856 1857 1863 public static void setIgnoreOutsideContent(final boolean ignoreOutsideContent) { 1864 HTMLParser.setIgnoreOutsideContent(ignoreOutsideContent); 1865 } 1866 1867 1871 public static boolean getIgnoreOutsideContent() { 1872 return HTMLParser.getIgnoreOutsideContent(); 1873 } 1874 1875 1881 public int getTimeout() { 1882 return timeout_; 1883 } 1884 1893 public void setTimeout(final int timeout){ 1894 timeout_ = timeout; 1895 } 1896 1897 1903 public boolean isThrowExceptionOnScriptError() { 1904 return throwExceptionOnScriptError_; 1905 } 1906 1907 1908 1912 public void setThrowExceptionOnScriptError(final boolean newValue) { 1913 throwExceptionOnScriptError_ = newValue; 1914 } 1915} 1916 1917 | Popular Tags |