0001: /*
0002: * @(#)CookieModule.java 0.3-2 18/06/1999
0003: *
0004: * This file is part of the HTTPClient package
0005: * Copyright (C) 1996-1999 Ronald Tschalär
0006: *
0007: * This library is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU Lesser General Public
0009: * License as published by the Free Software Foundation; either
0010: * version 2 of the License, or (at your option) any later version.
0011: *
0012: * This library is distributed in the hope that it will be useful,
0013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0015: * Lesser General Public License for more details.
0016: *
0017: * You should have received a copy of the GNU Lesser General Public
0018: * License along with this library; if not, write to the Free
0019: * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
0020: * MA 02111-1307, USA
0021: *
0022: * For questions, suggestions, bug-reports, enhancement-requests etc.
0023: * I may be contacted at:
0024: *
0025: * ronald@innovation.ch
0026: *
0027: */
0028:
0029: package HTTPClient;
0030:
0031: import java.io.File;
0032: import java.io.IOException;
0033: import java.io.FileInputStream;
0034: import java.io.FileOutputStream;
0035: import java.io.ObjectInputStream;
0036: import java.io.ObjectOutputStream;
0037: import java.net.ProtocolException;
0038: import java.util.Date;
0039: import java.util.Vector;
0040: import java.util.Hashtable;
0041: import java.util.Enumeration;
0042: import java.util.StringTokenizer;
0043:
0044: import java.awt.Frame;
0045: import java.awt.Panel;
0046: import java.awt.Label;
0047: import java.awt.Color;
0048: import java.awt.Button;
0049: import java.awt.Graphics;
0050: import java.awt.Dimension;
0051: import java.awt.TextArea;
0052: import java.awt.TextField;
0053: import java.awt.GridLayout;
0054: import java.awt.GridBagLayout;
0055: import java.awt.GridBagConstraints;
0056: import java.awt.event.ActionEvent;
0057: import java.awt.event.ActionListener;
0058: import java.awt.event.WindowEvent;
0059: import java.awt.event.WindowAdapter;
0060:
0061: /**
0062: * This module handles Netscape cookies (also called Version 0 cookies)
0063: * and Version 1 cookies. Specifically is reads the <var>Set-Cookie</var>
0064: * and <var>Set-Cookie2</var> response headers and sets the <var>Cookie</var>
0065: * and <var>Cookie2</var> headers as neccessary.
0066: *
0067: * <P>The accepting and sending of cookies is controlled by a
0068: * <var>CookiePolicyHandler</var>. This allows you to fine tune your privacy
0069: * preferences. A cookie is only added to the cookie list if the handler
0070: * allows it, and a cookie from the cookie list is only sent if the handler
0071: * allows it.
0072: *
0073: * <P>A cookie jar can be used to store cookies between sessions. This file is
0074: * read when this class is loaded and is written when the application exits;
0075: * only cookies from the default context are saved. The name of the file is
0076: * controlled by the system property <var>HTTPClient.cookies.jar</var> and
0077: * defaults to a system dependent name. The reading and saving of cookies is
0078: * enabled by setting the system property <var>HTTPClient.cookies.save</var>
0079: * to <var>true</var>.
0080: *
0081: * @see <a href="http://home.netscape.com/newsref/std/cookie_spec.html">Netscape's cookie spec</a>
0082: * @see <a href="ftp://ds.internic.net/internet-drafts/draft-ietf-http-state-man-mec-10.txt">HTTP State Management Mechanism spec</a>
0083: * @version 0.3-2 18/06/1999
0084: * @author Ronald Tschalär
0085: * @since V0.3
0086: */
0087:
0088: public class CookieModule implements HTTPClientModule, GlobalConstants {
0089: /** the list of known cookies */
0090: private static Hashtable cookie_cntxt_list = new Hashtable();
0091:
0092: /** the file to use for persistent cookie storage */
0093: private static File cookie_jar = null;
0094:
0095: /** an object, whose finalizer will save the cookies to the jar */
0096: private static Object cookieSaver = null;
0097:
0098: /** the cookie policy handler */
0099: private static CookiePolicyHandler cookie_handler = new DefaultCookiePolicyHandler();
0100:
0101: // read in cookies from disk at startup
0102:
0103: static {
0104: boolean persist;
0105: try {
0106: persist = Boolean.getBoolean("HTTPClient.cookies.save");
0107: } catch (RuntimeException e) {
0108: persist = false;
0109: }
0110:
0111: if (persist) {
0112: loadCookies();
0113:
0114: // the nearest thing to atexit() I know of...
0115:
0116: cookieSaver = new Object() {
0117: public void finalize() {
0118: saveCookies();
0119: }
0120: };
0121: try {
0122: System.runFinalizersOnExit(true);
0123: } catch (Throwable t) {
0124: }
0125: }
0126: }
0127:
0128: private static void loadCookies() {
0129: // The isFile() etc need to be protected by the catch as signed
0130: // applets may be allowed to read properties but not do IO
0131: try {
0132: cookie_jar = new File(getCookieJarName());
0133: if (cookie_jar.isFile() && cookie_jar.canRead()) {
0134: ObjectInputStream ois = new ObjectInputStream(
0135: new FileInputStream(cookie_jar));
0136: cookie_cntxt_list.put(HTTPConnection
0137: .getDefaultContext(), (Hashtable) ois
0138: .readObject());
0139: ois.close();
0140: }
0141: } catch (Throwable t) {
0142: cookie_jar = null;
0143: }
0144: }
0145:
0146: private static void saveCookies()
0147: {
0148: if (cookie_jar != null && (!cookie_jar.exists() ||
0149: cookie_jar.isFile() && cookie_jar.canWrite()))
0150: {
0151: Hashtable cookie_list = new Hashtable();
0152: Enumeration enum = Util.getList(cookie_cntxt_list,
0153: HTTPConnection.getDefaultContext())
0154: .elements();
0155:
0156: // discard cookies which are not to be kept across sessions
0157:
0158: while (enum.hasMoreElements())
0159: {
0160: Cookie cookie = (Cookie) enum.nextElement();
0161: if (!cookie.discard())
0162: cookie_list.put(cookie, cookie);
0163: }
0164:
0165:
0166: // save any remaining cookies in jar
0167:
0168: if (cookie_list.size() > 0)
0169: {
0170: try
0171: {
0172: ObjectOutputStream oos =
0173: new ObjectOutputStream(new FileOutputStream(cookie_jar));
0174: oos.writeObject(cookie_list);
0175: oos.close();
0176: }
0177: catch (Throwable t)
0178: { }
0179: }
0180: }
0181: }
0182:
0183: private static String getCookieJarName() {
0184: String file = null;
0185:
0186: try {
0187: file = System.getProperty("HTTPClient.cookies.jar");
0188: } catch (RuntimeException e) {
0189: }
0190:
0191: if (file == null) {
0192: // default to something reasonable
0193:
0194: String os = System.getProperty("os.name");
0195: if (os.equalsIgnoreCase("Windows 95")
0196: || os.equalsIgnoreCase("16-bit Windows")
0197: || os.equalsIgnoreCase("Windows")) {
0198: file = System.getProperty("java.home") + File.separator
0199: + ".httpclient_cookies";
0200: } else if (os.equalsIgnoreCase("Windows NT")) {
0201: file = System.getProperty("user.home") + File.separator
0202: + ".httpclient_cookies";
0203: } else if (os.equalsIgnoreCase("OS/2")) {
0204: file = System.getProperty("user.home") + File.separator
0205: + ".httpclient_cookies";
0206: } else if (os.equalsIgnoreCase("Mac OS")
0207: || os.equalsIgnoreCase("MacOS")) {
0208: file = "System Folder" + File.separator + "Preferences"
0209: + File.separator + "HTTPClientCookies";
0210: } else // it's probably U*IX or VMS
0211: {
0212: file = System.getProperty("user.home") + File.separator
0213: + ".httpclient_cookies";
0214: }
0215: }
0216:
0217: return file;
0218: }
0219:
0220: // Constructors
0221:
0222: CookieModule() {
0223: }
0224:
0225: // Methods
0226:
0227: /**
0228: * Invoked by the HTTPClient.
0229: */
0230: public int requestHandler(Request req, Response[] resp) {
0231: // First remove any Cookie headers we might have set for a previous
0232: // request
0233:
0234: NVPair[] hdrs = req.getHeaders();
0235: int length = hdrs.length;
0236: for (int idx = 0; idx < hdrs.length; idx++) {
0237: int beg = idx;
0238: while (idx < hdrs.length
0239: && hdrs[idx].getName().equalsIgnoreCase("Cookie"))
0240: idx++;
0241:
0242: if (idx - beg > 0) {
0243: length -= idx - beg;
0244: System.arraycopy(hdrs, idx, hdrs, beg, length - beg);
0245: }
0246: }
0247: if (length < hdrs.length) {
0248: hdrs = Util.resizeArray(hdrs, length);
0249: req.setHeaders(hdrs);
0250: }
0251:
0252: // Now set any new cookie headers
0253:
0254: Hashtable cookie_list = Util.getList(cookie_cntxt_list, req
0255: .getConnection().getContext());
0256: if (cookie_list.size() == 0)
0257: return REQ_CONTINUE; // no need to create a lot of objects
0258:
0259: Vector names = new Vector();
0260: Vector lens = new Vector();
0261: boolean cookie2 = false;
0262:
0263: synchronized (cookie_list) {
0264: Enumeration list = cookie_list.elements();
0265: Vector remove_list = null;
0266:
0267: while (list.hasMoreElements()) {
0268: Cookie cookie = (Cookie) list.nextElement();
0269:
0270: if (cookie.hasExpired()) {
0271: if (remove_list == null)
0272: remove_list = new Vector();
0273: remove_list.addElement(cookie);
0274: continue;
0275: }
0276:
0277: if (cookie.sendWith(req)
0278: && (cookie_handler == null || cookie_handler
0279: .sendCookie(cookie, req))) {
0280: int len = cookie.getPath().length();
0281: int idx;
0282:
0283: // insert in correct position
0284: for (idx = 0; idx < lens.size(); idx++)
0285: if (((Integer) lens.elementAt(idx)).intValue() < len)
0286: break;
0287:
0288: names.insertElementAt(cookie.toExternalForm(), idx);
0289: lens.insertElementAt(new Integer(len), idx);
0290:
0291: if (cookie instanceof Cookie2)
0292: cookie2 = true;
0293: }
0294: }
0295:
0296: // remove any marked cookies
0297: // Note: we can't do this during the enumeration!
0298: if (remove_list != null) {
0299: for (int idx = 0; idx < remove_list.size(); idx++)
0300: cookie_list.remove(remove_list.elementAt(idx));
0301: }
0302: }
0303:
0304: if (!names.isEmpty()) {
0305: StringBuffer value = new StringBuffer();
0306:
0307: if (cookie2)
0308: value.append("$Version=\"1\"; ");
0309:
0310: value.append((String) names.elementAt(0));
0311: for (int idx = 1; idx < names.size(); idx++) {
0312: value.append("; ");
0313: value.append((String) names.elementAt(idx));
0314: }
0315: hdrs = Util.resizeArray(hdrs, hdrs.length + 1);
0316: hdrs[hdrs.length - 1] = new NVPair("Cookie", value
0317: .toString());
0318:
0319: // add Cookie2 header if necessary
0320: if (!cookie2) {
0321: int idx;
0322: for (idx = 0; idx < hdrs.length; idx++)
0323: if (hdrs[idx].getName().equalsIgnoreCase("Cookie2"))
0324: break;
0325: if (idx == hdrs.length) {
0326: hdrs = Util.resizeArray(hdrs, hdrs.length + 1);
0327: hdrs[hdrs.length - 1] = new NVPair("Cookie2",
0328: "$Version=\"1\"");
0329: }
0330: }
0331:
0332: req.setHeaders(hdrs);
0333:
0334: if (DebugMods)
0335: System.err.println("CookM: Sending cookies '" + value
0336: + "'");
0337: }
0338:
0339: return REQ_CONTINUE;
0340: }
0341:
0342: /**
0343: * Invoked by the HTTPClient.
0344: */
0345: public void responsePhase1Handler(Response resp, RoRequest req)
0346: throws IOException {
0347: String set_cookie = resp.getHeader("Set-Cookie");
0348: String set_cookie2 = resp.getHeader("Set-Cookie2");
0349: if (set_cookie == null && set_cookie2 == null)
0350: return;
0351:
0352: resp.deleteHeader("Set-Cookie");
0353: resp.deleteHeader("Set-Cookie2");
0354:
0355: if (set_cookie != null)
0356: handleCookie(set_cookie, false, req, resp);
0357: if (set_cookie2 != null)
0358: handleCookie(set_cookie2, true, req, resp);
0359: }
0360:
0361: /**
0362: * Invoked by the HTTPClient.
0363: */
0364: public int responsePhase2Handler(Response resp, Request req) {
0365: return RSP_CONTINUE;
0366: }
0367:
0368: /**
0369: * Invoked by the HTTPClient.
0370: */
0371: public void responsePhase3Handler(Response resp, RoRequest req) {
0372: }
0373:
0374: /**
0375: * Invoked by the HTTPClient.
0376: */
0377: public void trailerHandler(Response resp, RoRequest req)
0378: throws IOException {
0379: String set_cookie = resp.getTrailer("Set-Cookie");
0380: String set_cookie2 = resp.getHeader("Set-Cookie2");
0381: if (set_cookie == null && set_cookie2 == null)
0382: return;
0383:
0384: resp.deleteTrailer("Set-Cookie");
0385: resp.deleteTrailer("Set-Cookie2");
0386:
0387: if (set_cookie != null)
0388: handleCookie(set_cookie, false, req, resp);
0389: if (set_cookie2 != null)
0390: handleCookie(set_cookie2, true, req, resp);
0391: }
0392:
0393: private void handleCookie(String set_cookie, boolean cookie2,
0394: RoRequest req, Response resp) throws ProtocolException {
0395: Cookie[] cookies;
0396: if (cookie2)
0397: cookies = Cookie2.parse(set_cookie, req);
0398: else
0399: cookies = Cookie.parse(set_cookie, req);
0400:
0401: if (DebugMods) {
0402: System.err.println("CookM: Received and parsed "
0403: + cookies.length + " cookies:");
0404: for (int idx = 0; idx < cookies.length; idx++)
0405: System.err.println("CookM: Cookie " + idx + ": "
0406: + cookies[idx]);
0407: }
0408:
0409: Hashtable cookie_list = Util.getList(cookie_cntxt_list, req
0410: .getConnection().getContext());
0411: synchronized (cookie_list) {
0412: for (int idx = 0; idx < cookies.length; idx++) {
0413: Cookie cookie = (Cookie) cookie_list.get(cookies[idx]);
0414: if (cookie != null && cookies[idx].hasExpired())
0415: cookie_list.remove(cookie); // expired, so remove
0416: else // new or replaced
0417: {
0418: if (cookie_handler == null
0419: || cookie_handler.acceptCookie(
0420: cookies[idx], req, resp))
0421: cookie_list.put(cookies[idx], cookies[idx]);
0422: }
0423: }
0424: }
0425: }
0426:
0427: /**
0428: * Discard all cookies for all contexts. Cookies stored in persistent
0429: * storage are not affected.
0430: */
0431: public static void discardAllCookies() {
0432: cookie_cntxt_list.clear();
0433: }
0434:
0435: /**
0436: * Discard all cookies for the given context. Cookies stored in persistent
0437: * storage are not affected.
0438: *
0439: * @param context the context Object
0440: */
0441: public static void discardAllCookies(Object context) {
0442: Hashtable cookie_list = Util
0443: .getList(cookie_cntxt_list, context);
0444: cookie_list.clear();
0445: }
0446:
0447: /**
0448: * List all stored cookies for all contexts.
0449: *
0450: * @return an array of all Cookies
0451: * @since V0.3-1
0452: */
0453: public static Cookie[] listAllCookies() {
0454: synchronized (cookie_cntxt_list) {
0455: Cookie[] cookies = new Cookie[0];
0456: int idx = 0;
0457:
0458: Enumeration cntxt_list = cookie_cntxt_list.elements();
0459: while (cntxt_list.hasMoreElements()) {
0460: Hashtable cntxt = (Hashtable) cntxt_list.nextElement();
0461: synchronized (cntxt) {
0462: cookies = Util.resizeArray(cookies, idx
0463: + cntxt.size());
0464: Enumeration cookie_list = cntxt.elements();
0465: while (cookie_list.hasMoreElements())
0466: cookies[idx++] = (Cookie) cookie_list
0467: .nextElement();
0468: }
0469: }
0470:
0471: return cookies;
0472: }
0473: }
0474:
0475: /**
0476: * List all stored cookies for a given context.
0477: *
0478: * @param context the context Object.
0479: * @return an array of Cookies
0480: * @since V0.3-1
0481: */
0482: public static Cookie[] listAllCookies(Object context)
0483: {
0484: Hashtable cookie_list = Util.getList(cookie_cntxt_list, context);
0485:
0486: synchronized(cookie_list)
0487: {
0488: Cookie[] cookies = new Cookie[cookie_list.size()];
0489: int idx = 0;
0490:
0491: Enumeration enum = cookie_list.elements();
0492: while (enum.hasMoreElements())
0493: cookies[idx++] = (Cookie) enum.nextElement();
0494:
0495: return cookies;
0496: }
0497: }
0498:
0499: /**
0500: * Add the specified cookie to the list of cookies in the default context.
0501: * If a compatible cookie (as defined by <var>Cookie.equals()</var>)
0502: * already exists in the list then it is replaced with the new cookie.
0503: *
0504: * @param cookie the Cookie to add
0505: * @since V0.3-1
0506: */
0507: public static void addCookie(Cookie cookie) {
0508: Hashtable cookie_list = Util.getList(cookie_cntxt_list,
0509: HTTPConnection.getDefaultContext());
0510: cookie_list.put(cookie, cookie);
0511: }
0512:
0513: /**
0514: * Add the specified cookie to the list of cookies for the specified
0515: * context. If a compatible cookie (as defined by
0516: * <var>Cookie.equals()</var>) already exists in the list then it is
0517: * replaced with the new cookie.
0518: *
0519: * @param cookie the cookie to add
0520: * @param context the context Object.
0521: * @since V0.3-1
0522: */
0523: public static void addCookie(Cookie cookie, Object context) {
0524: Hashtable cookie_list = Util
0525: .getList(cookie_cntxt_list, context);
0526: cookie_list.put(cookie, cookie);
0527: }
0528:
0529: /**
0530: * Remove the specified cookie from the list of cookies in the default
0531: * context. If the cookie is not found in the list then this method does
0532: * nothing.
0533: *
0534: * @param cookie the Cookie to remove
0535: * @since V0.3-1
0536: */
0537: public static void removeCookie(Cookie cookie) {
0538: Hashtable cookie_list = Util.getList(cookie_cntxt_list,
0539: HTTPConnection.getDefaultContext());
0540: cookie_list.remove(cookie);
0541: }
0542:
0543: /**
0544: * Remove the specified cookie from the list of cookies for the specified
0545: * context. If the cookie is not found in the list then this method does
0546: * nothing.
0547: *
0548: * @param cookie the cookie to remove
0549: * @param context the context Object
0550: * @since V0.3-1
0551: */
0552: public static void removeCookie(Cookie cookie, Object context) {
0553: Hashtable cookie_list = Util
0554: .getList(cookie_cntxt_list, context);
0555: cookie_list.remove(cookie);
0556: }
0557:
0558: /**
0559: * Sets a new cookie policy handler. This handler will be called for each
0560: * cookie that a server wishes to set and for each cookie that this
0561: * module wishes to send with a request. In either case the handler may
0562: * allow or reject the operation. If you wish to blindly accept and send
0563: * all cookies then just disable the handler with
0564: * <code>CookieModule.setCookiePolicyHandler(null);</code>.
0565: *
0566: * <P>At initialization time a default handler is installed. This
0567: * handler allows all cookies to be sent. For any cookie that a server
0568: * wishes to be set two lists are consulted. If the server matches any
0569: * host or domain in the reject list then the cookie is rejected; if
0570: * the server matches any host or domain in the accept list then the
0571: * cookie is accepted (in that order). If no host or domain match is
0572: * found in either of these two lists and user interaction is allowed
0573: * then a dialog box is poped up to ask the user whether to accept or
0574: * reject the cookie; if user interaction is not allowed the cookie is
0575: * accepted.
0576: *
0577: * <P>The accept and reject lists in the default handler are initialized
0578: * at startup from the two properties
0579: * <var>HTTPClient.cookies.hosts.accept</var> and
0580: * <var>HTTPClient.cookies.hosts.reject</var>. These properties must
0581: * contain a "|" separated list of host and domain names. All names
0582: * beginning with a "." are treated as domain names, all others as host
0583: * names. An empty string which will match all hosts. The two lists are
0584: * further expanded if the user chooses one of the "Accept All from Domain"
0585: * or "Reject All from Domain" buttons in the dialog box.
0586: *
0587: * <P>Note: the default handler does not implement the rules concerning
0588: * unverifiable transactions (section 4.3.5,
0589: * <A HREF="http://www.cis.ohio-state.edu/htbin/rfc/rfc2109">RFC-2109</A>).
0590: * The reason for this is simple: the default handler knows nothing
0591: * about the application using this client, and it therefore does not
0592: * have enough information to determine when a request is verifiable
0593: * and when not. You are therefore encouraged to provide your own handler
0594: * which implements section 4.3.5 (use the
0595: * <var>CookiePolicyHandler.sendCookie</var> method for this).
0596: *
0597: * @param the new policy handler
0598: * @return the previous policy handler
0599: */
0600: public static synchronized CookiePolicyHandler setCookiePolicyHandler(
0601: CookiePolicyHandler handler) {
0602: CookiePolicyHandler old = cookie_handler;
0603: cookie_handler = handler;
0604: return old;
0605: }
0606: }
0607:
0608: /**
0609: * A simple cookie policy handler.
0610: */
0611:
0612: class DefaultCookiePolicyHandler implements CookiePolicyHandler {
0613: /** a list of all hosts and domains from which to silently accept cookies */
0614: private String[] accept_domains = new String[0];
0615:
0616: /** a list of all hosts and domains from which to silently reject cookies */
0617: private String[] reject_domains = new String[0];
0618:
0619: /** the query popup */
0620: private BasicCookieBox popup = null;
0621:
0622: DefaultCookiePolicyHandler() {
0623: // have all cookies been accepted or rejected?
0624: String list;
0625:
0626: try {
0627: list = System
0628: .getProperty("HTTPClient.cookies.hosts.accept");
0629: } catch (RuntimeException e) {
0630: list = null;
0631: }
0632: String[] domains = Util.splitProperty(list);
0633: for (int idx = 0; idx < domains.length; idx++)
0634: addAcceptDomain(domains[idx].toLowerCase());
0635:
0636: try {
0637: list = System
0638: .getProperty("HTTPClient.cookies.hosts.reject");
0639: } catch (RuntimeException e) {
0640: list = null;
0641: }
0642: domains = Util.splitProperty(list);
0643: for (int idx = 0; idx < domains.length; idx++)
0644: addRejectDomain(domains[idx].toLowerCase());
0645: }
0646:
0647: /**
0648: * returns whether this cookie should be accepted. First checks the
0649: * stored lists of accept and reject domains, and if it is neither
0650: * accepted nor rejected by these then query the user via a popup.
0651: *
0652: * @param cookie the cookie in question
0653: * @param req the request
0654: * @param resp the response
0655: * @return true if we accept this cookie.
0656: */
0657: public boolean acceptCookie(Cookie cookie, RoRequest req,
0658: RoResponse resp) {
0659: String server = req.getConnection().getHost();
0660: if (server.indexOf('.') == -1)
0661: server += ".local";
0662:
0663: // Check lists. Reject takes priority over accept
0664:
0665: for (int idx = 0; idx < reject_domains.length; idx++) {
0666: if (reject_domains[idx].length() == 0
0667: || reject_domains[idx].charAt(0) == '.'
0668: && server.endsWith(reject_domains[idx])
0669: || reject_domains[idx].charAt(0) != '.'
0670: && server.equals(reject_domains[idx]))
0671: return false;
0672: }
0673:
0674: for (int idx = 0; idx < accept_domains.length; idx++) {
0675: if (accept_domains[idx].length() == 0
0676: || accept_domains[idx].charAt(0) == '.'
0677: && server.endsWith(accept_domains[idx])
0678: || accept_domains[idx].charAt(0) != '.'
0679: && server.equals(accept_domains[idx]))
0680: return true;
0681: }
0682:
0683: // Ok, not in any list, so ask the user (if allowed).
0684:
0685: if (!req.allowUI())
0686: return true;
0687:
0688: if (popup == null)
0689: popup = new BasicCookieBox();
0690:
0691: return popup.accept(cookie, this , server);
0692: }
0693:
0694: /**
0695: * This handler just allows all cookies to be sent which were accepted
0696: * (i.e. no further restrictions are placed on the sending of cookies).
0697: *
0698: * @return true
0699: */
0700: public boolean sendCookie(Cookie cookie, RoRequest req) {
0701: return true;
0702: }
0703:
0704: void addAcceptDomain(String domain) {
0705: if (domain.indexOf('.') == -1)
0706: domain += ".local";
0707:
0708: for (int idx = 0; idx < accept_domains.length; idx++) {
0709: if (domain.endsWith(accept_domains[idx]))
0710: return;
0711: if (accept_domains[idx].endsWith(domain)) {
0712: accept_domains[idx] = domain;
0713: return;
0714: }
0715: }
0716: accept_domains = Util.resizeArray(accept_domains,
0717: accept_domains.length + 1);
0718: accept_domains[accept_domains.length - 1] = domain;
0719: }
0720:
0721: void addRejectDomain(String domain) {
0722: if (domain.indexOf('.') == -1)
0723: domain += ".local";
0724:
0725: for (int idx = 0; idx < reject_domains.length; idx++) {
0726: if (domain.endsWith(reject_domains[idx]))
0727: return;
0728: if (reject_domains[idx].endsWith(domain)) {
0729: reject_domains[idx] = domain;
0730: return;
0731: }
0732: }
0733:
0734: reject_domains = Util.resizeArray(reject_domains,
0735: reject_domains.length + 1);
0736: reject_domains[reject_domains.length - 1] = domain;
0737: }
0738: }
0739:
0740: /**
0741: * A simple popup that asks whether the cookie should be accepted or rejected,
0742: * or if cookies from whole domains should be silently accepted or rejected.
0743: *
0744: * @version 0.3-2 18/06/1999
0745: * @author Ronald Tschalär
0746: */
0747: class BasicCookieBox extends Frame {
0748: private final static String title = "Set Cookie Request";
0749: private Dimension screen;
0750: private GridBagConstraints constr;
0751: private Label name_value_label;
0752: private Label domain_value;
0753: private Label ports_label;
0754: private Label ports_value;
0755: private Label path_value;
0756: private Label expires_value;
0757: private Label discard_note;
0758: private Label secure_note;
0759: private Label c_url_note;
0760: private Panel left_panel;
0761: private Panel right_panel;
0762: private Label comment_label;
0763: private TextArea comment_value;
0764: private TextField domain;
0765: private Button default_focus;
0766: private boolean accept;
0767: private boolean accept_domain;
0768:
0769: /**
0770: * Constructs the popup.
0771: */
0772: BasicCookieBox() {
0773: super (title);
0774:
0775: screen = getToolkit().getScreenSize();
0776:
0777: addNotify();
0778: addWindowListener(new Close());
0779:
0780: GridBagLayout layout;
0781: setLayout(layout = new GridBagLayout());
0782: constr = new GridBagConstraints();
0783:
0784: constr.gridwidth = GridBagConstraints.REMAINDER;
0785: constr.anchor = GridBagConstraints.WEST;
0786: add(new Label(
0787: "The server would like to set the following cookie:"),
0788: constr);
0789:
0790: Panel p = new Panel();
0791: left_panel = new Panel();
0792: left_panel.setLayout(new GridLayout(4, 1));
0793: left_panel.add(new Label("Name=Value:"));
0794: left_panel.add(new Label("Domain:"));
0795: left_panel.add(new Label("Path:"));
0796: left_panel.add(new Label("Expires:"));
0797: ports_label = new Label("Ports:");
0798: p.add(left_panel);
0799:
0800: right_panel = new Panel();
0801: right_panel.setLayout(new GridLayout(4, 1));
0802: right_panel.add(name_value_label = new Label());
0803: right_panel.add(domain_value = new Label());
0804: right_panel.add(path_value = new Label());
0805: right_panel.add(expires_value = new Label());
0806: ports_value = new Label();
0807: p.add(right_panel);
0808: add(p, constr);
0809: secure_note = new Label(
0810: "This cookie will only be sent over secure connections");
0811: discard_note = new Label(
0812: "This cookie will be discarded at the end of the session");
0813: c_url_note = new Label("");
0814: comment_label = new Label("Comment:");
0815: comment_value = new TextArea("", 3, 45,
0816: TextArea.SCROLLBARS_VERTICAL_ONLY);
0817: comment_value.setEditable(false);
0818:
0819: add(new Panel(), constr);
0820:
0821: constr.gridwidth = 1;
0822: constr.anchor = GridBagConstraints.CENTER;
0823: constr.weightx = 1.0;
0824: add(default_focus = new Button("Accept"), constr);
0825: default_focus.addActionListener(new Accept());
0826:
0827: Button b;
0828: constr.gridwidth = GridBagConstraints.REMAINDER;
0829: add(b = new Button("Reject"), constr);
0830: b.addActionListener(new Reject());
0831:
0832: constr.weightx = 0.0;
0833: p = new Separator();
0834: constr.fill = GridBagConstraints.HORIZONTAL;
0835: add(p, constr);
0836:
0837: constr.fill = GridBagConstraints.NONE;
0838: constr.anchor = GridBagConstraints.WEST;
0839: add(new Label(
0840: "Accept/Reject all cookies from a host or domain:"),
0841: constr);
0842:
0843: p = new Panel();
0844: p.add(new Label("Host/Domain:"));
0845: p.add(domain = new TextField(30));
0846: add(p, constr);
0847:
0848: add(new Label(
0849: "domains are characterized by a leading dot (`.');"),
0850: constr);
0851: add(new Label("an empty string matches all hosts"), constr);
0852:
0853: constr.anchor = GridBagConstraints.CENTER;
0854: constr.gridwidth = 1;
0855: constr.weightx = 1.0;
0856: add(b = new Button("Accept All"), constr);
0857: b.addActionListener(new AcceptDomain());
0858:
0859: constr.gridwidth = GridBagConstraints.REMAINDER;
0860: add(b = new Button("Reject All"), constr);
0861: b.addActionListener(new RejectDomain());
0862:
0863: pack();
0864:
0865: constr.anchor = GridBagConstraints.WEST;
0866: constr.gridwidth = GridBagConstraints.REMAINDER;
0867: }
0868:
0869: public Dimension getMaximumSize() {
0870: return new Dimension(screen.width * 3 / 4,
0871: screen.height * 3 / 4);
0872: }
0873:
0874: /**
0875: * our event handlers
0876: */
0877: private class Accept implements ActionListener {
0878: public void actionPerformed(ActionEvent ae) {
0879: accept = true;
0880: accept_domain = false;
0881: synchronized (BasicCookieBox.this ) {
0882: BasicCookieBox.this .notifyAll();
0883: }
0884: }
0885: }
0886:
0887: private class Reject implements ActionListener {
0888: public void actionPerformed(ActionEvent ae) {
0889: accept = false;
0890: accept_domain = false;
0891: synchronized (BasicCookieBox.this ) {
0892: BasicCookieBox.this .notifyAll();
0893: }
0894: }
0895: }
0896:
0897: private class AcceptDomain implements ActionListener {
0898: public void actionPerformed(ActionEvent ae) {
0899: accept = true;
0900: accept_domain = true;
0901: synchronized (BasicCookieBox.this ) {
0902: BasicCookieBox.this .notifyAll();
0903: }
0904: }
0905: }
0906:
0907: private class RejectDomain implements ActionListener {
0908: public void actionPerformed(ActionEvent ae) {
0909: accept = false;
0910: accept_domain = true;
0911: synchronized (BasicCookieBox.this ) {
0912: BasicCookieBox.this .notifyAll();
0913: }
0914: }
0915: }
0916:
0917: private class Close extends WindowAdapter {
0918: public void windowClosing(WindowEvent we) {
0919: new Reject().actionPerformed(null);
0920: }
0921: }
0922:
0923: /**
0924: * the method called by the DefaultCookiePolicyHandler.
0925: *
0926: * @return true if the cookie should be accepted
0927: */
0928: public synchronized boolean accept(Cookie cookie,
0929: DefaultCookiePolicyHandler h, String server) {
0930: // set the new values
0931:
0932: name_value_label.setText(cookie.getName() + "="
0933: + cookie.getValue());
0934: domain_value.setText(cookie.getDomain());
0935: path_value.setText(cookie.getPath());
0936: if (cookie.expires() == null)
0937: expires_value.setText("never");
0938: else
0939: expires_value.setText(cookie.expires().toString());
0940: int pos = 2;
0941: if (cookie.isSecure())
0942: add(secure_note, constr, pos++);
0943: if (cookie.discard())
0944: add(discard_note, constr, pos++);
0945:
0946: if (cookie instanceof Cookie2) {
0947: Cookie2 cookie2 = (Cookie2) cookie;
0948:
0949: // set ports list
0950: if (cookie2.getPorts() != null) {
0951: ((GridLayout) left_panel.getLayout()).setRows(5);
0952: left_panel.add(ports_label, 2);
0953: ((GridLayout) right_panel.getLayout()).setRows(5);
0954: int[] ports = cookie2.getPorts();
0955: StringBuffer plist = new StringBuffer();
0956: plist.append(ports[0]);
0957: for (int idx = 1; idx < ports.length; idx++) {
0958: plist.append(", ");
0959: plist.append(ports[idx]);
0960: }
0961: ports_value.setText(plist.toString());
0962: right_panel.add(ports_value, 2);
0963: }
0964:
0965: // set comment url
0966: if (cookie2.getCommentURL() != null) {
0967: c_url_note.setText("For more info on this cookie see: "
0968: + cookie2.getCommentURL());
0969: add(c_url_note, constr, pos++);
0970: }
0971:
0972: // set comment
0973: if (cookie2.getComment() != null) {
0974: comment_value.setText(cookie2.getComment());
0975: add(comment_label, constr, pos++);
0976: add(comment_value, constr, pos++);
0977: }
0978: }
0979:
0980: // invalidate all labels, so that new values are displayed correctly
0981:
0982: name_value_label.invalidate();
0983: domain_value.invalidate();
0984: ports_value.invalidate();
0985: path_value.invalidate();
0986: expires_value.invalidate();
0987: left_panel.invalidate();
0988: right_panel.invalidate();
0989: secure_note.invalidate();
0990: discard_note.invalidate();
0991: c_url_note.invalidate();
0992: comment_value.invalidate();
0993: invalidate();
0994:
0995: // set default domain test
0996:
0997: domain.setText(cookie.getDomain());
0998:
0999: // display
1000:
1001: setResizable(true);
1002: pack();
1003: setResizable(false);
1004: setLocation(
1005: (screen.width - getPreferredSize().width) / 2,
1006: (int) ((screen.height - getPreferredSize().height) / 2 * .7));
1007: setVisible(true);
1008: default_focus.requestFocus();
1009:
1010: // wait for user input
1011:
1012: try {
1013: wait();
1014: } catch (InterruptedException e) {
1015: }
1016:
1017: setVisible(false);
1018:
1019: // reset popup
1020:
1021: remove(secure_note);
1022: remove(discard_note);
1023: left_panel.remove(ports_label);
1024: ((GridLayout) left_panel.getLayout()).setRows(4);
1025: right_panel.remove(ports_value);
1026: ((GridLayout) right_panel.getLayout()).setRows(4);
1027: remove(c_url_note);
1028: remove(comment_label);
1029: remove(comment_value);
1030:
1031: // handle accept/reject domain buttons
1032:
1033: if (accept_domain) {
1034: String dom = domain.getText().trim().toLowerCase();
1035:
1036: if (accept)
1037: h.addAcceptDomain(dom);
1038: else
1039: h.addRejectDomain(dom);
1040: }
1041:
1042: return accept;
1043: }
1044: }
1045:
1046: /**
1047: * A simple separator element.
1048: */
1049: class Separator extends Panel {
1050: public void paint(Graphics g) {
1051: int w = getSize().width, h = getSize().height / 2;
1052:
1053: g.setColor(Color.darkGray);
1054: g.drawLine(2, h - 1, w - 2, h - 1);
1055: g.setColor(Color.white);
1056: g.drawLine(2, h, w - 2, h);
1057: }
1058:
1059: public Dimension getMinimumSize() {
1060: return new Dimension(4, 2);
1061: }
1062: }
|