1 38 package com.gargoylesoftware.htmlunit.javascript.host; 39 40 import java.io.IOException ; 41 import java.net.MalformedURLException ; 42 import java.net.URL ; 43 import java.util.Iterator ; 44 import java.util.List ; 45 46 import org.org.apache.commons.httpclient.NameValuePair; 47 import org.mozilla.javascript.Context; 48 import org.mozilla.javascript.Function; 49 import org.mozilla.javascript.Scriptable; 50 51 import com.gargoylesoftware.htmlunit.DefaultCredentialsProvider; 52 import com.gargoylesoftware.htmlunit.Page; 53 import com.gargoylesoftware.htmlunit.SubmitMethod; 54 import com.gargoylesoftware.htmlunit.WebClient; 55 import com.gargoylesoftware.htmlunit.WebRequestSettings; 56 import com.gargoylesoftware.htmlunit.javascript.JavaScriptEngine; 57 import com.gargoylesoftware.htmlunit.javascript.SimpleScriptable; 58 import com.gargoylesoftware.htmlunit.xml.XmlPage; 59 60 67 public class XMLHttpRequest extends SimpleScriptable { 68 69 private static final long serialVersionUID = 2369039843039430664L; 70 71 72 public static final int STATE_UNINITIALIZED = 0; 73 74 public static final int STATE_LOADING = 1; 75 76 public static final int STATE_LOADED = 2; 77 78 public static final int STATE_INTERACTIVE = 3; 79 80 public static final int STATE_COMPLETED = 4; 81 82 private int state_; 83 private Function stateChangeHandler_; 84 private WebRequestSettings requestSettings_; 85 private boolean async_; 86 private Thread requestThread_; 87 private XmlPage page_; 88 89 92 public XMLHttpRequest() { 93 state_ = STATE_UNINITIALIZED; 94 } 95 96 100 public Function jsxGet_onreadystatechange() { 101 return stateChangeHandler_; 102 } 103 104 108 public void jsxSet_onreadystatechange( Function stateChangeHandler ) { 109 stateChangeHandler_ = stateChangeHandler; 110 } 111 112 118 private void setState( final int state, Context context ) { 119 state_ = state; 120 if( stateChangeHandler_ != null ) { 121 if( context == null ) { 122 context = Context.getCurrentContext(); 123 } 124 final Scriptable scope = stateChangeHandler_.getParentScope(); 125 final Object [] args = new Object [ 0 ]; 126 stateChangeHandler_.call( context, scope, this, args ); 127 } 128 } 129 130 141 public int jsxGet_readyState() { 142 return state_; 143 } 144 145 149 public String jsxGet_responseText() { 150 if( page_ != null ) { 151 return page_.getContent(); 152 } 153 else { 154 getLog().debug( "XMLHttpRequest.responseText was retrieved before the response was available." ); 155 return ""; 156 } 157 } 158 159 163 public Object jsxGet_responseXML() { 164 if( page_ != null ) { 165 return page_.getXmlDocument(); 166 } 167 else { 168 getLog().error( "XMLHttpRequest.responseXML was retrieved before the response was available." ); 169 return null; 170 } 171 } 172 173 178 public int jsxGet_status() { 179 if( page_ != null ) { 180 return page_.getWebResponse().getStatusCode(); 181 } 182 else { 183 getLog().error( "XMLHttpRequest.status was retrieved before the response was available." ); 184 return 0; 185 } 186 } 187 188 192 public String jsxGet_statusText() { 193 if( page_ != null ) { 194 return page_.getWebResponse().getStatusMessage(); 195 } 196 else { 197 getLog().error( "XMLHttpRequest.statusText was retrieved before the response was available." ); 198 return null; 199 } 200 } 201 202 205 public void jsxFunction_abort() { 206 if( requestThread_ != null ) { 207 requestThread_.interrupt(); 208 } 209 } 210 211 215 public String jsxFunction_getAllResponseHeaders() { 216 if( page_ != null ) { 217 StringBuffer buffer = new StringBuffer (); 218 final List headers = page_.getWebResponse().getResponseHeaders(); 219 for( final Iterator i = headers.iterator(); i.hasNext(); ) { 220 NameValuePair header = (NameValuePair) i.next(); 221 buffer.append(header.getName()).append(": ").append(header.getValue()).append("\n"); 222 } 223 return buffer.toString(); 224 } 225 else { 226 getLog().error( "XMLHttpRequest.getAllResponseHeaders() was called before the response was available." ); 227 return null; 228 } 229 } 230 231 236 public String jsxFunction_getResponseHeader( final String headerName ) { 237 if( page_ != null ) { 238 return page_.getWebResponse().getResponseHeaderValue( headerName ); 239 } 240 else { 241 getLog().error( "XMLHttpRequest.getResponseHeader() was called before the response was available." ); 242 return null; 243 } 244 } 245 246 254 public void jsxFunction_open( final String method, final String url, final boolean async, 255 final String user, final String password ) { 256 try { 258 WebRequestSettings settings = new WebRequestSettings( new URL ( url ) ); 259 SubmitMethod submitMethod; 260 if( "POST".equalsIgnoreCase( method ) ) { 261 submitMethod = SubmitMethod.POST; 262 } 263 else { 264 submitMethod = SubmitMethod.GET; 265 } 266 settings.setSubmitMethod( submitMethod ); 267 if( user != null ) { 268 DefaultCredentialsProvider dcp = new DefaultCredentialsProvider(); 269 dcp.addCredentials( user, password ); 270 settings.setCredentialsProvider( dcp ); 271 } 272 requestSettings_ = settings; 273 } 274 catch( final MalformedURLException e ) { 275 getLog().error( "Unable to initialize XMLHttpRequest using malformed URL '" + url + "'." ); 276 return; 277 } 278 async_ = async; 280 setState( STATE_LOADING, null ); 282 } 283 284 288 public void jsxFunction_send( final String content ) { 289 final WebClient wc = JavaScriptEngine.getWebClientForCurrentThread(); 291 final Context context = Context.getCurrentContext(); 292 final Thread t = new Thread ( "XMLHttpRequest.send() Thread" ) { 293 public void run() { 294 try { 295 setState( STATE_LOADED, context ); 296 if( content != null && ! "undefined".equals( content ) ) { 297 requestSettings_.setRequestBody( content ); 298 } 299 final Page page = wc.getPage( requestSettings_ ); 300 final String contentType = page.getWebResponse().getContentType(); 301 if( "text/xml".equals( contentType ) == false ) { 302 setState( STATE_LOADING, context ); 303 String msg = "The Content-Type of the data returned from the server must be 'text/xml'; " + 304 "actual content type was '" + contentType + "'."; 305 throw Context.reportRuntimeError( msg ); 306 } 307 page_ = (XmlPage) page; 308 setState( STATE_INTERACTIVE, context ); 309 setState( STATE_COMPLETED, context ); 310 } 311 catch( final IOException e ) { 312 setState( STATE_LOADING, context ); 313 throw Context.reportRuntimeError( "Unable to send the XMLHttpRequest: " + e ); 314 } 315 } 316 }; 317 requestThread_ = t; 318 requestThread_.start(); 319 if( ! async_ ) { 321 try { 322 requestThread_.join(); 323 } 324 catch( final InterruptedException e ) { 325 getLog().info( t.getName() + " interrupted; abort() probably called." ); 326 } 327 } 328 } 329 330 336 public void jsxFunction_setRequestHeader( final String name, final String value ) { 337 if( requestSettings_ != null ) { 338 requestSettings_.addAdditionalHeader( name, value ); 339 } 340 else { 341 throw Context.reportRuntimeError( "The open() method must be called before setRequestHeader()." ); 342 } 343 } 344 345 } 346 | Popular Tags |