1 package com.ibm.staf.service.http;
2 
3 /*****************************************************************************/
4 /* Software Testing Automation Framework (STAF)                              */
5 /* (C) Copyright IBM Corp. 2004                                              */
6 /*                                                                           */
7 /* This software is licensed under the Eclipse Public License (EPL) V1.0.    */
8 /*****************************************************************************/
9 
10 /*****************************************************************************/
11 /*                                                                           */
12 /* Class: WebSession                                                         */
13 /* Description: This class provides the handle to maintain a http session.   */
14 /*                                                                           */
15 /*****************************************************************************/
16 
17 import com.ibm.staf.*;
18 import java.util.Vector;
19 import java.util.HashMap;
20 import java.util.Iterator;
21 import java.util.Map;
22 import java.net.URL;
23 import java.net.MalformedURLException;
24 import java.io.IOException;
25 import java.io.FileNotFoundException;
26 import java.io.StringReader;
27 import java.io.File;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.BufferedInputStream;
31 import java.io.FileInputStream;
32 import java.io.FileOutputStream;
33 import java.io.DataInputStream;
34 import java.io.DataOutputStream;
35 import java.io.FileWriter;
36 
37 import org.w3c.dom.Document;
38 
39 import com.ibm.staf.service.STAFServiceInterfaceLevel30;
40 import com.ibm.staf.STAFUtil;
41 import com.ibm.staf.service.http.html.InvalidParameterValueException;
42 import com.ibm.staf.service.http.html.WebLink;
43 import com.ibm.staf.service.http.html.WebForm;
44 import com.ibm.staf.service.http.html.HTMLParser;
45 
46 // HTTP Client
47 import org.apache.commons.httpclient.*;
48 import org.apache.commons.httpclient.util.EncodingUtil;
49 import org.apache.commons.httpclient.methods.*;
50 import org.apache.commons.httpclient.params.HttpMethodParams;
51 import org.apache.commons.httpclient.auth.AuthScope;
52 import org.apache.commons.httpclient.methods.multipart.*;
53 
54 // nekoHTML
55 import org.cyberneko.html.parsers.DOMParser;
56 import org.w3c.dom.html.HTMLDocument;
57 
58 // xerces
59 import org.xml.sax.SAXException;
60 import org.xml.sax.InputSource;
61 
62 public class WebSession
63 {
64     // These constants define the type of identification of the page element to
65     //  be accessed.
66     public static final int NAME_ID_TYPE = 0;
67     public static final int ID_ID_TYPE = 1;
68     public static final int INDEX_ID_TYPE = 2;
69 
70     // These constants define the parts of the summary
71     public static final String ID = "ID";
72     public static final String URL = "URL";
73     public static final String TITLE = "TITLE";
74     public static final String POLICY = "POLICY";
75     public static final String OWNER_INSTANCE_UUID = "OWNER_INSTANCE_UUID";
76     public static final String OWNER_MACHINE = "OWNER_MACHINE";
77     public static final String OWNER_HANDLE_NAME = "OWNER_HANDLE_NAME";
78     public static final String OWNER_HANDLE = "OWNER_HANDLE";
79     public static final String PARSE_CONTENT = "PARSE_CONTENT";
80     public static final String HTTP_PROXY_HOST = "HTTP_PROXY_HOST";
81     public static final String HTTP_PROXY_PORT = "HTTP_PROXY_PORT";
82 
83     // These constants are used to define the hash map of required components
84     //  of a requestMethod call
85     public static final String REQUEST_PARAMETERS = "PARAMETERS";
86     public static final String REQUEST_FILES = "FILES";
87     public static final String REQUEST_HEADERS = "HEADERS";
88     public static final String REQUEST_METHOD = "METHOD";
89     public static final String REQUEST_URL = "URL";
90     public static final String REQUEST_CONTENT = "CONTENT";
91     public static final String REQUEST_REDIRECT = "AUTO REDIRECT";
92 
93     public static final String RETURN_STATUS_CODE = "RETURN STATUS CODE";
94     public static final String RETURN_STATUS_MESSAGE = "RETURN STATUS MSG";
95     public static final String RETURN_HEADERS = "RETURN HEADERS";
96 
97     // These constants define the valid values for PARSECONTENT option
98     public static final String ENABLED = "Enabled";
99     public static final String DISABLED = "Disabled";
100     public static final String AUTODETECT = "AutoDetect";
101 
102     protected int id;
103     protected String ownerInstanceUUID;
104     protected String ownerMachine;
105     protected String ownerHandleName;
106     protected int ownerHandle;
107     protected HTTP httpService;
108     protected HttpClient session;
109     protected HttpMethodBase lastRequest;
110     protected HTMLParser parser;
111     protected HashMap defaultHeaders;
112     protected HashMap authenticationSets;
113     protected boolean followRedirect;
114     protected String fParseContent;
115     protected String currentContents;
116     protected String currentContentsFileName;
117 
118     // true means that a temporary session was opened for a single request
119     // (e.g. the SESSION option wasn't specified on the request)
120     protected boolean tempSession;
121 
122     private static final int BUFF_SIZE = 4096;
123     private static final int MAX_STRING_SIZE = 51200;
124 
125 /*****************************************************************************/
126 /*                                                                           */
127 /* Method: Constructor                                                       */
128 /* Description: Constructor method                                           */
129 /* Parameter: parentList - session list that this session is to be a part of */
130 /*                         it is required to determine the id of this session*/
131 /*            info - request info                                            */
132 /*                                                                           */
133 /*****************************************************************************/
134 
WebSession(SessionList parentList, STAFServiceInterfaceLevel30.RequestInfo info, HTTP httpService)135     public WebSession(SessionList parentList,
136                       STAFServiceInterfaceLevel30.RequestInfo info,
137                       HTTP httpService)
138     {
139         this(parentList, info, httpService, false);
140     }
141 
WebSession(SessionList parentList, STAFServiceInterfaceLevel30.RequestInfo info, HTTP httpService, boolean tempSession)142     public WebSession(SessionList parentList,
143                       STAFServiceInterfaceLevel30.RequestInfo info,
144                       HTTP httpService, boolean tempSession)
145     {
146         this.ownerInstanceUUID = info.stafInstanceUUID;
147         this.ownerMachine = info.endpoint;
148         this.ownerHandleName = info.handleName;
149         this.ownerHandle = info.handle;
150         this.httpService = httpService;
151         this.tempSession = tempSession;
152         id = parentList.addSession(this);
153         session = new HttpClient();
154 
155         lastRequest = null;
156         parser = new HTMLParser();
157         defaultHeaders = new HashMap();
158         authenticationSets = new HashMap();
159         followRedirect = false;
160         fParseContent = AUTODETECT;
161         currentContents = "";
162         currentContentsFileName = "";
163     }
164 
releaseConnection()165     public void releaseConnection()
166     {
167         currentContents = "";
168 
169         if (!currentContentsFileName.equals(""))
170         {
171             // Delete temporary file
172             (new File(currentContentsFileName)).delete();
173 
174             currentContentsFileName = "";
175         }
176 
177         if (lastRequest != null)
178         {
179             // Must call releaseConnection to release resources
180             lastRequest.releaseConnection();
181             lastRequest = null;
182         }
183 
184         // Close any idle connections.  This is required to close the socket
185         // so it doesn't remain open in a CLOSE_WAIT state.
186 
187         session.getHttpConnectionManager().closeIdleConnections(0);
188 
189         try
190         {
191             parser.setContent(HTMLParser.EMPTY_DOC);
192         }
193         catch (Exception e)
194         {
195            // HTMLParser.EMPTY_DOC is safe and will not cause an exception
196         }
197     }
198 
199 /*****************************************************************************/
200 /*                                                                           */
201 /* Method: getID                                                             */
202 /* Description: gets the session id of this WebSesson.                       */
203 /* Returns: the ID which identifies the session in the list                  */
204 /*                                                                           */
205 /*****************************************************************************/
206 
getID()207     public int getID()
208     {
209         return id;
210     }
211 
212 /*****************************************************************************/
213 /*                                                                           */
214 /* Method: getOwnerMachine                                                   */
215 /* Description: gets the owner machine for this WebSesson.                   */
216 /* Returns: the machine for the owner of this session                        */
217 /*                                                                           */
218 /*****************************************************************************/
219 
getOwnerMachine()220     public String getOwnerMachine()
221     {
222         return ownerMachine;
223     }
224 
225 /*****************************************************************************/
226 /*                                                                           */
227 /* Method: getOwnerHandleName                                                */
228 /* Description: gets the owner handle name for this WebSesson.               */
229 /* Returns: the handle name for the owner of this session                    */
230 /*                                                                           */
231 /*****************************************************************************/
232 
getOwnerHandleName()233     public String getOwnerHandleName()
234     {
235         return ownerHandleName;
236     }
237 
238 /*****************************************************************************/
239 /*                                                                           */
240 /* Method: getOwnerHandle                                                    */
241 /* Description: gets the owner handle for this WebSesson.                    */
242 /* Returns: the handle for the owner of this session                         */
243 /*                                                                           */
244 /*****************************************************************************/
245 
getOwnerHandle()246     public int getOwnerHandle()
247     {
248         return ownerHandle;
249     }
250 
251 /*****************************************************************************/
252 /*                                                                           */
253 /* Method: getCurrentContentsAsStream                                        */
254 /* Description: get the contents returned by the last interaction            */
255 /* Parameters: none                                                          */
256 /* Returns: the contents of the last interaction in an InputStream.          */
257 /*          This is the html code for the current page if the last action    */
258 /*          was a goto or link.  Otherwise it is the message generated by    */
259 /*          the METHOD call.                                                 */
260 /*                                                                           */
261 /*****************************************************************************/
262 
getCurrentContentsAsStream()263     public InputStream getCurrentContentsAsStream() throws IOException
264     {
265         if (HTTP.DEBUG)
266             System.out.println("In WebSession.getResponseBodyAsStream()");
267 
268         try
269         {
270             return lastRequest.getResponseBodyAsStream();
271         }
272         catch (NullPointerException e)
273         {
274             // No previous requests
275         }
276 
277         // Return null if an error occurs
278         return null;
279     }
280 
281 /*****************************************************************************/
282 /*                                                                           */
283 /* Method: getCurrentContents                                                */
284 /* Description: get the contents returned by the last interaction            */
285 /* Parameters: none                                                          */
286 /* Returns: the contents of the last interaction in a String.                */
287 /*          This is the html code for the current page if the last action    */
288 /*          was a goto or link. Otherwise it is the message generated by the */
289 /*          METHOD call.                                                     */
290 /*                                                                           */
291 /*****************************************************************************/
292 
getCurrentContents()293     public String getCurrentContents() throws STAFException,
294                                               ContentTooLargeException
295     {
296         if (HTTP.DEBUG)
297             System.out.println("In WebSession.getCurrentContents()");
298 
299         // Get content from where setCurrentContent stored it.
300         // If content is small, the content is stored in a string.
301         // If content is large, the content is stored in a temporary file.
302 
303         if (currentContentsFileName.equals(""))
304         {
305             // Current contents <= 50k are stored in a string
306 
307             if (HTTP.DEBUG)
308                 System.out.println("Current contents in string since < 50k");
309 
310             return currentContents;
311         }
312         else
313         {
314             // Current contents > 50k are stored in a temporary file
315             // Read from the file specified by currentContentsFileName
316 
317             if (HTTP.DEBUG)
318                 System.out.println("Current contents in temp file " +
319                                    currentContentsFileName);
320 
321             StringBuffer output = new StringBuffer();
322             InputStream instream = null;
323 
324             final byte[] buffer = new byte[BUFF_SIZE];
325 
326             try
327             {
328                 instream = new DataInputStream(new FileInputStream(
329                     currentContentsFileName));
330 
331                 // Read InputStream
332 
333                 while (true)
334                 {
335                     int amountRead = instream.read(buffer);
336 
337                     if (amountRead == -1)
338                     {
339                         break;
340                     }
341 
342                     // Write to a string
343                     output.append(new String(buffer, 0, amountRead));
344                 }
345             }
346             catch(IOException e)
347             {
348                 output = new StringBuffer(HTMLParser.EMPTY_DOC);
349 
350                 throw new STAFException(
351                      STAFResult.FileReadError,
352                     "Error getting current contents.\n" + e.toString());
353             }
354             catch(OutOfMemoryError e)
355             {
356                 output = new StringBuffer();
357 
358                 throw new ContentTooLargeException(
359                    "Getting the session content caused an OutOfMemoryError " +
360                    "because it is too large. Recommend redirecting the content " +
361                    "to a file using the FILE option or, if the content is not " +
362                    "needed, you may be able to specify the RETURNNOCONTENT " +
363                    "option depending on the request.");
364             }
365             finally
366             {
367                 try
368                 {
369                     if (instream != null) instream.close();
370                 }
371                 catch(IOException e)
372                 {
373                     throw new STAFException(
374                         STAFResult.FileReadError,
375                         "Error getting current contents while closing " +
376                         "stream.\n" + e.toString());
377                 }
378             }
379 
380             if (HTTP.DEBUG)
381                 System.out.println("WebSession.getCurrentContents() return");
382 
383             return output.toString();
384         }
385     }
386 
387 
388 /*****************************************************************************/
389 /*                                                                           */
390 /* Method: setCurrentContents                                                */
391 /* Description: Set the current contents for the last interaction by reading */
392 /*          from the input stream.  If temporary file (e.g. fileName == null)*/
393 /*          and contents <= 50K, store the contents in a string.  Otherwise, */
394 /*          store the contents in a file.                                    */
395 /*          Also, set the content for the HTML parser if the contents for    */
396 /*          the last interaction is text/html.                               */
397 /* Parameters: instream - input stream containing the contents for the last  */
398 /*                        interaction for this session.                      */
399 /*                                                                           */
400 /*****************************************************************************/
setCurrentContents(InputStream instream, String fileName, String machine)401     public void setCurrentContents(InputStream instream,
402                                    String fileName, String machine)
403         throws STAFException, IOException
404     {
405         if (HTTP.DEBUG)
406             System.out.println("In WebSession.setCurrentContents()");
407 
408         currentContents = "";
409         currentContentsFileName = "";
410 
411         if (instream == null) return;
412 
413         String localFileName = httpService.getTempDir() +
414             "session" + id + ".tmp";
415 
416         // Write the result string as a stream of raw bytes (e.g.
417         // binary mode)
418 
419         BufferedInputStream bis = null;
420         OutputStream outstream = null;
421         StringBuffer output = new StringBuffer();
422         long totalRead = 0;
423         final byte[] buffer = new byte[BUFF_SIZE];
424 
425         // Read content from input stream and write content to a string if
426         // fileName is not specified (e.g. is null) or if the content stream
427         // size is small (e.g. <= MAX_STRING_SIZE). Otherwise, write the
428         // content to a file.
429 
430         try
431         {
432             bis = new BufferedInputStream(instream);
433 
434             outstream = new DataOutputStream(new FileOutputStream(
435                 localFileName));
436 
437             while (true)
438             {
439                 int amountRead = bis.read(buffer);
440 
441                 if (amountRead == -1) break;
442 
443                 if ((fileName == null) && (totalRead <= MAX_STRING_SIZE))
444                 {
445                     // Write to a string
446                     output.append(new String(buffer, 0, amountRead));
447                 }
448 
449                 // Write to a file
450                 outstream.write(buffer, 0, amountRead);
451 
452                 totalRead += amountRead;
453             }
454 
455             if (HTTP.DEBUG)
456                 System.out.println("totalRead=" + totalRead);
457         }
458         catch(IOException e)
459         {
460             // Delete the temporary file before throwing the exception
461 
462             if (outstream != null) outstream.close();
463             (new File(localFileName)).delete();
464 
465             throw new STAFException(
466                  STAFResult.FileWriteError,
467                 "Error setting current contents.\n" + e.toString());
468         }
469         finally
470         {
471             try
472             {
473                 if (bis != null) bis.close();
474                 if (outstream != null) outstream.close();
475             }
476             catch(IOException e)
477             {
478                 (new File(localFileName)).delete();
479 
480                 throw new STAFException(
481                     STAFResult.FileWriteError,
482                     "Error setting current contents (when closing " +
483                     "streams).\n" + e.toString());
484             }
485         }
486 
487         if ((fileName == null) && (totalRead <= MAX_STRING_SIZE))
488         {
489             // Contents stored in a string
490 
491             if (HTTP.DEBUG)
492                 System.out.println("Contents stored in string");
493 
494             currentContents = output.toString();
495 
496             // Make sure the local temporary file is deleted
497 
498             (new File(localFileName)).delete();
499         }
500         else
501         {
502             // Contents stored in a file
503 
504             if (HTTP.DEBUG)
505                 System.out.println("Contents stored in file " + localFileName);
506 
507             currentContentsFileName = localFileName;
508             output = new StringBuffer("");
509         }
510 
511         // Determine if should parse the content as HTML or not
512 
513         boolean parseContent = false;
514 
515         if (tempSession)
516         {
517             // If temporary session, don't parse the content as HTML (since it
518             // is of no value since won't be able to access the parsed HTML
519             // content)
520 
521             if (HTTP.DEBUG)
522                 System.out.println(
523                     "Don't parse HTML content since temporary session");
524 
525             // Return since don't need to set content to EMPTY_DOC
526             return;
527         }
528 
529         if (fParseContent.equals(AUTODETECT))
530         {
531             // Auto-detect whether should parse the content as HTML by checking
532             // if the "Content-Type" header set by the Web Server contains
533             // "text/html".  If so, then parse the content as HTML.
534 
535             Header contentTypeHeader = lastRequest.getResponseHeader(
536                 "Content-Type");
537 
538             if (contentTypeHeader != null)
539             {
540                 String contentType = contentTypeHeader.getValue();
541 
542                 if (HTTP.DEBUG)
543                     System.out.println(
544                         "Autodetect whether to parse content based on " +
545                         "content type.  Content type: " + contentType);
546 
547                 if ((contentType != null) &&
548                     (contentType.indexOf("text/html") >= 0))
549                     parseContent = true;
550             }
551         }
552         else if (fParseContent.equals(ENABLED))
553         {
554             parseContent = true;
555         }
556 
557         if (HTTP.DEBUG)
558             System.out.println("Parse HTML content: " + parseContent);
559 
560         // If should parse the content as HTML, set the parser content to the
561         // current contents; otherwise, set the parser content to EMPTY_DOC
562 
563         try
564         {
565             if (parseContent)
566             {
567                 if (!currentContents.equals(""))
568                     parser.setContent(currentContents);
569                 else
570                     parser.setContent(
571                         new FileInputStream(currentContentsFileName));
572             }
573             else
574             {
575                 parser.setContent(HTMLParser.EMPTY_DOC);
576             }
577         }
578         catch (Exception e)
579         {
580             try
581             {
582                 parser.setContent(HTMLParser.EMPTY_DOC);
583             }
584             catch (Exception ex)
585             {
586                 // Do nothing. EMPTY_DOC is error free
587             }
588         }
589     }
590 
591 /*****************************************************************************/
592 /*                                                                           */
593 /* Method: writeContentToFile                                                */
594 /* Description: utility method to write the current content to a file        */
595 /* Parameters: filename    - string representation of a file                 */
596 /*             machineName - name of the machine to write the file to        */
597 /* Returns: void                                                             */
598 /*                                                                           */
599 /*****************************************************************************/
600 
writeContentToFile(String toFile, String toMachine)601 public void writeContentToFile(String toFile, String toMachine)
602     throws IOException, STAFException
603 {
604     if (HTTP.DEBUG)
605         System.out.println("WebSession.writeContentToFile()");
606 
607     // Store name for file redirect
608     String fName = toFile;
609 
610     if (currentContentsFileName.equals(""))
611     {
612         // Current contents reside in a string.  Write contents to a file.
613 
614         String fileName = toFile;
615 
616         if (toMachine != null)
617         {
618             // Create a temporary file name to use to store the content in
619             fileName = httpService.getTempDir() + "file" +
620                 httpService.getTempFileCount() + ".tmp";
621         }
622 
623         File outFile = new File(fileName);
624         FileWriter out = new FileWriter(outFile);
625         out.write(currentContents);
626         out.close();
627 
628         if (toMachine == null)
629         {
630             // The contents have already been written to the specified file
631             // on the local machine
632             return;
633         }
634 
635         // Copy the temporary file on the local machine to the specified file
636         // on the specified machine.
637 
638         String request = "COPY FILE " + fileName +
639             " TOFILE " + fName + " TOMACHINE " + toMachine;
640 
641         if (HTTP.DEBUG)
642             System.out.println("STAF local FS " + request);
643 
644         STAFResult res = httpService.getServiceHandle().submit2(
645             "local", "FS", request);
646 
647         // Delete the temporary local file
648 
649         (new File(fileName)).delete();
650 
651         if (res.rc != 0)
652         {
653             String errMsg = "FS " + request + " failed with RC=" + res.rc +
654                 " Result=" + res.result;
655             throw new STAFException(res.rc, errMsg);
656         }
657     }
658     else
659     {
660         // Current contents reside in a file on the local service machine
661 
662         String request = "";
663 
664         if (toMachine == null)
665         {
666             // Copy the contents file to a file on the local service machine
667             request = "COPY FILE " + currentContentsFileName +
668                 " TOFILE " + fName;
669         }
670         else
671         {
672             // Copy the contents file to a file on the specified machine
673             request = "COPY FILE " + currentContentsFileName +
674                 " TOFILE " + fName + " TOMACHINE " + toMachine;
675         }
676 
677         if (HTTP.DEBUG)
678             System.out.println("STAF local FS " + request);
679 
680         STAFResult res = httpService.getServiceHandle().submit2(
681             "local", "FS", request);
682 
683         if (res.rc != 0)
684         {
685             String errMsg = "FS " + request + " failed with RC=" + res.rc +
686                 " Result=" + res.result;
687             throw new STAFException(res.rc, errMsg);
688         }
689     }
690 
691     return;
692 }
693 
694 /*****************************************************************************/
695 /*                                                                           */
696 /* Method: getCurrentTitle                                                   */
697 /* Description: get the title of the current page of the session.            */
698 /* Parameters: none                                                          */
699 /* Returns: the title of the current page of the session.  If there is no    */
700 /*          title, an empty string is returned.                              */
701 /*                                                                           */
702 /*****************************************************************************/
703 
getCurrentTitle()704     public String getCurrentTitle()
705     {
706         try
707         {
708             return parser.getTitle();
709         }
710         catch (Exception e)
711         {
712             // Ignore errors (like DOMExceptions, NullPointerException) when
713             // getting the title to so that a QUERY SESSION or LIST SESSIONS
714             // request won't fail just because could not get the title for a
715             // session.
716             return "";
717         }
718     }
719 
720 /*****************************************************************************/
721 /*                                                                           */
722 /* Method: getCurrentUrl                                                     */
723 /* Description: get the url of the current page of the session.              */
724 /* Parameters: none                                                          */
725 /* Returns: the current url                                                  */
726 /*                                                                           */
727 /*****************************************************************************/
728 
getCurrentUrl()729     public String getCurrentUrl()
730     {
731         try{
732             String url = lastRequest.getURI().getURI();
733             return url;
734         }catch (NullPointerException e){
735             // no previous requests
736         }catch (URIException e){
737         }
738 
739         return "";
740     }
741 
742 /*****************************************************************************/
743 /*                                                                           */
744 /* Method: getCurrentStatusCode                                              */
745 /* Description: get the status code of the last request of the session.      */
746 /* Parameters: none                                                          */
747 /* Returns: the current status code                                          */
748 /*                                                                           */
749 /*****************************************************************************/
750 
getCurrentStatusCode()751     public int getCurrentStatusCode()
752     {
753         try{
754             return lastRequest.getStatusCode();
755         }catch (NullPointerException e){
756             // no previous requests
757         }
758         return -1;
759     }
760 
761 /*****************************************************************************/
762 /*                                                                           */
763 /* Method: getCurrentStatusText                                              */
764 /* Description: get the status message of the last request of the session.   */
765 /* Parameters: none                                                          */
766 /* Returns: the current status message                                       */
767 /*                                                                           */
768 /*****************************************************************************/
769 
getCurrentStatusText()770     public String getCurrentStatusText()
771     {
772         try{
773             return lastRequest.getStatusText();
774         }catch (NullPointerException e){
775             // no previous requests
776         }
777         return "";
778     }
779 
780 /*****************************************************************************/
781 /*                                                                           */
782 /* Method: getCurrentStatus                                                  */
783 /* Description: get the status of the last request of the session.           */
784 /* Parameters: none                                                          */
785 /* Returns: the current status                                               */
786 /*                                                                           */
787 /*****************************************************************************/
788 
getCurrentStatus()789     public String getCurrentStatus()
790     {
791 
792         int rc = getCurrentStatusCode();
793         String rm = getCurrentStatusText();
794         return rc + "\n" + rm;
795     }
796 
797 /*****************************************************************************/
798 /*                                                                           */
799 /* Method: getCookiePolicy                                                   */
800 /* Description: get the cookie handling policy for this session.             */
801 /* Parameters: none                                                          */
802 /* Returns: the cookie handling policy                                       */
803 /*                                                                           */
804 /*****************************************************************************/
805 
getCookiePolicy()806     public String getCookiePolicy()
807     {
808         return session.getParams().getCookiePolicy();
809     }
810 
811 /*****************************************************************************/
812 /*                                                                           */
813 /* Method: setCookiePolicy                                                   */
814 /* Description: set the cookie handling policy for this session.  If an      */
815 /*              invalid policy is selected the DEFAULT policy is set.        */
816 /*              Valid types: NETSCAPE, RFC2109, BROWSER, IGNORE              */
817 /*              Default policy is RFC2109.                                   */
818 /* Parameters: policy - the new cookie handling policy for the session.      */
819 /* Returns: void                                                             */
820 /*                                                                           */
821 /*****************************************************************************/
822 
setCookiePolicy(String policy)823     public void setCookiePolicy(String policy)
824     {
825         CookieAccess.setCookiePolicy(policy, session);
826     }
827 
828 /*****************************************************************************/
829 /*                                                                           */
830 /* Method: getCookieNames                                                    */
831 /* Description: get a list of cookies associated with this session.          */
832 /* Parameters: none                                                          */
833 /* Returns: a list of cookies associated with this session                   */
834 /*                                                                           */
835 /*****************************************************************************/
836 
getCookieNames()837     public Vector getCookieNames()
838     {
839         return CookieAccess.getCookieNames(session);
840     }
841 
842 /*****************************************************************************/
843 /*                                                                           */
844 /* Method: getCookieValue                                                    */
845 /* Description: get the value of the cookie with the specified name.         */
846 /*              This may need to change to get cookie summary to obtain      */
847 /*              domain and path information about a specific cookie.         */
848 /* Parameters: name - the name of the cookie                                 */
849 /* Returns: the value of the specified cookie.                               */
850 /*                                                                           */
851 /*****************************************************************************/
852 
getCookieValue(String name)853     public String getCookieValue(String name) throws InvalidCookieIDException
854     {
855         return CookieAccess.getCookieValue(name, session);
856     }
857 
858 /*****************************************************************************/
859 /*                                                                           */
860 /* Method: setCookieValue                                                    */
861 /* Description: sets the value of the specifed cookie to the specified value */
862 /* Parameters: name - name of the cookie                                     */
863 /*             value - new value for the cookie                              */
864 /* Returns: void                                                             */
865 /* Throws: InvalidCookieIDException if the cookie does not exist             */
866 /*                                                                           */
867 /*****************************************************************************/
868 
setCookieValue(String name, String value)869     public void setCookieValue (String name, String value)
870                                 throws InvalidCookieIDException
871     {
872         CookieAccess.setCookieValue(name, value, session);
873 
874     }
875 
876 /*****************************************************************************/
877 /*                                                                           */
878 /* Method: addCookie                                                         */
879 /* Description: Add a new cookie to the session.  This may need more         */
880 /*              parameters if path and domain are to be specified.           */
881 /* Parameters: name - name of the cookie                                     */
882 /*             value - new value for the cookie                              */
883 /* Returns: void                                                             */
884 /*                                                                           */
885 /*****************************************************************************/
886 
addCookie(String name, String value)887     public void addCookie(String name, String value)
888     {
889         CookieAccess.addCookie(CookieAccess.createCookie(name,value), session);
890     }
891 
892 /*****************************************************************************/
893 /*                                                                           */
894 /* Method: deleteCookie                                                      */
895 /* Description: Delete the specified cookie from the session.  If the cookie */
896 /*              does not exist, no error is declared.                        */
897 /* Parameters: name - name of the cookie                                     */
898 /* Returns: void                                                             */
899 /*                                                                           */
900 /*****************************************************************************/
901 
deleteCookie(String name)902     public void deleteCookie(String name) throws InvalidCookieIDException
903     {
904         CookieAccess.deleteCookie(name, session);
905     }
906 
907 /*****************************************************************************/
908 /*                                                                           */
909 /* Method: summarizeCookie                                                   */
910 /* Description: Get the information about a cookie.  If the cookie is not in */
911 /*              the session throw an InvalidElementException.                */
912 /* Parameters: name - name of the cookie                                     */
913 /* Returns: description of the cookie                                        */
914 /*                                                                           */
915 /*****************************************************************************/
916 
summarizeCookie(String name)917     public HashMap summarizeCookie(String name) throws
918                             InvalidCookieIDException
919     {
920         return CookieAccess.getCookieSummary(name, session);
921     }
922 
923 /*****************************************************************************/
924 /*                                                                           */
925 /* Method: listCookies                                                       */
926 /* Description: return a summary of all cookies in the current page          */
927 /* Parameters: None                                                          */
928 /* Returns: the summary of all cookies in the current page                   */
929 /*                                                                           */
930 /*****************************************************************************/
listCookies()931     public HashMap[] listCookies()
932     {
933         return CookieAccess.listCookies(session);
934     }
935 
936 /*****************************************************************************/
937 /*                                                                           */
938 /* Method: findLink                                                          */
939 /* Description: Find the specified link in the current page.  If the link is */
940 /*              not in the page or an invalid id type or an invalid value    */
941 /*              was specified throw an InvalidElementException.              */
942 /* Parameters: linkID - the identified for the link                          */
943 /*             idType - the type of id used to identify the link             */
944 /*                      ID_ID_TYPE and NAME_ID_TYPE are accepted             */
945 /* Returns: the link                                                         */
946 /*                                                                           */
947 /*****************************************************************************/
948 
findLink(String linkID, int idType)949     protected WebLink findLink(String linkID, int idType)
950                                 throws InvalidElementIDException
951     {
952         if (idType == ID_ID_TYPE)
953             return parser.getLinkByID(linkID);
954 
955         if (idType == NAME_ID_TYPE)
956             return parser.getLinkByName(linkID);
957 
958         if (idType == INDEX_ID_TYPE)
959         {
960             // Make sure specified index is numeric
961             try
962             {
963                 int index = (new Integer(linkID)).intValue();
964             }catch (NumberFormatException e)
965             {
966                 throw new InvalidElementIDException(
967                     linkID, "LINK INDEX " + linkID + " is not an integer");
968             }
969 
970             return parser.getLinkByIndex(Integer.parseInt(linkID));
971         }
972 
973         throw new InvalidElementIDException(linkID, "Bad ID Type.");
974     }
975 
976 /*****************************************************************************/
977 /*                                                                           */
978 /* Method: summarizeLink                                                     */
979 /* Description: Get the information about a link.  If the link is not in the */
980 /*              page or an invalid id type was specified throw an            */
981 /*              InvalidElementException.                                     */
982 /* Parameters: linkID - the identified for the link                          */
983 /*             idType - the type of id used to identify the link             */
984 /*                      ID_ID_TYPE and NAME_ID_TYPE are accepted             */
985 /* Returns: description of the link.                                         */
986 /*                                                                           */
987 /*****************************************************************************/
988 
summarizeLink(String linkID, int idType)989     public HashMap summarizeLink(String linkID, int idType) throws
990                             InvalidElementIDException
991     {
992         WebLink link = findLink(linkID, idType);
993 
994         try
995         {
996             return link.getSummary();
997 
998         }catch (NullPointerException e)
999         {
1000             throw new InvalidElementIDException (linkID, "Link " + linkID);
1001         }
1002     }
1003 
1004 /*****************************************************************************/
1005 /*                                                                           */
1006 /* Method: listLinks                                                         */
1007 /* Description: return a summary of all links in the current page            */
1008 /* Parameters: None                                                          */
1009 /* Returns: the summary of all links in the current page                     */
1010 /*                                                                           */
1011 /*****************************************************************************/
listLinks()1012     public HashMap[] listLinks()
1013     {
1014         return parser.listLinks();
1015     }
1016 
1017 /*****************************************************************************/
1018 /*                                                                           */
1019 /* Method: followLink                                                        */
1020 /* Description: Send the session to the target of the specified link in the  */
1021 /*              current page.  If the link is not in the page or an invalid  */
1022 /*              id type was specified throw an InvalidElementException.      */
1023 /* Parameters: linkID - the identified for the link                          */
1024 /*             idType - the type of id used to identify the link             */
1025 /*                      ID_ID_TYPE and NAME_ID_TYPE are accepted             */
1026 /* Returns: void                                                             */
1027 /*                                                                           */
1028 /*****************************************************************************/
1029 
followLink(String linkID, int idType, Boolean redirect)1030     public void followLink(String linkID, int idType, Boolean redirect) throws
1031         InvalidElementIDException, MalformedURLException, IOException,
1032         STAFException
1033     {
1034         WebLink link = findLink(linkID, idType);
1035 
1036         try
1037         {
1038             HashMap request = link.getRequest();
1039             request.put(REQUEST_REDIRECT, redirect);
1040 
1041             requestMethod(request);
1042 
1043         }catch (NullPointerException e)
1044         {
1045             throw new InvalidElementIDException (linkID, "Link " + linkID);
1046         }
1047     }
1048 
1049 /*****************************************************************************/
1050 /*                                                                           */
1051 /* Method: findForm                                                          */
1052 /* Description: Find the specified form in the current page.  If the form is */
1053 /*              not in the page or an invalid id type was specified throw an */
1054 /*              InvalidElementException.                                     */
1055 /* Parameters: formID - the identified for the form                          */
1056 /*             idType - the type of id used to identify the form             */
1057 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1058 /*                      accepted                                             */
1059 /* Returns: the form                                                         */
1060 /*                                                                           */
1061 /*****************************************************************************/
1062 
findForm(String formID, int idType)1063     protected WebForm findForm(String formID, int idType)
1064                                 throws InvalidElementIDException
1065     {
1066         if (idType == NAME_ID_TYPE)
1067             return parser.getFormByName(formID);
1068 
1069         if (idType == ID_ID_TYPE)
1070             return parser.getFormByID(formID);
1071 
1072         if (idType == INDEX_ID_TYPE)
1073         {
1074             // Make sure specified index is numeric
1075             try
1076             {
1077                 int index = (new Integer(formID)).intValue();
1078             }catch (NumberFormatException e)
1079             {
1080                 throw new InvalidElementIDException(
1081                     formID, "FORM INDEX " + formID + " is not an integer");
1082             }
1083 
1084             return parser.getFormByIndex(Integer.parseInt(formID));
1085         }
1086 
1087         throw new InvalidElementIDException(formID, "Bad ID Type.");
1088     }
1089 
1090 /*****************************************************************************/
1091 /*                                                                           */
1092 /* Method: getFormControlIDs                                                 */
1093 /* Description: Get the control ids in the specified form in the current     */
1094 /*              page.  If the form is not in the page or an invalid id type  */
1095 /*              was specified throw an InvalidElementException.              */
1096 /* Parameters: formID - the identified for the form                          */
1097 /*             idType - the type of id used to identify the form             */
1098 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1099 /*                      accepted                                             */
1100 /* Returns: a list of control ID's                                           */
1101 /*                                                                           */
1102 /*****************************************************************************/
1103 
getFormControlIDs(String formID, int idType)1104     public String[] getFormControlIDs(String formID, int idType)
1105                                    throws InvalidElementIDException
1106     {
1107         WebForm form = findForm(formID, idType);
1108         return form.getParameterKeyList();
1109     }
1110 
1111 /*****************************************************************************/
1112 /*                                                                           */
1113 /* Method: setFormElement                                                    */
1114 /* Description: Set the value of the specified control in the specified form */
1115 /*              in the current page.  If the form is not in the page or an   */
1116 /*              invalid id type was specified or an invalid control name was */
1117 /*              specified throw an InvalidElementException.                  */
1118 /* Parameters: formID - the identified for the form                          */
1119 /*             idType - the type of id used to identify the form             */
1120 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1121 /*                      accepted                                             */
1122 /*             elementID - the id of the control                             */
1123 /*             value - the value ot assign to the control                    */
1124 /* Returns: void                                                             */
1125 /*                                                                           */
1126 /*****************************************************************************/
1127 
setFormElement(String formID, int idType, String elementID, String value)1128     public void setFormElement(String formID, int idType,    String elementID,
1129                                 String value) throws InvalidElementIDException,
1130                                                 InvalidParameterValueException
1131     {
1132         WebForm form = findForm(formID, idType);
1133 
1134         try
1135         {
1136             form.setParameterValue(elementID, value);
1137 
1138         }catch (NullPointerException e)
1139         {
1140             throw new InvalidElementIDException (formID, "Form " + formID);
1141         }
1142     }
1143 
1144 /*****************************************************************************/
1145 /*                                                                           */
1146 /* Method: summarizeForm                                                     */
1147 /* Description: Get the information about a form.  If the form is not in the */
1148 /*              page or an invalid id type was specified throw an            */
1149 /*              InvalidElementException.                                     */
1150 /* Parameters: formID - the identified for the form                          */
1151 /*             idType - the type of id used to identify the form             */
1152 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1153 /*                      accepted                                             */
1154 /* Returns: description of the form.                                         */
1155 /*                                                                           */
1156 /*****************************************************************************/
1157 
summarizeForm(String formID, int idType)1158     public HashMap summarizeForm(String formID, int idType) throws
1159                             InvalidElementIDException
1160     {
1161         WebForm form = findForm (formID, idType);
1162 
1163         try
1164         {
1165             return form.getSummary();
1166 
1167         }catch (NullPointerException e)
1168         {
1169             throw new InvalidElementIDException (formID, "Form " + formID);
1170         }
1171     }
1172 
1173 /*****************************************************************************/
1174 /*                                                                           */
1175 /* Method: summarizeFormElement                                              */
1176 /* Description: Get the information about a form control.  If the form is not*/
1177 /*              in the page or an invalid id type was specified throw an     */
1178 /*              InvalidElementException.                                     */
1179 /* Parameters: formID - the identified for the form                          */
1180 /*             idType - the type of id used to identify the form             */
1181 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1182 /*                      accepted                                             */
1183 /*             formControlKey - the key used to identify the form contorl    */
1184 /* Returns: description of the form.                                         */
1185 /*                                                                           */
1186 /*****************************************************************************/
1187 
summarizeFormControl(String formID, int idType, String formControlKey)1188     public HashMap summarizeFormControl(String formID, int idType,
1189                                         String formControlKey) throws
1190                             InvalidElementIDException
1191     {
1192         WebForm form = findForm (formID, idType);
1193 
1194         try
1195         {
1196             return form.getParameterSummary(formControlKey);
1197 
1198         }catch (NullPointerException e)
1199         {
1200             throw new InvalidElementIDException (formID, "Form " + formID);
1201         }
1202     }
1203 /*****************************************************************************/
1204 /*                                                                           */
1205 /* Method: listForms                                                         */
1206 /* Description: return a summary of all forms in the current page            */
1207 /* Parameters: None                                                          */
1208 /* Returns: the summary of all forms in the current page                     */
1209 /*                                                                           */
1210 /*****************************************************************************/
listForms()1211     public HashMap[] listForms()
1212     {
1213         return parser.listForms();
1214     }
1215 
1216 /*****************************************************************************/
1217 /*                                                                           */
1218 /* Method: getFormElement                                                    */
1219 /* Description: Get the value of the specified control in the specified form */
1220 /*              in the current page.  If the form is not in the page or an   */
1221 /*              invalid id type was specified or an invalid control name was */
1222 /*              specified throw an InvalidElementException.                  */
1223 /* Parameters: formID - the identified for the form                          */
1224 /*             idType - the type of id used to identify the form             */
1225 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1226 /*                      accepted                                             */
1227 /*             elementID - the id of the control                             */
1228 /* Returns: the value of the specified control                               */
1229 /*                                                                           */
1230 /*****************************************************************************/
1231 
getFormElement(String formID, int idType, String elementID)1232     public String getFormElement(String formID, int idType,    String elementID)
1233                                 throws InvalidElementIDException
1234     {
1235         String value = null;
1236 
1237         WebForm form = findForm(formID, idType);
1238 
1239         try
1240         {
1241             value = form.getParameterValue(elementID);
1242 
1243         }catch (NullPointerException e)
1244         {
1245             throw new InvalidElementIDException (formID, "Form " + formID);
1246         }
1247 
1248         return value;
1249     }
1250 
1251 /*****************************************************************************/
1252 /*                                                                           */
1253 /* Method: submitForm                                                        */
1254 /* Description: Submit the specified form in the current page.  If the form  */
1255 /*              is not in the page or an invalid id type was specified       */
1256 /*              specified throw an InvalidElementException.                  */
1257 /* Parameters: formID - the identified for the form                          */
1258 /*             idType - the type of id used to identify the form             */
1259 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1260 /*                      accepted                                             */
1261 /* Returns: void                                                             */
1262 /*                                                                           */
1263 /*****************************************************************************/
1264 
submitForm(String formID, int idType, Boolean redirect)1265     public void submitForm(String formID, int idType, Boolean redirect) throws
1266         MalformedURLException, IOException, FileNotFoundException,
1267         InvalidElementIDException, STAFException
1268     {
1269         WebForm form = findForm(formID, idType);
1270 
1271         try
1272         {
1273             HashMap request = form.getRequest();
1274             request.put(REQUEST_REDIRECT, redirect);
1275 
1276             requestMethod(request);
1277 
1278         }catch (NullPointerException e)
1279         {
1280             throw new InvalidElementIDException (formID, "Form " + formID);
1281         }
1282     }
1283 
1284 /*****************************************************************************/
1285 /*                                                                           */
1286 /* Method: resetForm                                                         */
1287 /* Description: Reset the specified form in the current page.  If the form   */
1288 /*              is not in the page or an invalid id type was specified       */
1289 /*              specified throw an InvalidElementException.                  */
1290 /* Parameters: formID - the identified for the form                          */
1291 /*             idType - the type of id used to identify the form             */
1292 /*                      ID_ID_TYPE INDEX_ID_TYPE and NAME_ID_TYPE are        */
1293 /*                      accepted                                             */
1294 /* Returns: void                                                             */
1295 /*                                                                           */
1296 /*****************************************************************************/
1297 
resetForm(String formID, int idType)1298     public void resetForm(String formID, int idType)
1299                             throws InvalidElementIDException
1300     {
1301         WebForm form = findForm(formID, idType);
1302 
1303         try
1304         {
1305             form.reset();
1306 
1307         }catch (NullPointerException e)
1308         {
1309             throw new InvalidElementIDException (formID, "Form " + formID);
1310         }
1311     }
1312 
1313 /*****************************************************************************/
1314 /*                                                                           */
1315 /* Method: setRequestHeader                                                  */
1316 /* Description: Set the request to include the header specified.  If the     */
1317 /*              header is already part of the request it is replaced by the  */
1318 /*              new value.  If it is not present it is added.                */
1319 /* Parameters: request - this is the request for the header                  */
1320 /*             header - this is the header to be set                         */
1321 /* Returns: void                                                             */
1322 /*                                                                           */
1323 /*****************************************************************************/
1324 
setRequestHeader(HttpMethodBase request, Header header)1325     protected void setRequestHeader(HttpMethodBase request,
1326                                       Header header)
1327     {
1328         // this is a case insensitive match
1329         Header h = request.getRequestHeader(header.getName());
1330 
1331         if (h == null)
1332             request.addRequestHeader(header);
1333         else
1334             request.setRequestHeader(header);
1335     }
1336 
1337 /*****************************************************************************/
1338 /*                                                                           */
1339 /* Method: requestMethod                                                     */
1340 /* Description: submit the http request described                            */
1341 /* Parameters: data - hash map containing the components of the request      */
1342 /* Returns: void                                                             */
1343 /*                                                                           */
1344 /*****************************************************************************/
1345 
requestMethod(HashMap data)1346     public void requestMethod(HashMap data)throws MalformedURLException,
1347         IOException, FileNotFoundException, STAFException
1348 
1349     {
1350         requestMethod((String)data.get(REQUEST_URL),
1351                       (String)data.get(REQUEST_METHOD),
1352                       (HashMap)data.get(REQUEST_HEADERS),
1353                       (Vector)data.get(REQUEST_PARAMETERS),
1354                       (Vector)data.get(REQUEST_FILES),
1355                       (String)data.get(REQUEST_CONTENT),
1356                       (Boolean)data.get(REQUEST_REDIRECT),
1357                       null, null, false);
1358     }
1359 
1360 /*****************************************************************************/
1361 /*                                                                           */
1362 /* Method: requestMethod                                                     */
1363 /* Description: submit the http request described                            */
1364 /* Parameters: targetURL - the target url for this request                   */
1365 /*             method - the method of the http request                       */
1366 /*             headers - the headers to submit with the http request         */
1367 /*             params - the parameters to submit with the http request       */
1368 /*             files - a list of file names and associed parameter names to  */
1369 /*                     submit with the http request                          */
1370 /*             content - the body of the http request if no files or         */
1371 /*                       parameters were specified                           */
1372 /*             redirect - indicates whether to follow redirects              */
1373 /*             toFile - specifies the fully-qualified name of a file where   */
1374 /*                      the response should be stored (or null if not        */
1375 /*                      specified)                                           */
1376 /*             toMachine - specifies the machine that should be used to      */
1377 /*                         store the toFile (or null if not specified)       */
1378 /*             urlEncoded - specifies whether the targetURL is already       */
1379 /*                          escape-encoded (aka percent-encoded)             */
1380 /* Returns: void                                                             */
1381 /*                                                                           */
1382 /*****************************************************************************/
1383 
requestMethod(String targetURL, String method, HashMap headers, Vector params, Vector files, String content, Boolean redirect, String toFile, String toMachine, boolean urlEncoded)1384     public void requestMethod(String targetURL, String method,
1385                                       HashMap headers, Vector params,
1386                                       Vector files, String content,
1387                                       Boolean redirect,
1388                                       String toFile, String toMachine,
1389                                       boolean urlEncoded)
1390     throws MalformedURLException, IOException, FileNotFoundException,
1391         STAFException
1392     {
1393         // clean up the url and make it absolute
1394         targetURL = resolveUrl(targetURL, urlEncoded);
1395 
1396         // check to see if pre-emptive authentication is possible.
1397         session.getParams().setAuthenticationPreemptive(false);
1398         // strip off the protocol
1399         String host = targetURL.substring(targetURL.indexOf("://") + 3);
1400 
1401         Iterator it = authenticationSets.keySet().iterator();
1402 
1403         // match the current host with one in the list of automatic authenticators
1404         //  if it exists
1405         while(it.hasNext())
1406         {
1407             String key = (String) it.next();
1408             if (host.startsWith(key))
1409             try
1410             {
1411                 session.getParams().setAuthenticationPreemptive(true);
1412                 String [] values = getAuthenticationSetValues(key);
1413                 Credentials creds = new NTCredentials
1414                                         (values[0], values[1], key, values[2]);
1415 
1416                 //session.getState().setCredentials(null, key, creds);
1417                 session.getState().setCredentials(new AuthScope(
1418                     key, AuthScope.ANY_PORT, AuthScope.ANY_REALM), creds);
1419             }
1420             catch (InvalidElementIDException e)
1421             {
1422                 /* do nothing this won't be thrown since key is gotten from a list of
1423                 existing keys */
1424             }
1425         }
1426 
1427         releaseConnection();
1428 
1429         // purge expired cookies
1430         java.util.Date now = new java.util.Date();
1431         CookieAccess.purgeExpiredCookies(now, session);
1432 
1433         // create request
1434         try{
1435             if (method.equalsIgnoreCase("GET"))
1436             {
1437                 lastRequest = new GetMethod (targetURL);
1438                 // allow for parameters
1439                 if (content == null)
1440                     content = "";
1441                 content = "?" + content;
1442             }
1443             else if (method.equalsIgnoreCase("HEAD"))
1444                 lastRequest = new HeadMethod (targetURL);
1445             else if (method.equalsIgnoreCase("TRACE"))
1446                 lastRequest = new TraceMethod (targetURL);
1447             else if (method.equalsIgnoreCase("OPTIONS"))
1448                 lastRequest = new OptionsMethod (targetURL);
1449             else if (method.equalsIgnoreCase("DELETE"))
1450                 lastRequest = new DeleteMethod (targetURL);
1451             else if (method.equalsIgnoreCase("PUT"))
1452                 lastRequest = new PutMethod (targetURL);
1453             else if (method.equalsIgnoreCase("POST"))
1454                 lastRequest = new PostMethod (targetURL);
1455         }catch (java.lang.IllegalArgumentException e)
1456         {
1457             // - when URI is invalid
1458             throw new MalformedURLException("Invalid URI " + targetURL);
1459         }
1460         catch(java.lang.IllegalStateException e)
1461         {
1462             //- when protocol of the absolute URI is not recognised
1463             throw new MalformedURLException("Invalid protocol " + targetURL);
1464         }
1465 
1466         if (lastRequest == null)
1467             throw new MalformedURLException("Bad Method");
1468 
1469         // set default headers
1470         it = defaultHeaders.keySet().iterator();
1471         while(it.hasNext())
1472         {
1473             String key = (String) it.next();
1474             String value = (String) defaultHeaders.get(key);
1475             setRequestHeader(lastRequest, new Header(key, value));
1476         }
1477 
1478         // set requested headers
1479         if (headers != null)
1480         {
1481             it = headers.keySet().iterator();
1482 
1483             while(it.hasNext())
1484             {
1485                 String key = (String) it.next();
1486                 String value = (String) headers.get(key);
1487                 setRequestHeader(lastRequest, new Header(key, value));
1488             }
1489         }
1490 
1491         // Add parameters
1492 
1493         NameValuePair[] pairs = null;
1494 
1495         if (params != null)
1496         {
1497             int numParams = params.size();
1498             pairs = new NameValuePair[numParams];
1499 
1500             for (int i = 0; i < numParams; i++)
1501             {
1502                 Vector pair = (Vector)params.elementAt(i);
1503                 String key = (String)pair.elementAt(0);
1504                 String value = STAFUtil.removePrivacyDelimiters(
1505                     (String)pair.elementAt(1));
1506 
1507                 if (PostMethod.class == lastRequest.getClass())
1508                 {
1509                     ((PostMethod)lastRequest).addParameter(key, value);
1510                 }
1511                 else
1512                 {
1513                     // Need to url encode key and value
1514                     pairs[i] = new NameValuePair (key, value);
1515                 }
1516             }
1517         }
1518 
1519         // Add files, parameters, or content
1520 
1521         try
1522         {
1523             if (files != null)
1524             {
1525                 // This indicates a Multipart POST method
1526 
1527                 // The Multipart POST method uses a different request body
1528                 // format (e.g. MultipartRequestEntity) than a POST method.
1529 
1530                 int numFiles = files.size();
1531                 Part[] parts = new Part[numFiles];
1532 
1533                 // Add files to parts array
1534 
1535                 for (int i = 0; i < numFiles; i++)
1536                 {
1537                     Vector pair = (Vector)files.elementAt(i);
1538                     String key = (String)pair.elementAt(0);
1539                     String value = (String)pair.elementAt(1);
1540 
1541                     // Note: The key is not currently used.
1542                     // I think Blake used a key in case support for
1543                     // CONTENTFILEMACHINE was added in the future so that the
1544                     // key could be used to match a CONTENTFILE option to a
1545                     // CONTENTFILEMACHINE option.
1546 
1547                     try
1548                     {
1549                         parts[i] = new FilePart(value, new File(value));
1550                     }
1551                     catch (FileNotFoundException e)
1552                     {
1553                         // Error in getting file to be added to a post
1554 
1555                         String errMsg = " specified for INPUT FILE form " +
1556                             "control:\n";
1557 
1558                         if (value.equals(""))
1559                             errMsg = "No value" + errMsg;
1560                         else
1561                             errMsg = "Invalid value" + errMsg;
1562 
1563                         throw new FileNotFoundException(
1564                             errMsg + "  <INPUT type=\"file\" name=\"" + key +
1565                             "\" value=\"" + value + "\" ...>" +
1566                             "\nFileNotFoundException message: " +
1567                             e.getMessage());
1568                     }
1569                 }
1570 
1571                 ((PostMethod)lastRequest).setRequestEntity(
1572                     new MultipartRequestEntity(parts, lastRequest.getParams()));
1573             }
1574             else if ((params != null) &&
1575                      (GetMethod.class == lastRequest.getClass()))
1576             {
1577                 try
1578                 {
1579                     // XXX: May need to change the encoding based on codepage
1580                     content += EncodingUtil.formUrlEncode(
1581                         pairs, "ISO-8859-1") +
1582                         " "; // Pad with a space to counter space stripping
1583                 }
1584                 catch (HttpClientError uee)
1585                 {
1586                     throw new MalformedURLException(uee.getMessage());
1587                 }
1588             }
1589             else if (content != null)
1590             {
1591                 if (method.equalsIgnoreCase("GET"))
1592                 {
1593                     if (! content.equals("?"))
1594                     // pad content and don't try to include it in the body
1595                         content += " ";
1596                 }
1597                 else
1598                 {
1599                     ((EntityEnclosingMethod)lastRequest).setRequestEntity(
1600                         new StringRequestEntity(content));
1601                 }
1602             }
1603         }
1604         catch (ClassCastException e)
1605         {
1606             //  the error indicates that invalid options were specified on the
1607             //   requested method, a request of this type cannot include a body
1608 
1609             String msg = " Methods of type " + method + " cannot send " ;
1610 
1611             if (files != null)
1612                 msg += "files";
1613             else if (params != null)
1614                 msg += "parameters";
1615             else if (content != null)
1616                 msg += "body content";
1617 
1618             throw new MalformedURLException(msg);
1619         }
1620 
1621         if (method.equalsIgnoreCase("GET"))
1622         {
1623             content = content.substring(0, content.length() - 1);
1624 
1625             if (!content.equals(""))
1626                 lastRequest = new GetMethod(targetURL + content);
1627         }
1628 
1629         // set auto follow redirects
1630         // do not set redirect if type is put or post - causes httpclient error
1631         boolean doRedirect = followRedirect;
1632 
1633         // override the default setting
1634         if (redirect != null)
1635             doRedirect = redirect.booleanValue();
1636 
1637         if (doRedirect &&
1638             ! method.equalsIgnoreCase("POST") &&
1639             ! method.equalsIgnoreCase("PUT") )
1640 
1641             lastRequest.setFollowRedirects(true);
1642 
1643         else
1644             lastRequest.setFollowRedirects(false);
1645 
1646         int statusCode = -1;
1647 
1648         // Retry up to 5 times for GET method requests
1649 
1650         int numTries = 5;
1651 
1652         if (method.equalsIgnoreCase("GET"))
1653         {
1654             // Create a new DefaultHttpMethodRetryHandler that retries up to
1655             // 5 times (instead of the default of 3 times) but does not retry
1656             // methods that have successfully sent their requests.
1657 
1658             DefaultHttpMethodRetryHandler retryHandler =
1659                 new DefaultHttpMethodRetryHandler(numTries, false);
1660 
1661             session.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
1662                                              retryHandler);
1663         }
1664 
1665         // Submit request
1666         try
1667         {
1668             if (HTTP.DEBUG)
1669                 System.out.println(
1670                     "WebSession.requestMethod(): Before " +
1671                     "session.executeMethod(lastRequest)");
1672 
1673             statusCode = session.executeMethod(lastRequest);
1674 
1675             if (HTTP.DEBUG)
1676                 System.out.println(
1677                     "WebSession: requestMethod(): After " +
1678                     "session.executeMethod(lastRequest)");
1679         }
1680         catch (URIException e)
1681         {
1682             // Indicates bad URL
1683             // Is this redundant with the constructor exception ?
1684             throw new MalformedURLException("Invalid URI " + targetURL);
1685         }
1686         catch (HttpException e)
1687         {
1688             // Indicates the request failed
1689             throw e;
1690         }
1691         catch (IOException e)
1692         {
1693             // Indicates page failed to download
1694             throw e;
1695         }
1696         catch (java.lang.IllegalArgumentException e)
1697         {
1698             // When URI is invalid
1699             throw new MalformedURLException("Invalid URI " + targetURL);
1700         }
1701         catch (java.lang.IllegalStateException e)
1702         {
1703             // When protocol of the absolute URI is not recognized
1704             throw new MalformedURLException("Invalid protocol " + targetURL);
1705         }
1706 
1707         if (statusCode == -1)
1708             throw new HttpException ("Request Failed: Unknown Reason");
1709 
1710         if (doRedirect && (statusCode > 299) && (statusCode < 400))
1711         {
1712             // this was a post or put request
1713             // redirect manually
1714             Header locationHeader = lastRequest.getResponseHeader("location");
1715             if (locationHeader != null)
1716             {
1717                 String redirectLocation = locationHeader.getValue();
1718                 requestMethod(redirectLocation, "GET",
1719                               null, null, null, null,
1720                               new Boolean(true), toFile, toMachine, false);
1721             }
1722             // should not reach here because 3xx return codes should have
1723             // a location header specifying the redirect url
1724         }
1725 
1726         try
1727         {
1728             if (HTTP.DEBUG)
1729                 System.out.println(
1730                     "WebSession.requestMethod(): Before setCurrentContents(" +
1731                     "lastRequest.getResponseBodyAsStream(), " + toFile +
1732                     ", " + toMachine + ")");
1733 
1734             setCurrentContents(lastRequest.getResponseBodyAsStream(),
1735                                toFile, toMachine);
1736 
1737             if (HTTP.DEBUG)
1738                 System.out.println(
1739                     "WebSession.requestMethod(): After setCurrentContents()");
1740         }
1741         catch(IOException e)
1742         {
1743             throw e;
1744         }
1745         catch(STAFException e)
1746         {
1747             throw e;
1748         }
1749     }
1750 
1751 /*****************************************************************************/
1752 /*                                                                           */
1753 /* Method: getHttpResponse                                                   */
1754 /* Description: Generate a string containing all information generated by the*/
1755 /*              reply from the last interaction.  It corresponds to the info */
1756 /*              returned by the HTTP service 1.0.6 and earlier               */
1757 /* Parameters: none                                                          */
1758 /* Returns: a string containing the specified content from the last          */
1759 /*          interaction                                                      */
1760 /*                                                                           */
1761 /*****************************************************************************/
1762 
getHttpResponse()1763     public HashMap getHttpResponse ()
1764     {
1765         HashMap response = new HashMap();
1766 
1767         if (lastRequest == null) return response;
1768 
1769         response.put(RETURN_STATUS_CODE, Integer.toString(getCurrentStatusCode()));
1770         response.put(RETURN_STATUS_MESSAGE, getCurrentStatusText());
1771 
1772 
1773         Header heads [] = lastRequest.getResponseHeaders() ;
1774         Map headers = new HashMap();
1775 
1776         for (int i = 0; i < heads.length; i++)
1777         {
1778             // This may need to be changed to handle headers with multiple
1779             // values.
1780             headers.put(heads[i].getName(), heads[i].getValue());
1781         }
1782 
1783         response.put(RETURN_HEADERS, headers);
1784 
1785         return response;
1786     }
1787 
1788 /*****************************************************************************/
1789 /*                                                                           */
1790 /* Method: isOwner                                                           */
1791 /* Description: Determines if requester is the owner of the session by       */
1792 /* Parameters: Requester's machine, process name, and handle                 */
1793 /* Returns: true if Owner and false if not owner                             */
1794 /*                                                                           */
1795 /*****************************************************************************/
1796 
isOwner(String reqInstanceUUID)1797     public boolean isOwner(String reqInstanceUUID)
1798     {
1799         if (reqInstanceUUID.equals(ownerInstanceUUID))
1800         {
1801             return true;
1802         }
1803         else
1804         {
1805             return false;
1806         }
1807     }
1808 
1809 /*****************************************************************************/
1810 /*                                                                           */
1811 /* Method: getSummary                                                        */
1812 /* Description: get a summary of the session.                                */
1813 /* Parameters: none                                                          */
1814 /* Returns: description of a session                                         */
1815 /*                                                                           */
1816 /*****************************************************************************/
1817 
getSummary()1818     public HashMap getSummary()
1819     {
1820         HashMap summary = new HashMap();
1821 
1822         summary.put(ID,Integer.toString(id));
1823         summary.put(TITLE, getCurrentTitle());
1824         summary.put(URL, getCurrentUrl());
1825         summary.put(RETURN_STATUS_CODE, Integer.toString(getCurrentStatusCode()));
1826         summary.put(RETURN_STATUS_MESSAGE, getCurrentStatusText());
1827         summary.put(POLICY, getCookiePolicy());
1828         if (followRedirect)
1829             summary.put(REQUEST_REDIRECT, "Enabled");
1830         else
1831             summary.put(REQUEST_REDIRECT, "Disabled");
1832         summary.put(PARSE_CONTENT, fParseContent);
1833         summary.put(HTTP_PROXY_HOST,
1834                     session.getHostConfiguration().getProxyHost());
1835         summary.put(HTTP_PROXY_PORT,
1836                     new Integer(session.getHostConfiguration().getProxyPort()));
1837         summary.put(OWNER_INSTANCE_UUID, ownerInstanceUUID);
1838         summary.put(OWNER_MACHINE, ownerMachine);
1839         summary.put(OWNER_HANDLE_NAME, ownerHandleName);
1840         summary.put(OWNER_HANDLE, Integer.toString(ownerHandle));
1841 
1842         return summary;
1843     }
1844 
1845 /*****************************************************************************/
1846 /*                                                                           */
1847 /* Method: setDefaultHeader                                                  */
1848 /* Description: sets the value of the specifed default header to the         */
1849 /*              specified value                                              */
1850 /* Parameters: name - key of the header                                      */
1851 /*             value - new value for the header                              */
1852 /* Returns: void                                                             */
1853 /*                                                                           */
1854 /*****************************************************************************/
1855 
setDefaultHeader(String name, String value)1856     public void setDefaultHeader(String name, String value)
1857     {
1858         try
1859         {
1860             String key = getDefaultHeaderKey(name);
1861             defaultHeaders.put(key, value);
1862         } catch (InvalidElementIDException e)
1863         {
1864             defaultHeaders.put(name, value);
1865         }
1866     }
1867 
1868 /*****************************************************************************/
1869 /*                                                                           */
1870 /* Method: deleteDefaultHeader                                               */
1871 /* Description: remove the specifed default header                           */
1872 /* Parameters: name - key of the header                                      */
1873 /* Returns: void                                                             */
1874 /*                                                                           */
1875 /*****************************************************************************/
1876 
deleteDefaultHeader(String name)1877     public void deleteDefaultHeader(String name)
1878                                     throws InvalidElementIDException
1879     {
1880         String key = getDefaultHeaderKey(name);
1881         defaultHeaders.remove(key);
1882     }
1883 
1884 /*****************************************************************************/
1885 /*                                                                           */
1886 /* Method: getDefaultHeaderKey                                               */
1887 /* Description: get the key object of the specifed default header            */
1888 /* Parameters: name - key of the header                                      */
1889 /* Returns:  key object to access the defaultHeader HashMap                  */
1890 /*                                                                           */
1891 /*****************************************************************************/
1892 
getDefaultHeaderKey(String name)1893     public String getDefaultHeaderKey(String name)
1894                                     throws InvalidElementIDException
1895     {
1896         Iterator it = defaultHeaders.keySet().iterator();
1897 
1898         while(it.hasNext())
1899         {
1900             String key = (String) it.next();
1901             if (name.equalsIgnoreCase(key))
1902                 return key;
1903         }
1904         throw new InvalidElementIDException (name, "Header key " + name);
1905     }
1906 
1907 /*****************************************************************************/
1908 /*                                                                           */
1909 /* Method: getDefaultHeaderValue                                             */
1910 /* Description: get the value associated with the specifed default header    */
1911 /* Parameters: name - key of the header                                      */
1912 /* Returns:  value assoicated with the defaultHeader                         */
1913 /*                                                                           */
1914 /*****************************************************************************/
1915 
getDefaultHeaderValue(String name)1916     public String getDefaultHeaderValue(String name)
1917                                     throws InvalidElementIDException
1918     {
1919         String key = getDefaultHeaderKey(name);
1920 
1921         return (String)defaultHeaders.get(key);
1922     }
1923 
1924 /*****************************************************************************/
1925 /*                                                                           */
1926 /* Method: getDefaultHeaders                                                 */
1927 /* Description: get the HashMap storing the default header values            */
1928 /* Parameters: none                                                          */
1929 /* Returns: the default header HashMap                                       */
1930 /*                                                                           */
1931 /*****************************************************************************/
1932 
getDefaultHeaders()1933     public HashMap getDefaultHeaders()
1934     {
1935         return defaultHeaders;
1936     }
1937 
1938 /*****************************************************************************/
1939 /*                                                                           */
1940 /* Method: getDefaultFollowRedirect                                          */
1941 /* Description: get if the session follows 3XX redirects by default or not   */
1942 /* Parameters: none                                                          */
1943 /* Returns: if the session follows 3XX redirects by default or not           */
1944 /*                                                                           */
1945 /*****************************************************************************/
1946 
getDefaultFollowRedirect()1947     public boolean getDefaultFollowRedirect()
1948     {
1949         return followRedirect;
1950     }
1951 
1952 /*****************************************************************************/
1953 /*                                                                           */
1954 /* Method: setDefaultFollowRedirect                                          */
1955 /* Description: get if the session follows 3XX redirects by default or not   */
1956 /* Parameters: redirect - if the session follows 3XX redirects by default or */
1957 /*                        not                                                */
1958 /* Returns: void                                                             */
1959 /*                                                                           */
1960 /*****************************************************************************/
1961 
setDefaultFollowRedirect(boolean redirect)1962     public void setDefaultFollowRedirect(boolean redirect)
1963     {
1964         followRedirect = redirect;
1965     }
1966 
1967 /*****************************************************************************/
1968 /*                                                                           */
1969 /* Method: getParseContent                                                   */
1970 /* Description: Returns the value of fParseContent for the session           */
1971 /* Parameters: none                                                          */
1972 /* Returns:  A string containing Enabled, Disabled, or AutoDetect            */
1973 /*                                                                           */
1974 /*****************************************************************************/
1975 
getParseContent()1976     public String getParseContent()
1977     {
1978         return fParseContent;
1979     }
1980 
1981 /*****************************************************************************/
1982 /*                                                                           */
1983 /* Method: setParseContent                                                   */
1984 /* Description: Sets if/how the session should parse content as HTML         */
1985 /* Parameters: A string containing Enabled, Disabled, or AutoDetect, or an   */
1986 /*             invalid value                                                 */
1987 /*                                                                           */
1988 /* Returns:  STAFResult instance with RC == 0 if a valid parameter was input */
1989 /*           STAFResult instance with RC != 0 and an error message in the    */
1990 /*           result if an invalid parameter was input                        */
1991 /*                                                                           */
1992 /*****************************************************************************/
1993 
setParseContent(String parseContent)1994     public STAFResult setParseContent(String parseContent)
1995     {
1996         // Verify that Enabled, Disabled, or AutoDetect was specified,
1997         // case-insensitive
1998 
1999         if (parseContent.equalsIgnoreCase(ENABLED))
2000         {
2001             fParseContent = ENABLED;
2002         }
2003         else if (parseContent.equalsIgnoreCase(DISABLED))
2004         {
2005             fParseContent = DISABLED;
2006         }
2007         else if (parseContent.equalsIgnoreCase(AUTODETECT))
2008         {
2009             fParseContent = AUTODETECT;
2010         }
2011         else
2012         {
2013             return new STAFResult(
2014                 STAFResult.InvalidValue,
2015                 "PARSECONTENT option value must be Enabled, Disabled," +
2016                 " or AutoDetect, case-insensitive. Invalid value: " +
2017                 parseContent);
2018         }
2019 
2020         return new STAFResult(STAFResult.Ok);
2021     }
2022 
2023  /*****************************************************************************/
2024  /*                                                                           */
2025  /* Method: setHttpProxy                                                      */
2026  /* Description: sets the HTTP Proxy host and port for the session,           */
2027  /* Parameters: proxyHost - the HTTP Proxy host                               */
2028  /*             proxyPort - the HTTP Proxy port (-1 indicates to use the      */
2029  /*                         default port)                                     */
2030  /* Returns: void                                                             */
2031  /*                                                                           */
2032  /*****************************************************************************/
setHttpProxy(String proxyHost, int proxyPort)2033     public void setHttpProxy(String proxyHost, int proxyPort)
2034     {
2035         session.getHostConfiguration().setProxy(proxyHost, proxyPort);
2036     }
2037 
2038 /*****************************************************************************/
2039 /*                                                                           */
2040 /* Method: setAuthenticationSet                                              */
2041 /* Description: sets the user and password for preemptive challenges to the  */
2042 /*              host                                                         */
2043 /* Parameters: host - the host to associate with this user and password      */
2044 /*             user - the user to assciate with this host                    */
2045 /*             pwd  - the password to assciate with this host                */
2046 /* Returns: void                                                             */
2047 /*                                                                           */
2048 /*****************************************************************************/
2049 
setAuthenticationSet(String host, String user, String pwd, String domain)2050     public void setAuthenticationSet(String host, String user, String pwd,
2051                                       String domain)
2052     {
2053         String [] values = new String[3];
2054         values[0] = user;
2055         values[1] = pwd;
2056         values[2] = domain;
2057         try
2058         {
2059             String key = getAuthenticationSetKey(host);
2060             authenticationSets.put(key, values);
2061         } catch (InvalidElementIDException e)
2062         {
2063             authenticationSets.put(host, values);
2064         }
2065     }
2066 
2067 /*****************************************************************************/
2068 /*                                                                           */
2069 /* Method: deleteAuthenticationSet                                           */
2070 /* Description: remove the specifed host                                     */
2071 /* Parameters: host - the host to be removed                                 */
2072 /* Returns: void                                                             */
2073 /*                                                                           */
2074 /*****************************************************************************/
2075 
deleteAuthenticationSet(String host)2076     public void deleteAuthenticationSet(String host)
2077                                     throws InvalidElementIDException
2078     {
2079         String key = getAuthenticationSetKey(host);
2080         authenticationSets.remove(key);
2081     }
2082 
2083 /*****************************************************************************/
2084 /*                                                                           */
2085 /* Method: getAuthenticationSetKey                                           */
2086 /* Description: get the key object of the specifed host                      */
2087 /* Parameters: host - host string                                            */
2088 /* Returns: key object to access the authenticationSet HashMap               */
2089 /*                                                                           */
2090 /*****************************************************************************/
2091 
getAuthenticationSetKey(String host)2092     public String getAuthenticationSetKey(String host)
2093                                     throws InvalidElementIDException
2094     {
2095         Iterator it = authenticationSets.keySet().iterator();
2096 
2097         while(it.hasNext())
2098         {
2099             String key = (String) it.next();
2100             if (host.equalsIgnoreCase(key))
2101                 return key;
2102         }
2103         throw new InvalidElementIDException (host, "Authentication host key " + host);
2104     }
2105 
2106 /*****************************************************************************/
2107 /*                                                                           */
2108 /* Method: getAuthenticationSetValues                                        */
2109 /* Description: get the value associated with the specifed host              */
2110 /* Parameters: host - host assciated with the values                         */
2111 /* Returns:  values assoicated with the host, [0] is user, [1] is password   */
2112 /*                                                                           */
2113 /*****************************************************************************/
2114 
getAuthenticationSetValues(String host)2115     public String[] getAuthenticationSetValues(String host)
2116                                     throws InvalidElementIDException
2117     {
2118         String key = getAuthenticationSetKey(host);
2119 
2120         return (String[]) authenticationSets.get(key);
2121     }
2122 
2123 /*****************************************************************************/
2124 /*                                                                           */
2125 /* Method: getAuthenticationSets                                             */
2126 /* Description: get the HashMap storing the preemptive authentication values */
2127 /* Parameters: none                                                          */
2128 /* Returns: the authentication sets HashMap                                  */
2129 /*                                                                           */
2130 /*****************************************************************************/
2131 
getAuthenticationSets()2132     public HashMap getAuthenticationSets()
2133     {
2134         return authenticationSets;
2135     }
2136 
2137 /*****************************************************************************/
2138 /*                                                                           */
2139 /* Method: resolveUrl                                                        */
2140 /* Description: clean up the url so that it is a full and absolute url       */
2141 /* Parameters: targetURL - the url to be cleaned up                          */
2142 /*             encoded - indicates whether the url is already encoded        */
2143 /*                       (aka percent-encoded or percent-escaped)            */
2144 /* Returns: the updated URL string                                           */
2145 /*                                                                           */
2146 /*****************************************************************************/
resolveUrl(String targetURL, boolean encoded)2147     protected String resolveUrl(String targetURL, boolean encoded)
2148               throws URIException
2149     {
2150         // An instance of the URI class is always in an "escaped" (aka
2151         // "encoded") form, since escaping or unescaping a completed URI might
2152         // change its semantics.  Thus, we need to be careful not to escape or
2153         // unescape the same string more than once, since unescaping an
2154         // already unescaped string might lead to misinterpreting a percent
2155         // data character as another escaped character, or vice versa in the
2156         // case of escaping an already escaped string.
2157 
2158         URI target = new URI(targetURL, encoded);
2159         URI absolute = null;
2160         String baseURL = getCurrentUrl();
2161 
2162         if (target.isAbsoluteURI() || baseURL.equals(""))
2163         {
2164             // Set the absolute URL
2165             absolute = new URI(targetURL, encoded);
2166         }
2167         else
2168         {
2169             // Convert relative URL to an absolute URL
2170             URI base = new URI(baseURL, true);
2171             absolute = new URI(base, target);
2172         }
2173 
2174         String absoluteURL = absolute.toString();
2175 
2176         // Assume http protocol if no protocol specified
2177         if (absoluteURL.indexOf("://") == -1)
2178             absoluteURL = "http://" + absoluteURL;
2179 
2180         return absoluteURL;
2181     }
2182 
2183 }
2184 
2185