Source code: com/meterware/httpunit/WebWindow.java
1 package com.meterware.httpunit;
2 /********************************************************************************************************************
3 * $Id: WebWindow.java,v 1.19 2004/06/30 23:54:49 russgold Exp $
4 *
5 * Copyright (c) 2002-2004, Russell Gold
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
8 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
10 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
13 * of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
16 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
18 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
19 * DEALINGS IN THE SOFTWARE.
20 *
21 *******************************************************************************************************************/
22 import java.io.IOException;
23 import java.net.HttpURLConnection;
24 import java.net.MalformedURLException;
25 import java.util.List;
26
27 import org.xml.sax.SAXException;
28
29 /**
30 * A window managed by a {@link com.meterware.httpunit.WebClient WebClient}.
31 *
32 * @author <a href="mailto:russgold@httpunit.org">Russell Gold</a>
33 **/
34 public class WebWindow {
35
36 /** The client which created this window. **/
37 private WebClient _client;
38
39 /** A map of frame names to current contents. **/
40 private FrameHolder _frameContents;
41
42 /** The name of the window, set via JavaScript. **/
43 private String _name = "";
44
45 /** The web response containing the reference that opened this window **/
46 private WebResponse _opener;
47
48 /** True if this window has been closed. **/
49 private boolean _closed;
50
51
52 static final String NO_NAME = "$$HttpUnit_Window$$_";
53
54
55 /**
56 * Returns the web client associated with this window.
57 */
58 public WebClient getClient() {
59 return _client;
60 }
61
62
63 /**
64 * Returns true if this window has been closed.
65 */
66 public boolean isClosed() {
67 return _closed;
68 }
69
70
71 /**
72 * Closes this window.
73 */
74 public void close() {
75 if (!_closed) _client.close( this );
76 _closed = true;
77 }
78
79
80 /**
81 * Returns the name of this window. Windows created through normal HTML or browser commands have empty names,
82 * but JavaScript can set the name. A name may be used as a target for a request.
83 */
84 public String getName() {
85 return _name;
86 }
87
88
89 /**
90 * Returns the web response that contained the script which opened this window.
91 */
92 public WebResponse getOpener() {
93 return _opener;
94 }
95
96
97 /**
98 * Submits a GET method request and returns a response.
99 * @exception SAXException thrown if there is an error parsing the retrieved page
100 **/
101 public WebResponse getResponse( String urlString ) throws MalformedURLException, IOException, SAXException {
102 return getResponse( new GetMethodWebRequest( urlString ) );
103 }
104
105
106 /**
107 * Submits a web request and returns a response. This is an alternate name for the getResponse method.
108 */
109 public WebResponse sendRequest( WebRequest request ) throws MalformedURLException, IOException, SAXException {
110 return getResponse( request );
111 }
112
113
114 /**
115 * Submits a web request and returns a response, using all state developed so far as stored in
116 * cookies as requested by the server.
117 * @exception SAXException thrown if there is an error parsing the retrieved page
118 **/
119 public WebResponse getResponse( WebRequest request ) throws MalformedURLException, IOException, SAXException {
120 final RequestContext requestContext = new RequestContext();
121 final WebResponse response = getSubframeResponse( request, requestContext );
122 requestContext.runScripts();
123 return response == null ? null : response.getWindow().getFrameContents( response.getFrame() ); // javascript might replace the response in its frame
124 }
125
126
127 WebResponse getSubframeResponse( WebRequest request, RequestContext requestContext ) throws IOException, SAXException {
128 WebResponse response = getResource( request );
129
130 return response == null ? null : updateWindow( request.getTarget(), response, requestContext );
131 }
132
133
134 /**
135 * Updates this web client based on a received response. This includes updating
136 * cookies and frames.
137 **/
138 WebResponse updateWindow( String requestTarget, WebResponse response, RequestContext requestContext ) throws MalformedURLException, IOException, SAXException {
139 _client.updateClient( response );
140 if (getClient().getClientProperties().isAutoRefresh() && response.getRefreshRequest() != null) {
141 return getResponse( response.getRefreshRequest() );
142 } else if (shouldFollowRedirect( response )) {
143 delay( HttpUnitOptions.getRedirectDelay() );
144 return getResponse( new RedirectWebRequest( response ) );
145 } else {
146 _client.updateFrameContents( this, requestTarget, response, requestContext );
147 return response;
148 }
149 }
150
151
152 /**
153 * Returns the resource specified by the request. Does not update the window or load included framesets.
154 * May return null if the resource is a JavaScript URL which would normally leave the client unchanged.
155 */
156 public WebResponse getResource( WebRequest request ) throws IOException {
157 _client.tellListeners( request );
158
159 WebResponse response = null;
160 String urlString = request.getURLString().trim();
161 if (urlString.startsWith( "about:" )) {
162 response = new DefaultWebResponse( _client, _frameContents.getTargetFrame( request ), null, "" );
163 } else if (!HttpUnitUtils.isJavaScriptURL( urlString )) {
164 response = _client.newResponse( request, _frameContents.getTargetFrame( request ) );
165 } else {
166 WebRequestSource wrs = request.getWebRequestSource();
167 String result = (wrs == null) ? getCurrentPage().getScriptableObject().evaluateExpression( urlString )
168 : wrs.getScriptableDelegate().evaluateExpression( urlString );
169 if (result != null) response = new DefaultWebResponse( _client, _frameContents.getTargetFrame( request ), request.getURL(), result );
170 }
171
172 if (response != null) _client.tellListeners( response );
173 return response;
174 }
175
176
177 /**
178 * Returns the name of the currently active frames.
179 **/
180 public String[] getFrameNames() {
181 final List names = _frameContents.getActiveFrameNames();
182 return (String[]) names.toArray( new String[ names.size() ] );
183 }
184
185
186 /**
187 * Returns true if the specified frame name is defined in this window.
188 */
189 public boolean hasFrame( String frameName ) {
190 return _frameContents.get( frameName ) != null;
191 }
192
193
194 boolean hasFrame( FrameSelector frame ) {
195 return _frameContents.get( frame ) != null;
196 }
197
198
199 /**
200 * Returns the response associated with the specified frame name.
201 * Throws a runtime exception if no matching frame is defined.
202 **/
203 public WebResponse getFrameContents( String frameName ) {
204 WebResponse response = _frameContents.get( frameName );
205 if (response == null) throw new NoSuchFrameException( frameName );
206 return response;
207 }
208
209
210 /**
211 * Returns the response associated with the specified frame target.
212 * Throws a runtime exception if no matching frame is defined.
213 **/
214 WebResponse getFrameContents( FrameSelector targetFrame ) {
215 return _frameContents.getFrameContents( targetFrame );
216 }
217
218
219 WebResponse getSubframeContents( FrameSelector frame, String subFrameName ) {
220 return _frameContents.getSubframeContents( frame, subFrameName );
221 }
222
223
224 WebResponse getParentFrameContents( FrameSelector frame ) {
225 return _frameContents.getParentFrameContents( frame );
226 }
227
228
229 /**
230 * Returns the response representing the main page in this window.
231 */
232 public WebResponse getCurrentPage() {
233 return getFrameContents( WebRequest.TOP_FRAME );
234 }
235
236
237 WebWindow( WebClient client ) {
238 _client = client;
239 _frameContents = new FrameHolder( this );
240 _name = NO_NAME + _client.getOpenWindows().length;
241 }
242
243
244 WebWindow( WebClient client, WebResponse opener ) {
245 this( client );
246 _opener = opener;
247 }
248
249
250 void updateFrameContents( WebResponse response, RequestContext requestContext ) throws IOException, SAXException {
251 response.setWindow( this );
252 _frameContents.updateFrames( response, response.getFrame(), requestContext );
253 }
254
255
256 void setName( String name ) {
257 _name = name;
258 }
259
260
261 /**
262 * Delays the specified amount of time.
263 **/
264 private void delay( int numMilliseconds ) {
265 if (numMilliseconds == 0) return;
266 try {
267 Thread.sleep( numMilliseconds );
268 } catch (InterruptedException e) {
269 // ignore the exception
270 }
271 }
272
273
274 private boolean shouldFollowRedirect( WebResponse response ) {
275 return getClient().getClientProperties().isAutoRedirect()
276 && response.getResponseCode() >= HttpURLConnection.HTTP_MOVED_PERM
277 && response.getResponseCode() <= HttpURLConnection.HTTP_MOVED_TEMP
278 && response.getHeaderField( "Location" ) != null;
279 }
280
281
282 FrameSelector getTopFrame() {
283 return _frameContents.getTopFrame();
284 }
285
286
287 FrameSelector getFrame( String target ) {
288 return _frameContents.getFrame( target );
289 }
290
291 }