Changeset 418 for trunk/icedtea-web/netx


Ignore:
Timestamp:
Feb 11, 2013, 8:53:47 PM (13 years ago)
Author:
dmik
Message:

Merge icedtea-web v1.3 to trunk.

Location:
trunk/icedtea-web
Files:
2 deleted
54 edited
17 copied

Legend:

Unmodified
Added
Removed
  • trunk/icedtea-web

  • trunk/icedtea-web/netx/net/sourceforge/jnlp/AppletDesc.java

    r348 r418  
    2626 * @version $Revision: 1.8 $
    2727 */
    28 public class AppletDesc {
     28public class AppletDesc implements LaunchDesc {
    2929
    3030    /** the applet name */
     
    7474
    7575    /**
    76      * Returns the main class name
     76     * Returns the main class name in the dot-separated form (eg: foo.bar.Baz)
    7777     */
     78    @Override
    7879    public String getMainClass() {
    7980        return mainClass;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/ApplicationDesc.java

    r348 r418  
    2525 * @version $Revision: 1.7 $
    2626 */
    27 public class ApplicationDesc {
     27public class ApplicationDesc implements LaunchDesc {
    2828
    2929    /** the main class name and package */
     
    4747     * Returns the main class name
    4848     */
     49    @Override
    4950    public String getMainClass() {
    5051        return mainClass;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/DefaultLaunchHandler.java

    r348 r418  
    1717package net.sourceforge.jnlp;
    1818
     19import java.io.PrintStream;
     20
    1921import net.sourceforge.jnlp.runtime.*;
    2022
     
    2729 * @version $Revision: 1.1 $
    2830 */
    29 public class DefaultLaunchHandler implements LaunchHandler {
     31public class DefaultLaunchHandler extends AbstractLaunchHandler {
     32
     33    public DefaultLaunchHandler(PrintStream out) {
     34        super(out);
     35    }
    3036
    3137    /**
     
    5864     * @return true to allow the application to continue, false to stop it.
    5965     */
    60     public boolean validationError(LaunchException security) {
    61         printMessage(security);
     66    public boolean validationError(LaunchException error) {
     67        printMessage(error);
    6268        return true;
    6369    }
     
    7278    public void launchCompleted(ApplicationInstance application) {
    7379        //
    74     }
    75 
    76     /**
    77      * Print a message to stdout.
    78      */
    79     protected static void printMessage(LaunchException ex) {
    80         StringBuffer result = new StringBuffer();
    81         result.append("netx: ");
    82         result.append(ex.getCategory());
    83         if (ex.getSummary() != null) {
    84             result.append(": ");
    85             result.append(ex.getSummary());
    86         }
    87 
    88         if (JNLPRuntime.isDebug()) {
    89             if (ex.getCause() != null)
    90                 ex.getCause().printStackTrace();
    91             else
    92                 ex.printStackTrace();
    93         }
    94 
    95         Throwable causes[] = ex.getCauses();
    96 
    97         for (int i = 0; i < causes.length; i++) {
    98             result.append(" (");
    99             result.append(causes[i].getClass().getName());
    100             result.append(" ");
    101             result.append(causes[i].getMessage());
    102             result.append(")");
    103         }
    10480    }
    10581
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/GuiLaunchHandler.java

    r348 r418  
    3838package net.sourceforge.jnlp;
    3939
     40import java.io.PrintStream;
     41import java.lang.reflect.InvocationTargetException;
    4042import java.net.URL;
    4143
     
    5153 * including splash screens and exception dialogs.
    5254 */
    53 public class GuiLaunchHandler implements LaunchHandler {
     55public class GuiLaunchHandler extends AbstractLaunchHandler {
    5456
    5557    private JNLPSplashScreen splashScreen = null;
     58    private final Object mutex = new Object();
    5659    private UpdatePolicy policy = UpdatePolicy.ALWAYS;
     60
     61    public GuiLaunchHandler(PrintStream outputStream) {
     62        super(outputStream);
     63    }
    5764
    5865    @Override
     
    6673            @Override
    6774            public void run() {
     75                closeSplashScreen();
    6876                BasicExceptionDialog.show(exception);
    6977            }
    7078        });
     79        printMessage(exception);
     80    }
     81
     82    private void closeSplashScreen() {
     83        synchronized(mutex) {
     84            if (splashScreen != null) {
     85                if (splashScreen.isSplashScreenValid()) {
     86                    splashScreen.setVisible(false);
     87                }
     88                splashScreen.dispose();
     89            }
     90        }
    7191    }
    7292
     
    7696            @Override
    7797            public void run() {
    78                 if (splashScreen != null) {
    79                     if (splashScreen.isSplashScreenValid()) {
    80                         splashScreen.setVisible(false);
    81                     }
    82                     splashScreen.dispose();
    83                 }
     98                closeSplashScreen();
    8499            }
    85100        });
     
    88103    @Override
    89104    public void launchInitialized(final JNLPFile file) {
     105       
     106        int preferredWidth = 500;
     107        int preferredHeight = 400;
     108
     109        final URL splashImageURL = file.getInformation().getIconLocation(
     110                IconDesc.SPLASH, preferredWidth, preferredHeight);
     111
     112        if (splashImageURL != null) {
     113            final ResourceTracker resourceTracker = new ResourceTracker(true);
     114            resourceTracker.addResource(splashImageURL, file.getFileVersion(), null, policy);
     115            synchronized(mutex) {
     116                try {
     117                    SwingUtilities.invokeAndWait(new Runnable() {
     118                        @Override
     119                        public void run() {
     120                            splashScreen = new JNLPSplashScreen(resourceTracker, null, null);
     121                        }
     122                    });
     123                } catch (InterruptedException ie) {
     124                    // Wait till splash screen is created
     125                    while (splashScreen == null);
     126                } catch (InvocationTargetException ite) {
     127                    ite.printStackTrace();
     128                }
     129
     130                splashScreen.setSplashImageURL(splashImageURL);
     131            }
     132        }
     133       
    90134        SwingUtilities.invokeLater(new Runnable() {
    91135            @Override
    92136            public void run() {
    93                 final int preferredWidth = 500;
    94                 final int preferredHeight = 400;
    95 
    96                 URL splashImageURL = file.getInformation().getIconLocation(
    97                         IconDesc.SPLASH, preferredWidth, preferredHeight);
    98137                if (splashImageURL != null) {
    99                     ResourceTracker resourceTracker = new ResourceTracker(true);
    100                     resourceTracker.addResource(splashImageURL, file.getFileVersion(), null, policy);
    101                     splashScreen = new JNLPSplashScreen(resourceTracker, null, null);
    102                     splashScreen.setSplashImageURL(splashImageURL);
    103                     if (splashScreen.isSplashScreenValid()) {
    104                         splashScreen.setVisible(true);
     138                    synchronized(mutex) {
     139                        if (splashScreen.isSplashScreenValid()) {
     140                            splashScreen.setVisible(true);
     141                        }
    105142                    }
    106143                }
     
    111148    @Override
    112149    public boolean launchWarning(LaunchException warning) {
    113         DefaultLaunchHandler.printMessage(warning);
     150        printMessage(warning);
    114151        return true;
    115152    }
    116153
    117154    @Override
    118     public boolean validationError(LaunchException security) {
    119         DefaultLaunchHandler.printMessage(security);
     155    public boolean validationError(LaunchException error) {
     156        closeSplashScreen();
     157        printMessage(error);
    120158        return true;
    121159    }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/InstallerDesc.java

    r348 r418  
    2323 * @version $Revision: 1.6 $
    2424 */
    25 public class InstallerDesc {
     25public class InstallerDesc implements LaunchDesc {
    2626
    2727    /** the main class name and package. */
     
    4040     * Returns the main class name and package.
    4141     */
     42    @Override
    4243    public String getMainClass() {
    4344        return mainClass;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPFile.java

    r348 r418  
    9292
    9393    /** the application description */
    94     protected Object launchType;
     94    protected LaunchDesc launchType;
    9595
    9696    /** the component description */
     
    100100    protected SecurityDesc security;
    101101
     102    /** the default JVM locale */
     103    protected Locale defaultLocale = null;
     104
    102105    /** the default OS */
    103     protected Locale defaultLocale = null;
     106    protected String defaultOS = null;
    104107
    105108    /** the default arch */
    106     protected String defaultOS = null;
    107 
    108     /** the default jvm */
    109109    protected String defaultArch = null;
     110
     111    /** A signed JNLP file is missing from the main jar */
     112    private boolean missingSignedJNLP = false;
     113
     114    /** JNLP file contains special properties */
     115    private boolean containsSpecialProperties = false;
     116
     117    /**
     118     * List of acceptable properties (not-special)
     119     */
     120    private String[] generalProperties = SecurityDesc.getJnlpRIAPermissions();
    110121
    111122    { // initialize defaults if security allows
     
    119130    }
    120131
     132    static enum Match { LANG_COUNTRY_VARIANT, LANG_COUNTRY, LANG, GENERALIZED }
     133
    121134    /**
    122135     * Empty stub, allowing child classes to override the constructor
     
    175188     */
    176189    public JNLPFile(URL location, Version version, boolean strict, UpdatePolicy policy) throws IOException, ParseException {
     190        this(location, version, strict, policy, null);
     191    }
     192
     193    /**
     194     * Create a JNLPFile from a URL and a version, checking for updates
     195     * using the specified policy.
     196     *
     197     * @param location the location of the JNLP file
     198     * @param version the version of the JNLP file
     199     * @param strict whether to enforce the spec when
     200     * @param policy the update policy
     201     * @param forceCodebase codebase to use if not specified in JNLP file.
     202     * @throws IOException if an IO exception occurred
     203     * @throws ParseException if the JNLP file was invalid
     204     */
     205    protected JNLPFile(URL location, Version version, boolean strict, UpdatePolicy policy, URL forceCodebase) throws IOException, ParseException {
    177206        Node root = Parser.getRootNode(openURL(location, version, policy));
    178         parse(root, strict, location);
     207        parse(root, strict, location, forceCodebase);
    179208
    180209        //Downloads the original jnlp file into the cache if possible
     
    182211        //originated from a website, then download the one from the website
    183212        //into the cache).
    184         if (sourceLocation != null && location.getProtocol() == "file") {
     213        if (sourceLocation != null && "file".equals(location.getProtocol())) {
    185214            openURL(sourceLocation, version, policy);
    186215        }
     
    223252     */
    224253    public JNLPFile(InputStream input, boolean strict) throws ParseException {
    225         parse(Parser.getRootNode(input), strict, null);
     254        parse(Parser.getRootNode(input), strict, null, null);
    226255    }
    227256
     
    258287
    259288    /**
    260      * Returns the JNLP file's title. This method returns the same
     289     * Returns the JNLP file's best localized title. This method returns the same
    261290     * value as InformationDesc.getTitle().
    262291     */
     
    266295
    267296    /**
     297     * Returns the JNLP file's best localized vendor. This method returns the same
     298     * value as InformationDesc.getVendor().
     299     */
     300    public String getVendor() {
     301        return getInformation().getVendor();
     302    }
     303
     304    /**
    268305     * Returns the JNLP file's network location as specified in the
    269306     * JNLP file.
     
    323360    public InformationDesc getInformation(final Locale locale) {
    324361        return new InformationDesc(this, new Locale[] { locale }) {
     362            @Override
    325363            protected List<Object> getItems(Object key) {
    326364                List<Object> result = new ArrayList<Object>();
    327365
    328                 for (int i = 0; i < info.size(); i++) {
    329                     InformationDesc infoDesc = info.get(i);
    330 
    331                     if (localMatches(locale, infoDesc.getLocales()))
    332                         result.addAll(infoDesc.getItems(key));
     366                for (Match precision : Match.values()) {
     367                    for (InformationDesc infoDesc : JNLPFile.this.info) {
     368                        if (localeMatches(locale, infoDesc.getLocales(), precision)) {
     369                            result.addAll(infoDesc.getItems(key));
     370                        }
     371                    }
     372
     373                    if (result.size() > 0) {
     374                        return result;
     375                    }
    333376                }
    334 
    335377                return result;
     378            }
     379
     380            @Override
     381            public String getTitle() {
     382                for (Match precision : Match.values()) {
     383                    for (InformationDesc infoDesc : JNLPFile.this.info) {
     384                        String title = infoDesc.getTitle();
     385                        if (localeMatches(locale, infoDesc.getLocales(), precision)
     386                                && title != null && !"".equals(title)) {
     387                            return title;
     388                        }
     389                    }
     390                }
     391
     392                return null;
     393            }
     394
     395            @Override
     396            public String getVendor() {
     397                for (Match precision : Match.values()) {
     398                    for (InformationDesc infoDesc : JNLPFile.this.info) {
     399                        String vendor = infoDesc.getVendor();
     400                        if (localeMatches(locale, infoDesc.getLocales(), precision)
     401                                && vendor != null && !"".equals(vendor)) {
     402                            return vendor;
     403                        }
     404                    }
     405                }
     406
     407                return null;
    336408            }
    337409        };
     
    367439    public ResourcesDesc getResources(final Locale locale, final String os, final String arch) {
    368440        return new ResourcesDesc(this, new Locale[] { locale }, new String[] { os }, new String[] { arch }) {
     441
     442            @Override
    369443            public <T> List<T> getResources(Class<T> launchType) {
    370444                List<T> result = new ArrayList<T>();
    371445
    372                 for (int i = 0; i < resources.size(); i++) {
    373                     ResourcesDesc rescDesc = resources.get(i);
    374 
    375                     if (localMatches(locale, rescDesc.getLocales())
     446                for (ResourcesDesc rescDesc : resources) {
     447                    boolean hasUsableLocale = false;
     448                    for (Match match : Match.values()) {
     449                        hasUsableLocale |= localeMatches(locale, rescDesc.getLocales(), match);
     450                    }
     451                    if (hasUsableLocale
    376452                            && stringMatches(os, rescDesc.getOS())
    377453                            && stringMatches(arch, rescDesc.getArch()))
     
    384460            }
    385461
     462            @Override
    386463            public void addResource(Object resource) {
    387464                // todo: honor the current locale, os, arch values
     
    409486        List<ResourcesDesc> matchingResources = new ArrayList<ResourcesDesc>();
    410487        for (ResourcesDesc rescDesc: resources) {
    411             if (localMatches(locale, rescDesc.getLocales())
     488            boolean hasUsableLocale = false;
     489            for (Match match : Match.values()) {
     490                hasUsableLocale |= localeMatches(locale, rescDesc.getLocales(), match);
     491            }
     492            if (hasUsableLocale
    412493                    && stringMatches(os, rescDesc.getOS())
    413494                    && stringMatches(arch, rescDesc.getArch())) {
     
    422503     * ApplicationDesc and InstallerDesc
    423504     */
    424     public Object getLaunchInfo() {
     505    public LaunchDesc getLaunchInfo() {
    425506        return launchType;
    426507    }
     
    522603     * @param requested the local
    523604     * @param available the available locales
     605     * @param precision the depth with which to match locales. 1 checks only
     606     * language, 2 checks language and country, 3 checks language, country and
     607     * variant for matches. Passing 0 will always return true.
    524608     * @return true if requested matches any of available, or if
    525609     * available is empty or null.
    526610     */
    527     private boolean localMatches(Locale requested, Locale available[]) {
    528         if (available == null || available.length == 0)
    529             return true;
    530 
    531         for (int i = 0; i < available.length; i++) {
    532             String language = requested.getLanguage(); // "" but never null
    533             String country = requested.getCountry();
    534             String variant = requested.getVariant();
    535 
    536             if (!"".equals(language) && !language.equalsIgnoreCase(available[i].getLanguage()))
    537                 continue;
    538             if (!"".equals(country) && !country.equalsIgnoreCase(available[i].getCountry()))
    539                 continue;
    540             if (!"".equals(variant) && !variant.equalsIgnoreCase(available[i].getVariant()))
    541                 continue;
    542 
    543             return true;
    544         }
    545 
     611    public boolean localeMatches(Locale requested, Locale available[], Match matchLevel) {
     612
     613        if (matchLevel == Match.GENERALIZED)
     614            return available == null || available.length == 0;
     615
     616        String language = requested.getLanguage(); // "" but never null
     617        String country = requested.getCountry();
     618        String variant = requested.getVariant();
     619
     620        for (Locale locale : available) {
     621            switch (matchLevel) {
     622                case LANG:
     623                    if (!language.isEmpty()
     624                            && language.equals(locale.getLanguage())
     625                            && locale.getCountry().isEmpty()
     626                            && locale.getVariant().isEmpty())
     627                        return true;
     628                    break;
     629                case LANG_COUNTRY:
     630                    if (!language.isEmpty()
     631                            && language.equals(locale.getLanguage())
     632                            && !country.isEmpty()
     633                            && country.equals(locale.getCountry())
     634                            && locale.getVariant().isEmpty())
     635                        return true;
     636                    break;
     637                case LANG_COUNTRY_VARIANT:
     638                    if (language.equals(locale.getLanguage())
     639                            && country.equals(locale.getCountry())
     640                            && variant.equals(locale.getVariant()))
     641                        return true;
     642                    break;
     643                default:
     644                    break;
     645            }
     646        }
    546647        return false;
    547648    }
     
    575676     * @param location the file location or null
    576677     */
    577     private void parse(Node root, boolean strict, URL location) throws ParseException {
     678    private void parse(Node root, boolean strict, URL location, URL forceCodebase) throws ParseException {
    578679        try {
    579680            //if (location != null)
    580681            //  location = new URL(location, "."); // remove filename
    581682
    582             Parser parser = new Parser(this, location, root, strict, true); // true == allow extensions
     683            Parser parser = new Parser(this, location, root, strict, true, forceCodebase); // true == allow extensions
    583684
    584685            // JNLP tag information
     
    588689            sourceLocation = parser.getFileLocation() != null ? parser.getFileLocation() : location;
    589690            info = parser.getInfo(root);
     691            parser.checkForInformation();
    590692            update = parser.getUpdate(root);
    591693            resources = parser.getResources(root, false); // false == not a j2se/java resources section
     
    593695            component = parser.getComponent(root);
    594696            security = parser.getSecurity(root);
     697
     698            checkForSpecialProperties();
     699
    595700        } catch (ParseException ex) {
    596701            throw ex;
     
    600705
    601706            throw new RuntimeException(ex.toString());
     707        }
     708    }
     709
     710    /**
     711     * Inspects the JNLP file to check if it contains any special properties
     712     */
     713    private void checkForSpecialProperties() {
     714
     715        for (ResourcesDesc res : resources) {
     716            for (PropertyDesc propertyDesc : res.getProperties()) {
     717
     718                for (int i = 0; i < generalProperties.length; i++) {
     719                    String property = propertyDesc.getKey();
     720
     721                    if (property.equals(generalProperties[i])) {
     722                        break;
     723                    } else if (!property.equals(generalProperties[i])
     724                            && i == generalProperties.length - 1) {
     725                        containsSpecialProperties = true;
     726                        return;
     727                    }
     728                }
     729
     730            }
    602731        }
    603732    }
     
    675804    }
    676805
     806    /**
     807     * Returns a boolean after determining if a signed JNLP warning should be
     808     * displayed in the 'More Information' panel.
     809     *
     810     * @return true if a warning should be displayed; otherwise false
     811     */
     812    public boolean requiresSignedJNLPWarning() {
     813        return (missingSignedJNLP && containsSpecialProperties);
     814    }
     815
     816    /**
     817     * Informs that a signed JNLP file is missing in the main jar
     818     */
     819    public void setSignedJNLPAsMissing() {
     820        missingSignedJNLP = true;
     821    }
    677822}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/JNLPSplashScreen.java

    r348 r418  
    1111
    1212import javax.imageio.ImageIO;
    13 import javax.swing.JFrame;
     13import javax.swing.JDialog;
    1414
    1515import net.sourceforge.jnlp.cache.ResourceTracker;
    1616import net.sourceforge.jnlp.runtime.JNLPRuntime;
     17import net.sourceforge.jnlp.util.ImageResources;
    1718
    18 public class JNLPSplashScreen extends JFrame {
     19public class JNLPSplashScreen extends JDialog {
    1920
    2021    String applicationTitle;
     
    2829    public JNLPSplashScreen(ResourceTracker resourceTracker,
    2930            String applicationTitle, String applicationVendor) {
     31
     32        setIconImages(ImageResources.INSTANCE.getApplicationImages());
    3033
    3134        // If the JNLP file does not contain any icon images, the splash image
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/LaunchException.java

    r348 r418  
    1717package net.sourceforge.jnlp;
    1818
    19 import java.io.*;
    20 import java.util.*;
    21 
    22 import net.sourceforge.jnlp.util.*;
    23 
    2419/**
    2520 * Thrown when a JNLP application, applet, or installer could not
     
    3126public class LaunchException extends Exception {
    3227
    33     /** the original exception */
    34     private Throwable cause = null;
     28    private static final long serialVersionUID = 7283827853612357423L;
    3529
    3630    /** the file being launched */
     
    5347     */
    5448    public LaunchException(JNLPFile file, Exception cause, String severity, String category, String summary, String description) {
    55         super(severity + ": " + category + ": " + summary);
     49        super(severity + ": " + category + ": " + summary + " "
     50                    + (description == null ? "" : description), cause);
    5651
    5752        this.file = file;
     
    6055        this.description = description;
    6156        this.severity = severity;
    62 
    63         // replace with setCause when no longer 1.3 compatible
    64         this.cause = cause;
    6557    }
    6658
     
    6961     */
    7062    public LaunchException(Throwable cause) {
    71         this(cause.getMessage());
    72 
    73         // replace with setCause when no longer 1.3 compatible
    74         this.cause = cause;
     63        super(cause);
    7564    }
    7665
     
    7968     */
    8069    public LaunchException(String message, Throwable cause) {
    81         this(message + ": " + cause.getMessage());
    82 
    83         // replace with setCause when no longer 1.3 compatible
    84         this.cause = cause;
     70        super(message, cause);
    8571    }
    8672
     
    132118    }
    133119
    134     /**
    135      * Return the cause of the launch exception or null if there
    136      * is no cause exception.
    137      */
    138     public Throwable getCause() {
    139         return cause;
    140     }
    141 
    142     /**
    143      * Returns the causes for this exception.  This method is
    144      * useful on JRE 1.3 since getCause is not a standard method,
    145      * and will be removed once netx no longer supports 1.3.
    146      */
    147     public Throwable[] getCauses() {
    148         ArrayList<Throwable> result = new ArrayList<Throwable>();
    149 
    150         Reflect r = new Reflect();
    151         Throwable cause = this.cause;
    152 
    153         while (cause != null) {
    154             result.add(cause);
    155             cause = (Throwable) r.invoke(cause, "getCause");
    156         }
    157 
    158         return result.toArray(new Throwable[0]);
    159     }
    160 
    161     /**
    162      * Print the stack trace and the cause exception (1.3
    163      * compatible)
    164      */
    165     public void printStackTrace(PrintStream stream) {
    166         super.printStackTrace(stream);
    167 
    168         if (cause != null) {
    169             stream.println("Caused by: ");
    170             cause.printStackTrace(stream);
    171         }
    172     }
    173 
    174     /**
    175      * Print the stack trace and the cause exception (1.3
    176      * compatible)
    177      */
    178     public void printStackTrace(PrintWriter stream) {
    179         super.printStackTrace(stream);
    180 
    181         if (cause != null) {
    182             stream.println("Caused by: ");
    183             cause.printStackTrace(stream);
    184         }
    185     }
    186 
    187120}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/LaunchHandler.java

    r348 r418  
    5151     * @return true to allow the application to continue, false to stop it.
    5252     */
    53     public boolean validationError(LaunchException security);
     53    public boolean validationError(LaunchException error);
    5454
    5555    // this method will probably be replaced when real security
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Launcher.java

    r348 r418  
    2626import java.net.URL;
    2727import java.net.UnknownHostException;
     28import java.util.Arrays;
    2829import java.util.LinkedList;
    2930import java.util.List;
     
    3334import net.sourceforge.jnlp.cache.CacheUtil;
    3435import net.sourceforge.jnlp.cache.UpdatePolicy;
    35 import net.sourceforge.jnlp.runtime.AppThreadGroup;
    3636import net.sourceforge.jnlp.runtime.AppletInstance;
    3737import net.sourceforge.jnlp.runtime.ApplicationInstance;
     
    588588
    589589            main.setAccessible(true);
     590
     591            if (JNLPRuntime.isDebug()) {
     592                System.out.println("Invoking main() with args: " + Arrays.toString(args));
     593            }
    590594            main.invoke(null, new Object[] { args });
    591595
     
    703707            }
    704708
    705             AppThreadGroup group = (AppThreadGroup) Thread.currentThread().getThreadGroup();
    706 
     709            ThreadGroup group = Thread.currentThread().getThreadGroup();
     710
     711            // appletInstance is needed by ServiceManager when looking up
     712            // services. This could potentially be done in applet constructor
     713            // so initialize appletInstance before creating applet.
     714            AppletInstance appletInstance;
     715            if (cont == null)
     716                appletInstance = new AppletInstance(file, group, loader, null);
     717            else
     718                appletInstance = new AppletInstance(file, group, loader, null, cont);
     719
     720            loader.setApplication(appletInstance);
     721
     722            // Initialize applet now that ServiceManager has access to its
     723            // appletInstance.
    707724            String appletName = file.getApplet().getMainClass();
    708 
    709             //Classloader chokes if there's '/' in the path to the main class.
    710             //Must replace with '.' instead.
    711             appletName = appletName.replace('/', '.');
    712725            Class appletClass = loader.loadClass(appletName);
    713726            Applet applet = (Applet) appletClass.newInstance();
    714 
    715             AppletInstance appletInstance;
    716             if (cont == null)
    717                 appletInstance = new AppletInstance(file, group, loader, applet);
    718             else
    719                 appletInstance = new AppletInstance(file, group, loader, applet, cont);
    720 
    721             group.setApplication(appletInstance);
    722             loader.setApplication(appletInstance);
    723 
     727            // Finish setting up appletInstance.
     728            appletInstance.setApplet(applet);
     729            appletInstance.getAppletEnvironment().setApplet(applet);
     730           
    724731            setContextClassLoaderForAllThreads(appletInstance.getThreadGroup(), appletInstance.getClassLoader());
    725732
     
    747754
    748755            String appletName = file.getApplet().getMainClass();
    749 
    750             //Classloader chokes if there's '/' in the path to the main class.
    751             //Must replace with '.' instead.
    752             appletName = appletName.replace('/', '.');
    753756            Class appletClass = loader.loadClass(appletName);
    754757            Applet applet = (Applet) appletClass.newInstance();
     
    766769        try {
    767770            JNLPClassLoader loader = JNLPClassLoader.getInstance(file, updatePolicy);
    768             AppThreadGroup group = (AppThreadGroup) Thread.currentThread().getThreadGroup();
     771            ThreadGroup group = Thread.currentThread().getThreadGroup();
    769772
    770773            ApplicationInstance app = new ApplicationInstance(file, group, loader);
    771             group.setApplication(app);
    772774            loader.setApplication(app);
    773775
     
    785787     * ThreadGroup has to be created at an earlier point in the applet code.
    786788     */
    787     protected AppThreadGroup createThreadGroup(JNLPFile file) {
    788         AppThreadGroup appThreadGroup = null;
     789    protected ThreadGroup createThreadGroup(JNLPFile file) {
     790        ThreadGroup tg = null;
    789791
    790792        if (file instanceof PluginBridge) {
    791             appThreadGroup = (AppThreadGroup) Thread.currentThread().getThreadGroup();
     793            tg = Thread.currentThread().getThreadGroup();
    792794        } else {
    793             appThreadGroup = new AppThreadGroup(mainGroup, file.getTitle());
    794         }
    795 
    796         return appThreadGroup;
     795            tg = new ThreadGroup(mainGroup, file.getTitle());
     796        }
     797
     798        return tg;
    797799    }
    798800
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/NetxPanel.java

    r348 r418  
    2424
    2525import net.sourceforge.jnlp.AppletLog;
    26 import net.sourceforge.jnlp.runtime.AppThreadGroup;
    2726import net.sourceforge.jnlp.runtime.AppletInstance;
    2827import net.sourceforge.jnlp.runtime.JNLPRuntime;
    2928
    3029import java.net.URL;
     30import java.util.HashMap;
    3131import java.util.Hashtable;
     32import java.util.Map;
     33import java.util.concurrent.ConcurrentHashMap;
     34import java.util.concurrent.ConcurrentMap;
    3235
    3336import sun.applet.AppletViewerPanel;
     
    4548    private AppletInstance appInst = null;
    4649    private boolean appletAlive;
     50    private final String uKey;
     51
     52    // We use this so that we can create exactly one thread group
     53    // for all panels with the same uKey.
     54    private static final Map<String, ThreadGroup> uKeyToTG =
     55        new HashMap<String, ThreadGroup>();
     56    private static final Object TGMapMutex = new Object();
     57
     58    // This map is actually a set (unfortunately there is no ConcurrentSet
     59    // in java.util.concurrent). If KEY is in this map, then we know that
     60    // an app context has been created for the panel that has uKey.equals(KEY),
     61    // so we avoid creating it a second time for panels with the same uKey.
     62    // Because it's a set, only the keys matter. However, we can't insert
     63    // null values in because if we did, we couldn't use null checks to see
     64    // if a key was absent before a putIfAbsent.
     65    private static final ConcurrentMap<String, Boolean> appContextCreated =
     66        new ConcurrentHashMap<String, Boolean>();
    4767
    4868    public NetxPanel(URL documentURL, Hashtable<String, String> atts) {
    4969        super(documentURL, atts);
     70
     71        /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html,
     72         * classloaders are shared iff these properties match:
     73         * codebase, cache_archive, java_archive, archive
     74         *
     75         * To achieve this, we create the uniquekey based on those 4 values,
     76         * always in the same order. The initial "<NAME>=" parts ensure a
     77         * bad tag cannot trick the loader into getting shared with another.
     78         */
     79
     80        // Firefox sometimes skips the codebase if it is default  -- ".",
     81        // so set it that way if absent
     82        String codebaseAttr =      atts.get("codebase") != null ?
     83                                   atts.get("codebase") : ".";
     84
     85        String cache_archiveAttr = atts.get("cache_archive") != null ?
     86                                   atts.get("cache_archive") : "";
     87
     88        String java_archiveAttr =  atts.get("java_archive") != null ?
     89                                   atts.get("java_archive") : "";
     90
     91        String archiveAttr =       atts.get("archive") != null ?
     92                                   atts.get("archive") : "";
     93
     94        this.uKey = "codebase=" + codebaseAttr +
     95                    "cache_archive=" + cache_archiveAttr +
     96                    "java_archive=" + java_archiveAttr +
     97                    "archive=" +  archiveAttr;
     98
     99        // when this was being done (incorrectly) in Launcher, the call was
     100        // new AppThreadGroup(mainGroup, file.getTitle());
     101        synchronized(TGMapMutex) {
     102            if (!uKeyToTG.containsKey(this.uKey)) {
     103                ThreadGroup tg = new ThreadGroup(Launcher.mainGroup, this.documentURL.toString());
     104                uKeyToTG.put(this.uKey, tg);
     105            }
     106        }
    50107    }
    51108
     
    56113        this.exitOnFailure = exitOnFailure;
    57114        this.appletAlive = true;
    58     }
    59 
    60     @Override
    61     public void run() {
    62         /*
    63          * create an AppContext for this thread associated with this particular
    64          * plugin instance (which runs in a different thread group from the rest
    65          * of the plugin).
    66          */
    67         SunToolkit.createNewAppContext();
    68 
    69         super.run();
    70115    }
    71116
     
    79124        super.showAppletException(t);
    80125    }
    81    
     126
    82127    //Overriding to use Netx classloader. You might need to relax visibility
    83128    //in sun.applet.AppletPanel for runLoader().
     
    91136                                getWidth(),
    92137                                getHeight(),
    93                                 atts);
     138                                atts, uKey);
    94139
    95140            doInit = true;
     
    155200        }
    156201
    157         // when this was being done (incorrectly) in Launcher, the call was
    158         // new AppThreadGroup(mainGroup, file.getTitle());
    159         ThreadGroup tg = new AppThreadGroup(Launcher.mainGroup,
    160                 this.documentURL.toString());
    161         handler = new Thread(tg, this);
     202        handler = new Thread(getThreadGroup(), this);
    162203        handler.start();
    163204    }
     
    175216        return handler != null && handler.isAlive() && this.appletAlive;
    176217    }
     218
     219    public ThreadGroup getThreadGroup() {
     220        synchronized(TGMapMutex) {
     221            return uKeyToTG.get(uKey);
     222        }
     223    }
     224
     225    public void createNewAppContext() {
     226        if (Thread.currentThread().getThreadGroup() != getThreadGroup()) {
     227            throw new RuntimeException("createNewAppContext called from the wrong thread.");
     228        }
     229        // only create a new context if one hasn't already been created for the
     230        // applets with this unique key.
     231        if (null == appContextCreated.putIfAbsent(uKey, Boolean.TRUE)) {
     232            SunToolkit.createNewAppContext();
     233        }
     234    }
    177235}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Node.java

    r348 r418  
    2020    private Node next;
    2121    private Node children[];
     22    private List <String> attributeNames= null;
    2223
    2324    Node(XMLElement xml) {
     
    6162        return children;
    6263    }
     64   
     65    /**
     66     * To retrieve all attribute names
     67     * @return all attribute names of the Node in ArrayList<String>
     68     */
     69    List<String> getAttributeNames() {
     70        if (attributeNames == null) {
     71            attributeNames= new ArrayList<String>();
     72
     73            for (Enumeration e = xml.enumerateAttributeNames(); e.hasMoreElements();)
     74                attributeNames.add(new String((String) e.nextElement()));
     75        }
     76
     77        return attributeNames;
     78    }
    6379
    6480    String getAttribute(String name) {
     
    87103    private Node next;
    88104    private Node children[];
     105    private String attributeNames[];
    89106
    90107    Node(ParsedXML tinyNode) {
     
    128145        return children;
    129146    }
    130 
     147   
    131148    String getAttribute(String name) {
    132149        return tinyNode.getAttribute(name);
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Parser.java

    r348 r418  
    11// Copyright (C) 2001-2003 Jon A. Maxwell (JAM)
    2 // Copyright (C) 2009 Red Hat, Inc.
     2// Copyright (C) 2012 Red Hat, Inc.
    33//
    44// This library is free software; you can redistribute it and/or
     
    2929import net.sourceforge.jnlp.UpdateDesc.Check;
    3030import net.sourceforge.jnlp.UpdateDesc.Policy;
     31import net.sourceforge.jnlp.runtime.JNLPRuntime;
    3132import net.sourceforge.nanoxml.*;
    3233
     
    111112     */
    112113    public Parser(JNLPFile file, URL base, Node root, boolean strict, boolean allowExtensions) throws ParseException {
     114        this(file, base, root, strict, allowExtensions, null);
     115    }
     116
     117    /**
     118     * Create a parser for the JNLP file.  If the location
     119     * parameters is not null it is used as the default codebase
     120     * (does not override value of jnlp element's href
     121     * attribute).<p>
     122     *
     123     * The root node may be normalized as a side effect of this
     124     * constructor.
     125     *
     126     * @param file the (uninitialized) file reference
     127     * @param base if codebase is not specified, a default base for relative URLs
     128     * @param root the root node
     129     * @param strict whether to enforce strict compliance with the JNLP spec
     130     * @param allowExtensions whether to allow extensions to the JNLP spec
     131     * @param codebase codebase to use if we did not parse one from JNLP file.
     132     * @throws ParseException if the JNLP file is invalid
     133     */
     134    public Parser(JNLPFile file, URL base, Node root, boolean strict, boolean allowExtensions, URL codebase) throws ParseException {
    113135        this.file = file;
    114136        this.root = root;
     
    123145        this.spec = getVersion(root, "spec", "1.0+");
    124146        this.codebase = addSlash(getURL(root, "codebase", base));
    125         this.base = (codebase != null) ? codebase : base; // if codebase not specified use default codebase
     147        if (this.codebase == null) // We only override it if it is not specified.
     148            this.codebase = codebase;
     149        this.base = (this.codebase != null) ? this.codebase : base; // if codebase not specified use default codebase
    126150        fileLocation = getURL(root, "href", this.base);
    127151
     
    403427
    404428    /**
     429     * Make sure a title and vendor are present and nonempty and localized as
     430     * best matching as possible for the JVM's current locale. Fallback to a
     431     * generalized title and vendor otherwise. If none is found, throw an exception.
     432     *
     433     * Additionally prints homepage, description, title and vendor to stdout
     434     * if in Debug mode.
     435     * @throws RequiredElementException
     436     */
     437    void checkForInformation() throws RequiredElementException {
     438        if (JNLPRuntime.isDebug()) {
     439            System.out.println("Homepage: " + file.getInformation().getHomepage());
     440            System.out.println("Description: " + file.getInformation().getDescription());
     441        }
     442
     443        String title = file.getTitle();
     444        String vendor = file.getVendor();
     445
     446        if (title == null || title.trim().isEmpty())
     447            throw new MissingTitleException();
     448        else if (JNLPRuntime.isDebug())
     449            System.out.println("Acceptable title tag found, contains: " + title);
     450
     451        if (vendor == null || vendor.trim().isEmpty())
     452            throw new MissingVendorException();
     453        else if (JNLPRuntime.isDebug())
     454            System.out.println("Acceptable vendor tag found, contains: " + vendor);
     455    }
     456
     457    /**
    405458     * Returns all of the information elements under the specified
    406459     * node.
     
    416469        // ensure that there are at least one information section present
    417470        if (info.length == 0)
    418             throw new ParseException(R("PNoInfoElement"));
     471            throw new MissingInformationException();
    419472
    420473        // create objects from the info sections
    421         for (int i = 0; i < info.length; i++)
    422             result.add(getInformationDesc(info[i]));
     474        for (Node infoNode : info) {
     475            result.add(getInformationDesc(infoNode));
     476        }
    423477
    424478        return result;
     
    582636     * @throws ParseException if the JNLP file is invalid
    583637     */
    584     public Object getLauncher(Node parent) throws ParseException {
     638    public LaunchDesc getLauncher(Node parent) throws ParseException {
    585639        // check for other than one application type
    586640        if (1 < getChildNodes(parent, "applet-desc").length
     
    869923        String language = localeStr.substring(0, 2);
    870924        String country = (localeStr.length() < 5) ? "" : localeStr.substring(3, 5);
    871         String variant = (localeStr.length() < 7) ? "" : localeStr.substring(6, 8);
     925        String variant = (localeStr.length() > 7) ? localeStr.substring(6) : "";
    872926
    873927        // null is not allowed n locale but "" is
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/PluginBridge.java

    r348 r418  
    11/*
    2  * Copyright 2007 Red Hat, Inc.
     2 * Copyright 2012 Red Hat, Inc.
    33 * This file is part of IcedTea, http://icedtea.classpath.org
    44 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
     
    2323package net.sourceforge.jnlp;
    2424
     25import java.io.File;
    2526import java.net.URL;
    2627import java.net.MalformedURLException;
    27 import java.util.Hashtable;
     28import java.util.HashSet;
    2829import java.util.Locale;
    2930import java.util.List;
    3031import java.util.ArrayList;
    3132import java.util.Map;
     33import java.util.Set;
    3234
    3335import net.sourceforge.jnlp.runtime.JNLPRuntime;
    3436
     37/**
     38 * Allows reuse of code that expects a JNLPFile object,
     39 * while overriding behaviour specific to applets.
     40 */
    3541public class PluginBridge extends JNLPFile {
    3642
    37     String name;
    38     String[] jars = new String[0];
    39     String[] cacheJars = new String[0];
    40     String[] cacheExJars = new String[0];
    41     Hashtable<String, String> atts;
     43    private String name;
     44    private Set<String> jars = new HashSet<String>();
     45    //Folders can be added to the code-base through the archive tag
     46    private List<String> codeBaseFolders = new ArrayList<String>();
     47    private String[] cacheJars = new String[0];
     48    private String[] cacheExJars = new String[0];
     49    private Map<String, String> atts;
    4250    private boolean usePack;
    4351    private boolean useVersion;
    4452    private boolean codeBaseLookup;
    45 
     53    private boolean useJNLPHref;
     54
     55    /**
     56     * Creates a new PluginBridge using a default JNLPCreator.
     57     */
    4658    public PluginBridge(URL codebase, URL documentBase, String jar, String main,
    47                         int width, int height, Hashtable<String, String> atts)
     59                        int width, int height, Map<String, String> atts,
     60                        String uKey)
     61            throws Exception {
     62        this(codebase, documentBase, jar, main, width, height, atts, uKey, new JNLPCreator());
     63    }
     64
     65    /**
     66     * Handles archive tag entries, which may be folders or jar files
     67     * @param archives the components of the archive tag
     68     */
     69    private void addArchiveEntries(String[] archives) {
     70        for (String archiveEntry : archives){
     71            // trim white spaces
     72            archiveEntry = archiveEntry.trim();
     73
     74            /*Only '/' on linux, '/' or '\\' on windows*/
     75            if (archiveEntry.endsWith("/") || archiveEntry.endsWith(File.pathSeparator)) {
     76                this.codeBaseFolders.add(archiveEntry);
     77            } else {
     78                this.jars.add(archiveEntry);
     79            }
     80        }
     81    }
     82
     83    public PluginBridge(URL codebase, URL documentBase, String archive, String main,
     84                        int width, int height, Map<String, String> atts,
     85                        String uKey, JNLPCreator jnlpCreator)
    4886            throws Exception {
    4987        specVersion = new Version("1.0");
     
    5189        this.codeBase = codebase;
    5290        this.sourceLocation = documentBase;
     91        this.atts = atts;
    5392
    5493        if (atts.containsKey("jnlp_href")) {
     94            useJNLPHref = true;
    5595            try {
    56                 URL jnlp = new URL(codeBase.toExternalForm() + atts.get("jnlp_href"));
    57                 JNLPFile jnlpFile = new JNLPFile(jnlp);
     96                // Use codeBase as the context for the URL. If jnlp_href's
     97                // value is a complete URL, it will replace codeBase's context.
     98                URL jnlp = new URL(codeBase, atts.get("jnlp_href"));
     99                JNLPFile jnlpFile = jnlpCreator.create(jnlp, null, false, JNLPRuntime.getDefaultUpdatePolicy(), codeBase);
    58100                Map<String, String> jnlpParams = jnlpFile.getApplet().getParameters();
     101                info = jnlpFile.info;
    59102
    60103                // Change the parameter name to lowercase to follow conventions.
    61104                for (Map.Entry<String, String> entry : jnlpParams.entrySet()) {
    62                     atts.put(entry.getKey().toLowerCase(), entry.getValue());
     105                    this.atts.put(entry.getKey().toLowerCase(), entry.getValue());
    63106                }
     107                JARDesc[] jarDescs = jnlpFile.getResources().getJARs();
     108                for (JARDesc jarDesc : jarDescs) {
     109                     String fileName = jarDesc.getLocation().toExternalForm();
     110                     this.jars.add(fileName);
     111                 }
    64112            } catch (MalformedURLException e) {
    65113                // Don't fail because we cannot get the jnlp file. Parameters are optional not required.
    66114                // it is the site developer who should ensure that file exist.
    67                 System.err.println("Unable to get JNLP file at: " + codeBase.toExternalForm()
    68                         + atts.get("jnlp_href"));
    69             }
     115                System.err.println("Unable to get JNLP file at: " + atts.get("jnlp_href")
     116                        + " with context of URL as: " + codeBase.toExternalForm());
     117            }
     118        } else {
     119            // Should we populate this list with applet attribute tags?
     120            info = new ArrayList<InformationDesc>();
     121            useJNLPHref = false;
    70122        }
    71123
     
    100152        }
    101153
    102         if (jar != null && jar.length() > 0) {
    103             this.jars = jar.split(",");
    104 
    105             // trim white spaces
    106             for (int i = 0; i < this.jars.length; i++) {
    107                 this.jars[i] = this.jars[i].trim();
    108             }
     154        if (archive != null && archive.length() > 0) {
     155            String[] archives = archive.split(",");
     156
     157            addArchiveEntries(archives);
    109158
    110159            if (JNLPRuntime.isDebug()) {
    111                 System.err.println("Jar string: " + jar);
    112                 System.err.println("jars length: " + jars.length);
    113             }
    114         }
    115         this.atts = atts;
     160                System.err.println("Jar string: " + archive);
     161                System.err.println("jars length: " + archives.length);
     162            }
     163        }
    116164
    117165        name = atts.get("name");
     
    124172            main = main.substring(0, main.length() - 6);
    125173
    126         launchType = new AppletDesc(name, main, documentBase, width,
     174        // the class name should be of the form foo.bar.Baz not foo/bar/Baz
     175        String mainClass = main.replace('/', '.');
     176        launchType = new AppletDesc(name, mainClass, documentBase, width,
    127177                                    height, atts);
    128178
     
    133183            security = null;
    134184
    135         /* According to http://download.oracle.com/javase/6/docs/technotes/guides/deployment/deployment-guide/applet-compatibility.html,
    136          * classloaders are shared iff these properties match:
    137          * codebase, cache_archive, java_archive, archive
    138          *
    139          * To achieve this, we create the uniquekey based on those 4 values,
    140          * always in the same order. The initial "<NAME>=" parts ensure a
    141          * bad tag cannot trick the loader into getting shared with another.
    142          */
    143 
    144         // Firefox sometimes skips the codebase if it is default  -- ".",
    145         // so set it that way if absent
    146         String codebaseAttr =      atts.get("codebase") != null ?
    147                                    atts.get("codebase") : ".";
    148 
    149         String cache_archiveAttr = atts.get("cache_archive") != null ?
    150                                    atts.get("cache_archive") : "";
    151 
    152         String java_archiveAttr =  atts.get("java_archive") != null ?
    153                                    atts.get("java_archive") : "";
    154 
    155         String archiveAttr =       atts.get("archive") != null ?
    156                                    atts.get("archive") : "";
    157 
    158         this.uniqueKey = "codebase=" + codebaseAttr +
    159                          "cache_archive=" + cache_archiveAttr +
    160                          "java_archive=" + java_archiveAttr +
    161                          "archive=" +  archiveAttr;
    162 
     185        this.uniqueKey = uKey;
    163186        usePack = false;
    164187        useVersion = false;
     
    184207    }
    185208
     209    public boolean useJNLPHref() {
     210        return useJNLPHref;
     211    }
     212
    186213    /**
    187214     * {@inheritdoc }
     
    194221    public String getTitle() {
    195222        return name;
    196     }
    197 
    198     public InformationDesc getInformation(final Locale locale) {
    199         return new InformationDesc(this, new Locale[] { locale }) {
    200             protected List<Object> getItems(Object key) {
    201                 // Should we populate this list with applet attribute tags?
    202                 return new ArrayList<Object>();
    203             }
    204         };
    205223    }
    206224
     
    218236                        jarDescs.addAll(sharedResources.getResources(JARDesc.class));
    219237
    220                         for (int i = 0; i < jars.length; i++)
    221                             if (jars[i].length() > 0)
    222                                 jarDescs.add(new JARDesc(new URL(codeBase, jars[i]),
     238                        for (String name : jars) {
     239                            if (name.length() > 0)
     240                                jarDescs.add(new JARDesc(new URL(codeBase, name),
    223241                                        null, null, false, true, false, true));
     242                        }
    224243
    225244                        boolean cacheable = true;
     
    229248                            cacheable = false;
    230249
    231                         for (int i = 0; i < cacheJars.length; i++) {
    232 
    233                             String[] jarAndVer = cacheJars[i].split(";");
     250                        for (String cacheJar : cacheJars) {
     251
     252                            String[] jarAndVer = cacheJar.split(";");
    234253
    235254                            String jar = jarAndVer[0];
     
    247266                        }
    248267
    249                         for (int i = 0; i < cacheExJars.length; i++) {
    250 
    251                             if (cacheExJars[i].length() == 0)
     268                        for (String cacheExJar : cacheExJars) {
     269
     270                            if (cacheExJar.length() == 0)
    252271                                continue;
    253272
    254                             String[] jarInfo = cacheExJars[i].split(";");
     273                            String[] jarInfo = cacheExJar.split(";");
    255274
    256275                            String jar = jarInfo[0].trim();
     
    302321
    303322    /**
     323     * Returns the list of folders to be added to the codebase
     324     */
     325    public List<String> getCodeBaseFolders() {
     326        return new ArrayList<String>(codeBaseFolders);
     327    }
     328
     329    /**
    304330     * Returns the resources section of the JNLP file for the
    305331     * specified locale, os, and arch.
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/ResourcesDesc.java

    r348 r418  
    7676        JARDesc jars[] = getJARs();
    7777
    78         for (int i = 0; i < jars.length; i++)
    79             if (jars[i].isMain())
    80                 return jars[i];
     78        for (JARDesc jar : jars) {
     79            if (jar.isMain())
     80                return jar;
     81        }
    8182
    8283        if (jars.length > 0)
     
    161162        Map<String, String> properties = new HashMap<String, String>();
    162163        List<PropertyDesc> resources = getResources(PropertyDesc.class);
    163         for (int i = 0; i < resources.size(); i++) {
    164             PropertyDesc prop = resources.get(i);
     164        for (PropertyDesc prop : resources) {
    165165            properties.put(prop.getKey(), prop.getValue());
    166166        }
     
    206206        List<T> result = new ArrayList<T>();
    207207
    208         for (int i = 0; i < resources.size(); i++)
    209             if (type.isAssignableFrom(resources.get(i).getClass()))
    210                 result.add(type.cast(resources.get(i)));
     208        for (Object resource : resources) {
     209            if (type.isAssignableFrom(resource.getClass()))
     210                result.add(type.cast(resource));
     211        }
    211212
    212213        return result;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/SecurityDesc.java

    r348 r418  
    203203
    204204        // discard sandbox, give all
    205         if (type == ALL_PERMISSIONS) {
     205        if (ALL_PERMISSIONS.equals(type)) {
    206206            permissions = new Permissions();
    207207            if (customTrustedPolicy == null) {
     
    214214
    215215        // add j2ee to sandbox if needed
    216         if (type == J2EE_PERMISSIONS)
     216        if (J2EE_PERMISSIONS.equals(type))
    217217            for (int i = 0; i < j2eePermissions.length; i++)
    218218                permissions.add(j2eePermissions[i]);
     
    239239                permissions.add(jnlpRIAPermissions[i]);
    240240
    241         if (downloadHost != null)
     241        if (downloadHost != null && downloadHost.length() > 0)
    242242            permissions.add(new SocketPermission(downloadHost,
    243243                                                 "connect, accept"));
     
    245245        return permissions;
    246246    }
     247   
     248    /**
     249     * Returns all the names of the basic JNLP system properties accessible by RIAs
     250     */
     251    public static String[] getJnlpRIAPermissions() {
     252        String[] jnlpPermissions = new String[jnlpRIAPermissions.length];
     253
     254        for (int i = 0; i < jnlpRIAPermissions.length; i++)
     255            jnlpPermissions[i] = jnlpRIAPermissions[i].getName();
     256
     257        return jnlpPermissions;
     258    }
    247259
    248260}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/Version.java

    r348 r418  
    231231
    232232        // compare as integers
     233        // for normalization key, compare exact object, not using .equals
    233234        try {
    234235            if (!(part1 == emptyString)) // compare to magic normalization key
     
    243244        }
    244245
    245         if (part1 == emptyString)
     246        if (part1 == emptyString) // compare to magic normalization key
    246247            part1 = "";
    247         if (part2 == emptyString)
     248        if (part2 == emptyString) // compare to magic normalization key
    248249            part2 = "";
    249250
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/CacheLRUWrapper.java

    r348 r418  
    3737package net.sourceforge.jnlp.cache;
    3838
     39import java.util.Set;
     40import static  net.sourceforge.jnlp.runtime.Translator.R;
     41
    3942import java.io.File;
    4043import java.io.IOException;
     
    4447import java.util.Collections;
    4548import java.util.Comparator;
     49import java.util.Iterator;
    4650import java.util.List;
    4751import java.util.Map.Entry;
     
    6872
    6973    /* location of cache directory */
    70     private final String cacheDir = new File(JNLPRuntime.getConfiguration()
    71             .getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR)).getPath();
     74    private final String setCachePath = JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR);
     75    private final String cacheDir = new File(setCachePath != null ? setCachePath : System.getProperty("java.io.tmpdir")).getPath();
    7276
    7377    /*
     
    105109     */
    106110    public synchronized void load() {
    107         cacheOrder.load();
     111        boolean loaded = cacheOrder.load();
     112        /*
     113         * clean up possibly corrupted entries
     114         */
     115        if (loaded && checkData()) {
     116            if (JNLPRuntime.isDebug()) {
     117                new LruCacheException().printStackTrace();
     118            }
     119            System.out.println(R("CFakeCache"));
     120            store();
     121            System.out.println(R("CFakedCache"));
     122        }
     123    }
     124
     125    /**
     126     * check content of cacheOrder and remove invalid/corrupt entries
     127     *
     128     * @return true, if cache was corrupted and affected entry removed
     129     */
     130    private boolean checkData () {
     131        boolean modified = false;
     132        Set<Entry<Object, Object>> q = cacheOrder.entrySet();
     133        for (Iterator<Entry<Object, Object>> it = q.iterator(); it.hasNext();) {
     134            Entry<Object, Object> currentEntry = it.next();
     135
     136            final String key = (String) currentEntry.getKey();
     137            final String path = (String) currentEntry.getValue();
     138
     139            // 1. check key format: "milliseconds,number"
     140            try {
     141                String sa[] = key.split(",");
     142                Long l1 = Long.parseLong(sa[0]);
     143                Long l2 = Long.parseLong(sa[1]);
     144            } catch (Exception ex) {
     145                it.remove();
     146                modified = true;
     147                continue;
     148            }
     149
     150            // 2. check path format - does the path look correct?
     151            if (path != null) {
     152                if (path.indexOf(cacheDir) < 0) {
     153                    it.remove();
     154                    modified = true;
     155                }
     156            } else {
     157                it.remove();
     158                modified = true;
     159            }
     160        }
     161       
     162        return modified;
    108163    }
    109164
     
    173228            @Override
    174229            public int compare(Entry<String, String> e1, Entry<String, String> e2) {
    175                 try {
    176                     Long t1 = Long.parseLong(e1.getKey().split(",")[0]);
    177                     Long t2 = Long.parseLong(e2.getKey().split(",")[0]);
    178 
    179                     int c = t1.compareTo(t2);
    180                     return c < 0 ? 1 : (c > 0 ? -1 : 0);
    181                 } catch (NumberFormatException e) {
    182                     // Perhaps an error is too harsh. Maybe just somehow turn
    183                     // caching off if this is the case.
    184                     throw new InternalError("Corrupt LRU file entries");
    185                 }
     230                Long t1 = Long.parseLong(e1.getKey().split(",")[0]);
     231                Long t2 = Long.parseLong(e2.getKey().split(",")[0]);
     232
     233                int c = t1.compareTo(t2);
     234                return c < 0 ? 1 : (c > 0 ? -1 : 0);
    186235            }
    187236        });
     
    250299        return System.currentTimeMillis() + "," + getIdForCacheFolder(path);
    251300    }
     301
     302    void clearLRUSortedEntries() {
     303        cacheOrder.clear();
     304    }
    252305}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/CacheUtil.java

    r382 r418  
    4848public class CacheUtil {
    4949
    50     private static final String cacheDir = new File(JNLPRuntime.getConfiguration()
    51             .getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR)).getPath(); // Do this with file to standardize it.
     50    private static final String setCacheDir = JNLPRuntime.getConfiguration().getProperty(DeploymentConfiguration.KEY_USER_CACHE_DIR);
     51    private static final String cacheDir = new File(setCacheDir != null ? setCacheDir : System.getProperty("java.io.tmpdir")).getPath(); // Do this with file to standardize it.
    5252    private static final CacheLRUWrapper lruHandler = CacheLRUWrapper.getInstance();
    5353    private static final HashMap<String, FileLock> propertiesLockPool = new HashMap<String, FileLock>();
     
    6262     */
    6363    public static boolean urlEquals(URL u1, URL u2) {
    64         if (u1 == u2)
     64        if (u1 == u2) {
    6565            return true;
    66         if (u1 == null || u2 == null)
    67             return false;
    68 
    69         if (!compare(u1.getProtocol(), u2.getProtocol(), true) ||
    70                 !compare(u1.getHost(), u2.getHost(), true) ||
    71                 //u1.getDefaultPort() != u2.getDefaultPort() || // only in 1.4
    72                 !compare(u1.getPath(), u2.getPath(), false) ||
    73                 !compare(u1.getQuery(), u2.getQuery(), false) ||
    74                 !compare(u1.getRef(), u2.getRef(), false))
    75             return false;
    76         else
     66        }
     67        if (u1 == null || u2 == null) {
     68            return false;
     69        }
     70
     71        if (notNullUrlEquals(u1, u2)) {
    7772            return true;
    78     }
    79 
     73        }
     74        try {
     75            URL nu1 = ResourceTracker.normalizeUrl(u1, false);
     76            URL nu2 = ResourceTracker.normalizeUrl(u2, false);
     77            if (notNullUrlEquals(nu1, nu2)) {
     78                return true;
     79            }
     80        } catch (Exception ex) {
     81            //keep silent here and return false
     82        }
     83        return false;
     84    }
     85
     86    private static boolean notNullUrlEquals(URL u1, URL u2) {
     87        if (!compare(u1.getProtocol(), u2.getProtocol(), true)
     88                || !compare(u1.getHost(), u2.getHost(), true)
     89                || //u1.getDefaultPort() != u2.getDefaultPort() || // only in 1.4
     90                !compare(u1.getPath(), u2.getPath(), false)
     91                || !compare(u1.getQuery(), u2.getQuery(), false)
     92                || !compare(u1.getRef(), u2.getRef(), false)) {
     93            return false;
     94        } else {
     95            return true;
     96        }
     97    }
    8098    /**
    8199     * Caches a resource and returns a URL for it in the cache;
     
    145163     * and we check for those by calling {@link #okToClearCache()}
    146164     */
    147     public static void clearCache() {
     165    public static boolean clearCache() {
    148166
    149167        if (!okToClearCache()) {
    150168            System.err.println(R("CCannotClearCache"));
    151             return;
     169            return false;
    152170        }
    153171
    154172        File cacheDir = new File(CacheUtil.cacheDir);
    155173        if (!(cacheDir.isDirectory())) {
    156             return;
     174            return false;
    157175        }
    158176
     
    166184            throw new RuntimeException(e);
    167185        }
     186        return true;
    168187    }
    169188
     
    307326            if (cacheFile == null) { // We did not find a copy of it.
    308327                cacheFile = makeNewCacheFile(source, version);
    309             }
    310             lruHandler.store();
     328            } else
     329                lruHandler.store();
    311330            lruHandler.unlock();
    312331        }
     
    329348                final String path = e.getValue();
    330349
    331                 if (path != null) {
    332                     if (pathToURLPath(path).equals(urlPath.getPath())) { // Match found.
    333                         cacheFile = new File(path);
    334                         lruHandler.updateEntry(key);
    335                         break; // Stop searching since we got newest one already.
    336                     }
     350                if (pathToURLPath(path).equals(urlPath.getPath())) { // Match found.
     351                    cacheFile = new File(path);
     352                    lruHandler.updateEntry(key);
     353                    break; // Stop searching since we got newest one already.
    337354                }
    338355            }
     
    481498            // only resources not starting out downloaded are displayed
    482499            List<URL> urlList = new ArrayList<URL>();
    483             for (int i = 0; i < resources.length; i++) {
    484                 if (!tracker.checkResource(resources[i]))
    485                     urlList.add(resources[i]);
     500            for (URL url : resources) {
     501                if (!tracker.checkResource(url))
     502                    urlList.add(url);
    486503            }
    487504            URL undownloaded[] = urlList.toArray(new URL[urlList.size()]);
     
    493510                long total = 0;
    494511
    495                 for (int i = 0; i < undownloaded.length; i++) {
     512                for (URL url : undownloaded) {
    496513                    // add in any -1's; they're insignificant
    497                     total += tracker.getTotalSize(undownloaded[i]);
    498                     read += tracker.getAmountRead(undownloaded[i]);
     514                    total += tracker.getTotalSize(url);
     515                    read += tracker.getAmountRead(url);
    499516                }
    500517
    501518                int percent = (int) ((100 * read) / Math.max(1, total));
    502519
    503                 for (int i = 0; i < undownloaded.length; i++)
    504                     listener.progress(undownloaded[i], "version",
    505                                       tracker.getAmountRead(undownloaded[i]),
    506                                       tracker.getTotalSize(undownloaded[i]),
     520                for (URL url : undownloaded) {
     521                    listener.progress(url, "version",
     522                                      tracker.getAmountRead(url),
     523                                      tracker.getTotalSize(url),
    507524                                      percent);
     525                }
    508526            } while (!tracker.waitForResources(resources, indicator.getUpdateRate()));
    509527
    510528            // make sure they read 100% until indicator closes
    511             for (int i = 0; i < undownloaded.length; i++)
    512                 listener.progress(undownloaded[i], "version",
    513                                   tracker.getTotalSize(undownloaded[i]),
    514                                   tracker.getTotalSize(undownloaded[i]),
     529            for (URL url : undownloaded) {
     530                listener.progress(url, "version",
     531                                  tracker.getTotalSize(url),
     532                                  tracker.getTotalSize(url),
    515533                                  100);
    516 
     534            }
    517535        } catch (InterruptedException ex) {
    518536            if (JNLPRuntime.isDebug())
     
    528546     */
    529547    public static void cleanCache() {
     548
    530549        if (okToClearCache()) {
    531550            // First we want to figure out which stuff we need to delete.
     
    546565                // Check if the item is contained in cacheOrder.
    547566                final String key = e.getKey();
    548                 final String value = e.getValue();
    549 
    550                 if (value != null) {
    551                     File file = new File(value);
    552                     PropertiesFile pf = new PropertiesFile(new File(value + ".info"));
    553                     boolean delete = Boolean.parseBoolean(pf.getProperty("delete"));
    554 
    555                     /*
    556                      * This will get me the root directory specific to this cache item.
    557                      * Example:
    558                      *  cacheDir = /home/user1/.icedtea/cache
    559                      *  file.getPath() = /home/user1/.icedtea/cache/0/http/www.example.com/subdir/a.jar
    560                      *  rStr first becomes: /0/http/www.example.com/subdir/a.jar
    561                      *  then rstr becomes: /home/user1/.icedtea/cache/0
    562                      */
    563                     String rStr = file.getPath().substring(cacheDir.length());
    564                     rStr = cacheDir + rStr.substring(0, rStr.indexOf(File.separatorChar, 1));
    565                     long len = file.length();
    566 
    567                     if (keep.contains(file.getPath().substring(rStr.length()))) {
    568                         lruHandler.removeEntry(key);
    569                         continue;
    570                     }
    571                    
    572                     /*
    573                      * we remove entries from our lru if any of the following condition is met.
    574                      * Conditions:
    575                      *  - delete: file has been marked for deletion.
    576                      *  - !file.isFile(): if someone tampered with the directory, file doesn't exist.
    577                      *  - maxSize >= 0 && curSize + len > maxSize: If a limit was set and the new size
    578                      *  on disk would exceed the maximum size.
    579                      */
    580                     if (delete || !file.isFile() || (maxSize >= 0 && curSize + len > maxSize)) {
    581                         lruHandler.removeEntry(key);
    582                         remove.add(rStr);
    583                     } else {
    584                         curSize += len;
    585                         keep.add(file.getPath().substring(rStr.length()));
    586 
    587                         for (File f : file.getParentFile().listFiles()) {
    588                             if (!(f.equals(file) || f.equals(pf.getStoreFile()))){
    589                                 try {
    590                                     FileUtils.recursiveDelete(f, f);
    591                                 } catch (IOException e1) {
    592                                     e1.printStackTrace();
    593                                 }
    594                             }
     567                final String path = e.getValue();
     568
     569                File file = new File(path);
     570                PropertiesFile pf = new PropertiesFile(new File(path + ".info"));
     571                boolean delete = Boolean.parseBoolean(pf.getProperty("delete"));
     572
     573                /*
     574                 * This will get me the root directory specific to this cache item.
     575                 * Example:
     576                 *  cacheDir = /home/user1/.icedtea/cache
     577                 *  file.getPath() = /home/user1/.icedtea/cache/0/http/www.example.com/subdir/a.jar
     578                 *  rStr first becomes: /0/http/www.example.com/subdir/a.jar
     579                 *  then rstr becomes: /home/user1/.icedtea/cache/0
     580                 */
     581                String rStr = file.getPath().substring(cacheDir.length());
     582                rStr = cacheDir + rStr.substring(0, rStr.indexOf(File.separatorChar, 1));
     583                long len = file.length();
     584
     585                if (keep.contains(file.getPath().substring(rStr.length()))) {
     586                    lruHandler.removeEntry(key);
     587                    continue;
     588                }
     589
     590                /*
     591                 * we remove entries from our lru if any of the following condition is met.
     592                 * Conditions:
     593                 *  - delete: file has been marked for deletion.
     594                 *  - !file.isFile(): if someone tampered with the directory, file doesn't exist.
     595                 *  - maxSize >= 0 && curSize + len > maxSize: If a limit was set and the new size
     596                 *  on disk would exceed the maximum size.
     597                 */
     598                if (delete || !file.isFile() || (maxSize >= 0 && curSize + len > maxSize)) {
     599                    lruHandler.removeEntry(key);
     600                    remove.add(rStr);
     601                    continue;
     602                }
     603
     604                curSize += len;
     605                keep.add(file.getPath().substring(rStr.length()));
     606
     607                for (File f : file.getParentFile().listFiles()) {
     608                    if (!(f.equals(file) || f.equals(pf.getStoreFile()))) {
     609                        try {
     610                            FileUtils.recursiveDelete(f, f);
     611                        } catch (IOException e1) {
     612                            e1.printStackTrace();
    595613                        }
    596614                    }
    597                 } else {
    598                     lruHandler.removeEntry(key);
     615
    599616                }
    600617            }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/DefaultDownloadIndicator.java

    r348 r418  
    2929
    3030import net.sourceforge.jnlp.runtime.*;
     31import net.sourceforge.jnlp.util.ImageResources;
    3132
    3233/**
     
    5859    /** the display window */
    5960    private static JFrame frame;
     61    private static final Object frameMutex = new Object();
    6062
    6163    /** shared constraint */
     
    98100        DownloadPanel result = new DownloadPanel(downloadName);
    99101
    100         if (frame == null) {
    101             frame = new JFrame(downloading + "...");
    102             frame.getContentPane().setLayout(new GridBagLayout());
    103         }
    104 
    105         if (resources != null)
    106             for (int i = 0; i < resources.length; i++)
    107                 result.addProgressPanel(resources[i], null);
    108 
    109         frame.getContentPane().add(result, vertical);
    110         frame.pack();
    111 
    112         if (!frame.isVisible()) {
    113             Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    114             Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration());
    115             Dimension screen = new Dimension(screenSize.width - insets.left,
    116                     screenSize.height - insets.top);
    117             frame.setLocation(screen.width - frame.getWidth(),
    118                               screen.height - frame.getHeight());
    119         }
    120 
    121         frame.setVisible(true);
    122 
    123         return result;
     102        synchronized (frameMutex) {
     103            if (frame == null) {
     104                frame = new JFrame(downloading + "...");
     105                frame.setIconImages(ImageResources.INSTANCE.getApplicationImages());
     106                frame.getContentPane().setLayout(new GridBagLayout());
     107            }
     108
     109            if (resources != null) {
     110                for (URL url : resources) {
     111                    result.addProgressPanel(url, null);
     112                }
     113            }
     114
     115            frame.getContentPane().add(result, vertical);
     116            frame.pack();
     117
     118            if (!frame.isVisible()) {
     119                Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
     120                Insets insets = Toolkit.getDefaultToolkit().getScreenInsets(frame.getGraphicsConfiguration());
     121                Dimension screen = new Dimension(screenSize.width - insets.left,
     122                        screenSize.height - insets.top);
     123                frame.setLocation(screen.width - frame.getWidth(),
     124                        screen.height - frame.getHeight());
     125            }
     126
     127            frame.setVisible(true);
     128
     129            return result;
     130        }
    124131    }
    125132
     
    135142        ActionListener hider = new ActionListener() {
    136143            public void actionPerformed(ActionEvent evt) {
    137                 if (frame.getContentPane().getComponentCount() == 1)
    138                     frame.setVisible(false);
    139 
    140                 frame.getContentPane().remove((DownloadPanel) listener);
    141                 frame.pack();
     144                synchronized(frameMutex) {
     145                    frame.getContentPane().remove((DownloadPanel) listener);
     146                    frame.pack();
     147
     148                    if (frame.getContentPane().getComponentCount() == 0) {
     149                        frame.setVisible(false);
     150                        frame.dispose();
     151                        frame = null;
     152                    }
     153                }
    142154            }
    143155        };
     
    187199
    188200                add(panel, verticalIndent);
    189                 frame.pack();
     201                synchronized (frameMutex) {
     202                    frame.pack();
     203                }
    190204
    191205                urls.add(url);
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/Resource.java

    r348 r418  
    273273        }
    274274
    275         for (int i = 0; i < send.size(); i++) {
    276             ResourceTracker rt = send.get(i);
     275        for (ResourceTracker rt : send) {
    277276            rt.fireDownloadEvent(this);
    278277        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/cache/ResourceTracker.java

    r348 r418  
    2525import java.io.InputStream;
    2626import java.io.OutputStream;
     27import java.io.UnsupportedEncodingException;
    2728import java.net.HttpURLConnection;
    2829import java.net.MalformedURLException;
    2930import java.net.URL;
    3031import java.net.URLConnection;
     32import java.net.URLDecoder;
     33import java.net.URLEncoder;
    3134import java.security.AccessController;
    3235import java.security.PrivilegedAction;
     
    109112    private static final int STARTED = Resource.STARTED;
    110113
     114    // normalization of url
     115    private static final char PATH_DELIMITER_MARK = '/';
     116    private static final String PATH_DELIMITER = "" + PATH_DELIMITER_MARK;
     117    private static final char QUERY_DELIMITER_MARK = '&';
     118    private static final String QUERY_DELIMITER = "" + QUERY_DELIMITER_MARK;
     119    private static final char QUERY_MARK = '?';
     120    private static final char HREF_MARK = '#';
     121    private static final String UTF8 = "utf-8";
     122
    111123    /** max threads */
    112124    private static final int maxThreads = 5;
     
    173185    public void addResource(URL location, Version version, DownloadOptions options, UpdatePolicy updatePolicy) {
    174186        if (location == null)
    175             throw new IllegalArgumentException("location==null");
    176 
     187            throw new IllegalResourceDescriptorException("location==null");
     188        try {
     189            location = normalizeUrl(location, JNLPRuntime.isDebug());
     190        } catch (Exception ex) {
     191            System.err.println("Normalization of " + location.toString() + " have failed");
     192            ex.printStackTrace();
     193        }
    177194        Resource resource = Resource.getResource(location, version, updatePolicy);
    178195        boolean downloaded = false;
     
    209226     * collected.
    210227     *
    211      * @throws IllegalArgumentException if the resource is not being tracked
     228     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    212229     */
    213230    public void removeResource(URL location) {
     
    315332
    316333        DownloadEvent event = new DownloadEvent(this, resource);
    317         for (int i = 0; i < l.length; i++) {
     334        for (DownloadListener dl : l) {
    318335            if (0 != ((ERROR | DOWNLOADED) & status))
    319                 l[i].downloadCompleted(event);
     336                dl.downloadCompleted(event);
    320337            else if (0 != (DOWNLOADING & status))
    321                 l[i].downloadStarted(event);
     338                dl.downloadStarted(event);
    322339            else if (0 != (CONNECTING & status))
    323                 l[i].updateStarted(event);
     340                dl.updateStarted(event);
    324341        }
    325342    }
     
    335352     * @param location the resource location
    336353     * @return the resource, or null if it could not be downloaded
    337      * @throws IllegalArgumentException if the resource is not being tracked
     354     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    338355     * @see CacheUtil#isCacheable
    339356     */
     
    362379     * @param location the resource location
    363380     * @return a local file containing the resource, or null
    364      * @throws IllegalArgumentException if the resource is not being tracked
     381     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    365382     * @see CacheUtil#isCacheable
    366383     */
     
    402419     *
    403420     * @throws IOException if there was an error opening the stream
    404      * @throws IllegalArgumentException if the resource is not being tracked
     421     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    405422     */
    406423    public InputStream getInputStream(URL location) throws IOException {
     
    426443     * @param timeout the time in ms to wait before returning, 0 for no timeout
    427444     * @return whether the resources downloaded before the timeout
    428      * @throws IllegalArgumentException if the resource is not being tracked
     445     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    429446     */
    430447    public boolean waitForResources(URL urls[], long timeout) throws InterruptedException {
     
    433450        synchronized (resources) {
    434451            // keep the lock so getResource doesn't have to aquire it each time
    435             for (int i = 0; i < urls.length; i++)
     452            for (int i = 0; i < urls.length; i++) {
    436453                resources[i] = getResource(urls[i]);
     454            }
    437455        }
    438456
     
    451469     * @return whether the resource downloaded before the timeout
    452470     * @throws InterruptedException if another thread interrupted the wait
    453      * @throws IllegalArgumentException if the resource is not being tracked
     471     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    454472     */
    455473    public boolean waitForResource(URL location, long timeout) throws InterruptedException {
     
    462480     * @param location the resource location
    463481     * @return the number of bytes transferred
    464      * @throws IllegalArgumentException if the resource is not being tracked
     482     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    465483     */
    466484    public long getAmountRead(URL location) {
     
    474492     * accessed with the getCacheFile method).
    475493     *
    476      * @throws IllegalArgumentException if the resource is not being tracked
     494     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    477495     */
    478496    public boolean checkResource(URL location) {
     
    488506     *
    489507     * @return true if the resource is already downloaded (or an error occurred)
    490      * @throws IllegalArgumentException if the resource is not being tracked
     508     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    491509     */
    492510    public boolean startResource(URL location) {
     
    501519     *
    502520     * @return true if the resource is already downloaded (or an error occurred)
    503      * @throws IllegalArgumentException if the resource is not being tracked
     521     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    504522     */
    505523    private boolean startResource(Resource resource) {
     
    533551     * @param location the resource location
    534552     * @return the number of bytes, or -1
    535      * @throws IllegalArgumentException if the resource is not being tracked
     553     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    536554     */
    537555    public long getTotalSize(URL location) {
     
    589607        synchronized (lock) {
    590608            if (!resource.isSet(CONNECT | DOWNLOAD))
    591                 throw new IllegalArgumentException("Invalid resource state (resource: " + resource + ")");
     609                throw new IllegalResourceDescriptorException("Invalid resource state (resource: " + resource + ")");
    592610
    593611            queue.add(resource);
     
    852870        }
    853871        URL bestUrl = null;
    854         for (int i = 0; i < urls.size(); i++) {
    855             URL url = urls.get(i);
     872        for (URL url : urls) {
    856873            try {
    857874                URLConnection connection = url.openConnection();
     
    9831000        int score = Integer.MAX_VALUE;
    9841001
    985         for (int i = 0; i < source.size(); i++) {
    986             Resource resource = source.get(i);
     1002        for (Resource resource : source) {
    9871003            boolean selectable = false;
    9881004
     
    9951011                int activeCount = 0;
    9961012
    997                 for (int j = 0; j < active.size(); j++)
    998                     if (active.get(j) == resource.getTracker())
     1013                for (ResourceTracker rt : active) {
     1014                    if (rt == resource.getTracker())
    9991015                        activeCount++;
     1016                }
    10001017
    10011018                // try to spread out the downloads so that a slow host
     
    10141031     * Return the resource matching the specified URL.
    10151032     *
    1016      * @throws IllegalArgumentException if the resource is not being tracked
     1033     * @throws IllegalResourceDescriptorException if the resource is not being tracked
    10171034     */
    10181035    private Resource getResource(URL location) {
    10191036        synchronized (resources) {
    1020             for (int i = 0; i < resources.size(); i++) {
    1021                 Resource resource = resources.get(i);
    1022 
     1037            for (Resource resource : resources) {
    10231038                if (CacheUtil.urlEquals(resource.location, location))
    10241039                    return resource;
     
    10261041        }
    10271042
    1028         throw new IllegalArgumentException("Location does not specify a resource being tracked.");
     1043        throw new IllegalResourceDescriptorException("Location does not specify a resource being tracked.");
    10291044    }
    10301045
     
    10421057
    10431058        // start them downloading / connecting in background
    1044         for (int i = 0; i < resources.length; i++)
    1045             startResource(resources[i]);
     1059        for (Resource resource : resources) {
     1060            startResource(resource);
     1061        }
    10461062
    10471063        // wait for completion
     
    10511067            synchronized (lock) {
    10521068                // check for completion
    1053                 for (int i = 0; i < resources.length; i++) {
     1069                for (Resource resource : resources) {
    10541070                    //NetX Deadlocking may be solved by removing this
    10551071                    //synch block.
    1056                     synchronized (resources[i]) {
    1057                         if (!resources[i].isSet(DOWNLOADED | ERROR)) {
     1072                    synchronized (resource) {
     1073                        if (!resource.isSet(DOWNLOADED | ERROR)) {
    10581074                            finished = false;
    10591075                            break;
     
    11281144    };
    11291145
     1146    private static String normalizeChunk(String base, boolean debug) throws UnsupportedEncodingException {
     1147        if (base == null) {
     1148            return base;
     1149        }
     1150        if ("".equals(base)) {
     1151            return base;
     1152        }
     1153        String result = base;
     1154        String ssE = URLDecoder.decode(base, UTF8);
     1155        //            System.out.println("*" + base + "*");
     1156        //            System.out.println("-" + ssE + "-");
     1157        if (base.equals(ssE)) {
     1158            result = URLEncoder.encode(base, UTF8);
     1159            if (debug) {
     1160                System.out.println(base + " chunk needs to be encoded => " + result);
     1161            }
     1162        } else {
     1163            if (debug) {
     1164                System.out.println(base + " chunk already encoded");
     1165            }
     1166        }
     1167        return result;
     1168    }
     1169
     1170    public static URL normalizeUrl(URL u, boolean debug) throws MalformedURLException, UnsupportedEncodingException {
     1171        if (u == null) {
     1172            return null;
     1173        }
     1174        String protocol = u.getProtocol();
     1175        if (protocol == null || "file".equals(protocol)) {
     1176            return u;
     1177        }
     1178        String file = u.getPath();
     1179        if (file == null) {
     1180            return u;
     1181        }
     1182        String host = u.getHost();
     1183        String ref = u.getRef();
     1184        int port = u.getPort();
     1185        String query = u.getQuery();
     1186        String[] qq = {};
     1187        if (query != null) {
     1188            qq = query.split(QUERY_DELIMITER);
     1189        }
     1190        String[] ss = file.split(PATH_DELIMITER);
     1191        int normalized = 0;
     1192        if (debug) {
     1193            System.out.println("normalizing path " + file + " in " + u.toString());
     1194        }
     1195        for (int i = 0; i < ss.length; i++) {
     1196            String base = ss[i];
     1197            String r = normalizeChunk(base, debug);
     1198            if (!r.equals(ss[i])) {
     1199                normalized++;
     1200            }
     1201            ss[i] = r;
     1202        }
     1203        if (debug) {
     1204            System.out.println("normalizing query " + query + " in " + u.toString());
     1205        }
     1206        for (int i = 0; i < qq.length; i++) {
     1207            String base = qq[i];
     1208            String r = normalizeChunk(base, debug);
     1209            if (!r.equals(qq[i])) {
     1210                normalized++;
     1211            }
     1212            qq[i] = r;
     1213        }
     1214        if (normalized == 0) {
     1215            if (debug) {
     1216                System.out.println("Nothing was normalized in this url");
     1217            }
     1218            return u;
     1219        } else {
     1220            if (debug) {
     1221                System.out.println(normalized + " chunks normalized, rejoining url");
     1222            }
     1223        }
     1224        StringBuilder composed = new StringBuilder("");
     1225        for (int i = 0; i < ss.length; i++) {
     1226            String string = ss[i];
     1227            if (ss.length <= 1 || (string != null && !"".equals(string))) {
     1228                composed.append(PATH_DELIMITER_MARK).append(string);
     1229            }
     1230        }
     1231        String composed1 = composed.toString();
     1232        if (query != null && !query.trim().equals("")) {
     1233            composed.append(QUERY_MARK);
     1234            for (int i = 0; i < qq.length; i++) {
     1235                String string = qq[i];
     1236                if ((string != null && !"".equals(string))) {
     1237                    composed.append(string);
     1238                    if (i != qq.length - 1) {
     1239                        composed.append(QUERY_DELIMITER_MARK);
     1240                    }
     1241                }
     1242            }
     1243        }
     1244        String composed2 = composed.substring(composed1.length() - 1);
     1245        if (ref != null && !ref.trim().equals("")) {
     1246            composed.append(HREF_MARK).append(ref);
     1247        }
     1248
     1249        URL result = new URL(protocol, host, port, composed.toString());
     1250
     1251        if (debug) {
     1252            System.out.println("normalized `" + composed1 + "` and `" + composed2 + "` in " + result.toString());
     1253        }
     1254        return result;
     1255
     1256    }
    11301257}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/AdvancedProxySettingsDialog.java

    r348 r418  
    3232import net.sourceforge.jnlp.config.DeploymentConfiguration;
    3333import net.sourceforge.jnlp.runtime.Translator;
     34import net.sourceforge.jnlp.util.ImageResources;
    3435
    3536/**
     
    5556    public AdvancedProxySettingsDialog(DeploymentConfiguration config) {
    5657        super((Frame) null, dialogTitle, true); // Don't need a parent.
     58        setIconImages(ImageResources.INSTANCE.getApplicationImages());
     59
    5760        this.config = config;
    5861
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/CacheViewer.java

    r348 r418  
    3131import net.sourceforge.jnlp.config.DeploymentConfiguration;
    3232import net.sourceforge.jnlp.runtime.Translator;
     33import net.sourceforge.jnlp.util.ImageResources;
    3334
    3435/**
     
    5253    public CacheViewer(DeploymentConfiguration config) {
    5354        super((Frame) null, dialogTitle, true); // Don't need a parent.
     55        setIconImages(ImageResources.INSTANCE.getApplicationImages());
    5456        this.config = config;
    5557
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/ControlPanel.java

    r348 r418  
    5656import net.sourceforge.jnlp.security.KeyStores;
    5757import net.sourceforge.jnlp.security.viewer.CertificatePane;
     58import net.sourceforge.jnlp.util.ImageResources;
    5859
    5960/**
     
    103104        super();
    104105        setTitle(Translator.R("CPHead"));
     106        setIconImages(ImageResources.INSTANCE.getApplicationImages());
    105107
    106108        this.config = config;
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/controlpanel/TemporaryInternetFilesPanel.java

    r348 r418  
    2727import java.awt.event.ItemEvent;
    2828import java.awt.event.ItemListener;
     29import java.io.File;
    2930
    3031import javax.swing.JButton;
     
    3435import javax.swing.JFileChooser;
    3536import javax.swing.JLabel;
     37import javax.swing.JOptionPane;
    3638import javax.swing.JPanel;
    3739import javax.swing.JSlider;
     
    110112                JFileChooser fileChooser = new JFileChooser();
    111113                fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
     114                fileChooser.setFileHidingEnabled(false);
    112115                if (fileChooser.showOpenDialog(null) == JFileChooser.APPROVE_OPTION) {
     116                    // Check if we have permission to write to that location.
    113117                    String result = fileChooser.getSelectedFile().getAbsolutePath();
    114                     location.setText(result);
    115                     config.setProperty(properties[1], result);
     118                    File dirLocation = new File(result);
     119                    boolean canWrite = dirLocation.canWrite();
     120                    while (!canWrite && dirLocation != null){ // File does not exist, or no permission.
     121                       
     122                        if (dirLocation.exists()) {
     123                            JOptionPane.showMessageDialog(null, "No permission to write to this location.");
     124                            return;
     125                        }
     126                       
     127                        dirLocation = dirLocation.getParentFile();
     128                        canWrite = dirLocation.canWrite();
     129                    }
     130                   
     131                    if (canWrite) {
     132                        location.setText(result);
     133                        config.setProperty(properties[1], result);
     134                    }
    116135                }
    117136            }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/resources/Messages.properties

    r372 r418  
    8181LSignedAppJarUsingUnsignedJar=Signed application using unsigned jars.
    8282LSignedAppJarUsingUnsignedJarInfo=The main application jar is signed, but some of the jars it is using aren't.
    83 
     83LSignedJNLPFileDidNotMatch=The signed JNLP file did not match the launching JNLP file.
     84LNoSecInstance=Error: No security instance for {0}. The application may have trouble continuing
     85LCertFoundIn={0} found in cacerts ({1})
     86 
    8487JNotApplet=File is not an applet.
    8588JNotApplication=File is not an application.
     
    104107PTwoMains=Duplicate main JAR defined in a resources element (there can be only one)
    105108PNativeHasMain=Cannot specify main attribute on native JARs.
    106 PNoInfoElement=No information section defined
     109PNoInfoElement=No information section defined.
     110PMissingTitle=title
     111PMissingVendor=vendor
     112PMissingElement=The {0} section has not been defined for your locale nor does a default value exist in the JNLP file.
    107113PTwoDescriptions=Duplicate description of kind {0}
    108114PSharing=Element "sharing-allowed" is illegal in a standard JNLP file
     
    120126PUrlNotInCodebase=Relative URL does not specify a subdirectory of the codebase. (node={0}, href={1}, base={2})
    121127PBadRelativeUrl=Invalid relative URL (node={0}, href={1}, base={2})
    122 PBadNonrelativeUrl=Invalid non-relative URL (node={0}, href={0}).
     128PBadNonrelativeUrl=Invalid non-relative URL (node={0}, href={1})
    123129PNeedsAttribute=The {0} element must specify a {1} attribute.
    124130PBadXML=Invalid XML document syntax.
     
    190196CChooseCacheDir=Cache directory
    191197CCannotClearCache=Can not clear cache at this time
     198CFakeCache=Cache is corrupt. Fixing.
     199CFakedCache=Cache is corrupt and has been fixed. It is strongly recommended that you run 'javaws -Xclearcache' and rerun your application as soon as possible.
    192200
    193201# Security
     
    199207SSignatureError=The application's digital signature has an error. Do you want to run the application?
    200208SUntrustedSource=The digital signature could not be verified by a trusted source. Only run if you trust the origin of the application.
     209SWarnFullPermissionsIgnorePolicy=The code executed will be given full permissions, ignoring any java policies you may have.
    201210STrustedSource=The digital signature has been validated by a trusted source.
    202211SClipboardReadAccess=The application has requested read-only access to the system clipboard. Do you want to allow this action?
     
    205214SNetworkAccess=The application has requested permission to establish connections to {0}. Do you want to allow this action?
    206215SNoAssociatedCertificate=<no associated certificate>
     216SUnverified=(unverified)
    207217SAlwaysTrustPublisher=Always trust content from this publisher
    208 SHttpsUnverified=The website's certificate cannot be verified.
     218SHttpsUnverified=The website's HTTPS certificate cannot be verified.
    209219SNotAllSignedSummary=Only parts of this application code are signed.
    210220SNotAllSignedDetail=This application contains both signed and unsigned code. While signed code is safe if you trust the provider, unsigned code may imply code outside of the trusted provider's control.
    211221SNotAllSignedQuestion=Do you wish to proceed and run this application anyway?
    212222SAuthenticationPrompt=The {0} server at {1} is requesting authentication. It says "{2}"
     223SJNLPFileIsNotSigned=This application contains a digital signature in which the launching JNLP file is not signed.
    213224
    214225# Security - used for the More Information dialog
     
    241252CVDetails=Details
    242253CVExport=Export
     254CVExportPasswordMessage=Enter password to protect key file:
    243255CVImport=Import
     256CVImportPasswordMessage=Enter password to access file:
    244257CVIssuedBy=Issued By
    245258CVIssuedTo=Issued To
     259CVPasswordTitle=Authentication Required
    246260CVRemove=Remove
    247261CVRemoveConfirmMessage=Are you sure you want to remove the selected certificate?
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/AppletEnvironment.java

    r348 r418  
    117117
    118118        List<AppletAudioClip> clips = weakClips.hardList();
    119         for (int i = 0; i < clips.size(); i++) {
    120             clips.get(i).dispose();
     119        for (AppletAudioClip clip : clips) {
     120            clip.dispose();
    121121        }
    122122    }
     
    208208
    209209    /**
     210     * Set the applet of this environment; can only be called once.
     211     */
     212    public void setApplet(Applet applet) {
     213        if (this.applet != null) {
     214            if (JNLPRuntime.isDebug()) {
     215                Exception ex = new IllegalStateException("Applet can only be set once.");
     216                ex.printStackTrace();
     217            }
     218            return;
     219        }
     220        this.applet = applet;
     221    }
     222
     223    /**
    210224     * Returns an enumeration that contains only the applet
    211225     * from the JNLP file.
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/AppletInstance.java

    r348 r418  
    5050
    5151        this.environment = new AppletEnvironment(file, this);
     52    }
     53
     54    /**
     55     * Set the applet of this launched application; can only be called once.
     56     */
     57    public void setApplet(Applet applet) {
     58        if (this.applet != null) {
     59            if (JNLPRuntime.isDebug()) {
     60                Exception ex = new IllegalStateException("Applet can only be set once.");
     61                ex.printStackTrace();
     62            }
     63            return;
     64        }
     65        this.applet = applet;
    5266    }
    5367
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/ApplicationInstance.java

    r348 r418  
    232232        PrivilegedAction<Object> installProps = new PrivilegedAction<Object>() {
    233233            public Object run() {
    234                 for (int i = 0; i < props.length; i++) {
    235                     System.setProperty(props[i].getKey(), props[i].getValue());
     234                for (PropertyDesc propDesc : props) {
     235                    System.setProperty(propDesc.getKey(), propDesc.getValue());
    236236                }
    237237
     
    273273        try {
    274274            // destroy resources
    275             for (int i = 0; i < weakWindows.size(); i++) {
    276                 Window w = weakWindows.get(i);
     275            for (Window w : weakWindows) {
    277276                if (w != null)
    278277                    w.dispose();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/Boot.java

    r348 r418  
    157157            JNLPRuntime.setForksAllowed(false);
    158158        }
     159        if (null != getOption("-Xtrustall")) {
     160            JNLPRuntime.setTrustAll(true);
     161        }
    159162
    160163        JNLPRuntime.setInitialArgments(Arrays.asList(argsIn));
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/CachedJarFileCallback.java

    r348 r418  
    9595        if (UrlUtils.isLocalFile(localUrl)) {
    9696            // if it is known to us, just return the cached file
    97             return new JarFile(localUrl.getPath());
     97            JarFile returnFile = new JarFile(localUrl.getPath());
     98           
     99            try {
     100               
     101                // Blank out the class-path because:
     102                // 1) Web Start does not support it
     103                // 2) For the plug-in, we want to cache files from class-path so we do it manually
     104                returnFile.getManifest().getMainAttributes().putValue("Class-Path", "");
     105
     106                if (JNLPRuntime.isDebug()) {
     107                    System.err.println("Class-Path attribute cleared for " + returnFile.getName());
     108                }
     109
     110            } catch (NullPointerException npe) {
     111                // Discard NPE here. Maybe there was no manifest, maybe there were no attributes, etc.
     112            }
     113
     114            return returnFile;
    98115        } else {
    99116            // throw new IllegalStateException("a non-local file in cache");
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPClassLoader.java

    r348 r418  
    1818import static net.sourceforge.jnlp.runtime.Translator.R;
    1919
     20import java.io.Closeable;
    2021import java.io.File;
    2122import java.io.FileOutputStream;
     23import java.io.FileReader;
    2224import java.io.IOException;
    2325import java.io.InputStream;
     26import java.io.InputStreamReader;
    2427import java.net.MalformedURLException;
     28import java.net.SocketPermission;
    2529import java.net.URL;
    2630import java.net.URLClassLoader;
    2731import java.security.AccessControlContext;
     32import java.security.AccessControlException;
    2833import java.security.AccessController;
    2934import java.security.AllPermission;
     
    3338import java.security.Permissions;
    3439import java.security.PrivilegedAction;
     40import java.security.PrivilegedActionException;
     41import java.security.PrivilegedExceptionAction;
     42import java.security.ProtectionDomain;
    3543import java.util.ArrayList;
     44import java.util.Arrays;
     45import java.util.Collection;
    3646import java.util.Collections;
    3747import java.util.Enumeration;
    3848import java.util.HashMap;
    3949import java.util.HashSet;
     50import java.util.Iterator;
    4051import java.util.LinkedList;
    4152import java.util.List;
     
    4455import java.util.TreeSet;
    4556import java.util.Vector;
     57import java.util.concurrent.ConcurrentHashMap;
    4658import java.util.jar.JarEntry;
    4759import java.util.jar.JarFile;
    4860import java.util.jar.Manifest;
    4961
     62import net.sourceforge.jnlp.AppletDesc;
     63import net.sourceforge.jnlp.ApplicationDesc;
    5064import net.sourceforge.jnlp.DownloadOptions;
    5165import net.sourceforge.jnlp.ExtensionDesc;
    5266import net.sourceforge.jnlp.JARDesc;
    5367import net.sourceforge.jnlp.JNLPFile;
     68import net.sourceforge.jnlp.JNLPMatcher;
     69import net.sourceforge.jnlp.JNLPMatcherException;
     70import net.sourceforge.jnlp.LaunchDesc;
    5471import net.sourceforge.jnlp.LaunchException;
    5572import net.sourceforge.jnlp.ParseException;
     
    5976import net.sourceforge.jnlp.Version;
    6077import net.sourceforge.jnlp.cache.CacheUtil;
     78import net.sourceforge.jnlp.cache.IllegalResourceDescriptorException;
    6179import net.sourceforge.jnlp.cache.ResourceTracker;
    6280import net.sourceforge.jnlp.cache.UpdatePolicy;
    6381import net.sourceforge.jnlp.security.SecurityDialogs;
    6482import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
    65 import net.sourceforge.jnlp.tools.JarSigner;
     83import net.sourceforge.jnlp.tools.JarCertVerifier;
    6684import net.sourceforge.jnlp.util.FileUtils;
    6785import sun.misc.JarIndex;
     
    82100    // resources in an extension.
    83101
     102    /** Signed JNLP File and Template */
     103    final public static String TEMPLATE = "JNLP-INF/APPLICATION_TEMPLATE.JNLP";
     104    final public static String APPLICATION = "JNLP-INF/APPLICATION.JNLP";
     105   
     106    /** True if the application has a signed JNLP File */
     107    private boolean isSignedJNLP = false;
     108   
    84109    /** map from JNLPFile url to shared classloader */
    85110    private static Map<String, JNLPClassLoader> urlToLoader =
     
    134159    private ArrayList<String> unverifiedJars = null;
    135160
    136     /** the jarsigner tool to verify our jars */
    137     private JarSigner js = null;
     161    /** the jar cert verifier tool to verify our jars */
     162    private JarCertVerifier jcv = null;
    138163
    139164    private boolean signing = false;
     
    151176    private HashMap<URL, SecurityDesc> jarLocationSecurityMap =
    152177            new HashMap<URL, SecurityDesc>();
     178
     179    /*Set to prevent once tried-to-get resources to be tried again*/
     180    private Set<URL> alreadyTried = Collections.synchronizedSet(new HashSet<URL>());
    153181   
    154182    /** Loader for codebase (which is a path, rather than a file) */
    155183    private CodeBaseClassLoader codeBaseLoader;
     184   
     185    /** True if the jar with the main class has been found
     186     * */
     187    private boolean foundMainJar= false;
     188
     189    /** Name of the application's main class */
     190    private String mainClass = null;
     191
     192    /**
     193     * Variable to track how many times this loader is in use
     194     */
     195    private int useCount = 0;
    156196
    157197    /**
     
    161201     */
    162202    protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy) throws LaunchException {
     203        this(file,policy,null);
     204    }
     205
     206    /**
     207     * Create a new JNLPClassLoader from the specified file.
     208     *
     209     * @param file the JNLP file
     210     * @param name of the application's main class
     211     */
     212    protected JNLPClassLoader(JNLPFile file, UpdatePolicy policy, String mainName) throws LaunchException {
    163213        super(new URL[0], JNLPClassLoader.class.getClassLoader());
    164214
     
    169219        this.updatePolicy = policy;
    170220        this.resources = file.getResources();
     221
     222        this.mainClass = mainName;
    171223
    172224        // initialize extensions
     
    276328     */
    277329    public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy) throws LaunchException {
     330        return getInstance(file, policy, null);
     331    }
     332
     333    /**
     334     * Returns a JNLP classloader for the specified JNLP file.
     335     *
     336     * @param file the file to load classes for
     337     * @param policy the update policy to use when downloading resources
     338     * @param mainName Overrides the main class name of the application
     339     */
     340    public static JNLPClassLoader getInstance(JNLPFile file, UpdatePolicy policy, String mainName) throws LaunchException {
    278341        JNLPClassLoader baseLoader = null;
    279342        JNLPClassLoader loader = null;
     
    292355                     !baseLoader.getJNLPFile().getFileLocation().equals(file.getFileLocation()))) {
    293356
    294                 loader = new JNLPClassLoader(file, policy);
     357                loader = new JNLPClassLoader(file, policy, mainName);
    295358
    296359                // New loader init may have caused extentions to create a
     
    304367
    305368                    loader.merge(extLoader);
     369                    extLoader.decrementLoaderUseCount(); // loader urls have been merged, ext loader is no longer used
    306370                }
    307371
     
    309373                // the baseLoader
    310374                if (baseLoader != null && baseLoader != loader) {
    311                     loader.merge(baseLoader);
     375                   loader.merge(baseLoader);
    312376                }
    313377
     
    316380                if (!file.isApplication()) {
    317381                    // If this is an applet, we do need to consider its loader
    318                     loader = new JNLPClassLoader(file, policy);
     382                   loader = new JNLPClassLoader(file, policy, mainName);
    319383
    320384                    if (baseLoader != null)
     
    330394        // loaders are mapped to a unique key. Only extensions and parent
    331395        // share a key, so it is safe to always share based on it
    332         urlToLoader.put(uniqueKey, loader);
     396       
     397        loader.incrementLoaderUseCount();
     398        synchronized(urlToLoader) {
     399            urlToLoader.put(uniqueKey, loader);
     400        }
    333401
    334402        return loader;
     
    342410     * @param version the file's version
    343411     * @param policy the update policy to use when downloading resources
    344      */
    345     public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version, UpdatePolicy policy)
     412     * @param mainName Overrides the main class name of the application
     413     */
     414    public static JNLPClassLoader getInstance(URL location, String uniqueKey, Version version, UpdatePolicy policy, String mainName)
    346415            throws IOException, ParseException, LaunchException {
    347416        JNLPClassLoader loader = urlToLoader.get(uniqueKey);
    348417
    349         if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation()))
    350             loader = getInstance(new JNLPFile(location, uniqueKey, version, false, policy), policy);
     418        if (loader == null || !location.equals(loader.getJNLPFile().getFileLocation())) {
     419            JNLPFile jnlpFile = new JNLPFile(location, uniqueKey, version, false, policy);
     420
     421            loader = getInstance(jnlpFile, policy, mainName);
     422        }
    351423
    352424        return loader;
     
    362434
    363435        loaderList.add(this);
     436
     437        if (mainClass == null) {
     438            Object obj = file.getLaunchInfo();
     439
     440            if (obj instanceof ApplicationDesc) {
     441                ApplicationDesc ad = (ApplicationDesc) file.getLaunchInfo();
     442                mainClass = ad.getMainClass();
     443            } else if (obj instanceof AppletDesc) {
     444                AppletDesc ad = (AppletDesc) file.getLaunchInfo();
     445                mainClass = ad.getMainClass();
     446            }
     447        }
    364448
    365449        //if (ext != null) {
     
    367451            try {
    368452                String uniqueKey = this.getJNLPFile().getUniqueKey();
    369                 JNLPClassLoader loader = getInstance(ext[i].getLocation(), uniqueKey, ext[i].getVersion(), updatePolicy);
     453                JNLPClassLoader loader = getInstance(ext[i].getLocation(), uniqueKey, ext[i].getVersion(), updatePolicy, mainClass);
    370454                loaderList.add(loader);
    371455            } catch (Exception ex) {
     
    401485
    402486    /**
     487     * Check if a described jar file is invalid
     488     * @param jar the jar to check
     489     * @return true if file exists AND is an invalid jar, false otherwise
     490     */
     491    private boolean isInvalidJar(JARDesc jar){
     492        File cacheFile = tracker.getCacheFile(jar.getLocation());
     493        if (cacheFile == null)
     494            return false;//File cannot be retrieved, do not claim it is an invalid jar
     495        boolean isInvalid = false;
     496        try {
     497            JarFile jarFile = new JarFile(cacheFile.getAbsolutePath());
     498            jarFile.close();
     499        } catch (IOException ioe){
     500            //Catch a ZipException or any other read failure
     501            isInvalid = true;
     502        }
     503        return isInvalid;
     504    }
     505
     506    /**
     507     * Determine how invalid jars should be handled
     508     * @return whether to filter invalid jars, or error later on
     509     */
     510    private boolean shouldFilterInvalidJars(){
     511        if (file instanceof PluginBridge){
     512            PluginBridge pluginBridge = (PluginBridge)file;
     513            /*Ignore on applet, ie !useJNLPHref*/
     514            return !pluginBridge.useJNLPHref();
     515        }
     516        return false;//Error is default behaviour
     517    }
     518
     519    /**
    403520     * Load all of the JARs used in this JNLP file into the
    404521     * ResourceTracker for downloading.
    405522     */
    406523    void initializeResources() throws LaunchException {
     524        if (file instanceof PluginBridge){
     525            PluginBridge bridge = (PluginBridge)file;
     526
     527            for (String codeBaseFolder : bridge.getCodeBaseFolders()){
     528                try {
     529                    addToCodeBaseLoader(new URL(file.getCodeBase(), codeBaseFolder));
     530                } catch (MalformedURLException mfe) {
     531                    System.err.println("Problem trying to add folder to code base:");
     532                    System.err.println(mfe.getMessage());
     533                }
     534            }
     535        }
     536
    407537        JARDesc jars[] = resources.getJARs();
    408         if (jars == null || jars.length == 0)
     538
     539        if (jars == null || jars.length == 0) {
     540
     541            boolean allSigned = true;
     542            for (int i = 1; i < loaders.length; i++) {
     543                if (!loaders[i].getSigning()) {
     544                    allSigned = false;
     545                    break;
     546                }
     547            }
     548
     549            if(allSigned)
     550                signing = true;
     551
     552            //Check if main jar is found within extensions
     553            foundMainJar = foundMainJar || hasMainInExtensions();
     554
    409555            return;
     556        }
    410557        /*
    411558        if (jars == null || jars.length == 0) {
     
    429576                               );
    430577        }
     578       
     579        //If there are no eager jars, initialize the first jar
     580        if(initialJars.size() == 0)
     581            initialJars.add(jars[0]);
    431582
    432583        if (strict)
    433584            fillInPartJars(initialJars); // add in each initial part's lazy jars
    434585
     586        waitForJars(initialJars); //download the jars first.
     587
     588        //A ZipException will propagate later on if the jar is invalid and not checked here
     589        if (shouldFilterInvalidJars()){
     590            //We filter any invalid jars
     591            Iterator<JARDesc> iterator = initialJars.iterator();
     592            while (iterator.hasNext()){
     593                JARDesc jar = iterator.next();
     594                if (isInvalidJar(jar)) {
     595                    //Remove this jar as an available jar
     596                    iterator.remove();
     597                    tracker.removeResource(jar.getLocation());
     598                    available.remove(jar);
     599                }
     600            }
     601        }
     602
    435603        if (JNLPRuntime.isVerifying()) {
    436604
    437             JarSigner js;
    438             waitForJars(initialJars); //download the jars first.
     605            JarCertVerifier jcv;
    439606
    440607            try {
    441                 js = verifyJars(initialJars);
     608                jcv = verifyJars(initialJars);
    442609            } catch (Exception e) {
    443                 //we caught an Exception from the JarSigner class.
     610                //we caught an Exception from the JarCertVerifier class.
    444611                //Note: one of these exceptions could be from not being able
    445612                //to read the cacerts or trusted.certs files.
     
    450617
    451618            //Case when at least one jar has some signing
    452             if (js.anyJarsSigned() && js.isFullySignedByASingleCert()) {
     619            if (jcv.anyJarsSigned() && jcv.isFullySignedByASingleCert()) {
    453620                signing = true;
    454621
    455                 if (!js.allJarsSigned() &&
     622                if (!jcv.allJarsSigned() &&
    456623                                    !SecurityDialogs.showNotAllSignedWarningDialog(file))
    457624                    throw new LaunchException(file, null, R("LSFatal"), R("LCClient"), R("LSignedAppJarUsingUnsignedJar"), R("LSignedAppJarUsingUnsignedJarInfo"));
    458625
     626
     627                // Check for main class in the downloaded jars, and check/verify signed JNLP fill
     628                checkForMain(initialJars);
     629
     630                // If jar with main class was not found, check available resources
     631                while (!foundMainJar && available != null && available.size() != 0)
     632                    addNextResource();
     633
     634                // If the jar with main class was not found, check extension
     635                // jnlp's resources
     636                foundMainJar = foundMainJar || hasMainInExtensions();
     637
     638                // If jar with main class was not found and there are no more
     639                // available jars, throw a LaunchException
     640                if (file.getLaunchInfo() != null) {
     641                    if (!foundMainJar
     642                            && (available == null || available.size() == 0))
     643                        throw new LaunchException(file, null, R("LSFatal"),
     644                                R("LCClient"), R("LCantDetermineMainClass"),
     645                                R("LCantDetermineMainClassInfo"));
     646                }
     647
     648                // If main jar was found, but a signed JNLP file was not located
     649                if (!isSignedJNLP && foundMainJar)
     650                    file.setSignedJNLPAsMissing();
     651               
    459652                //user does not trust this publisher
    460                 if (!js.getAlreadyTrustPublisher()) {
    461                     checkTrustWithUser(js);
     653                if (!jcv.getAlreadyTrustPublisher()) {
     654                    checkTrustWithUser(jcv);
    462655                } else {
    463656                    /**
     
    476669        for (JARDesc jarDesc : file.getResources().getJARs()) {
    477670            try {
    478                 File cachedFile = tracker.getCacheFile(jarDesc.getLocation());
     671
     672                File cachedFile;
     673
     674                try {
     675                    cachedFile = tracker.getCacheFile(jarDesc.getLocation());
     676                } catch (IllegalResourceDescriptorException irde){
     677                    //Caused by ignored resource being removed due to not being valid
     678                    System.err.println("JAR " + jarDesc.getLocation() + " is not a valid jar file. Continuing.");
     679                    continue;
     680                }
    479681
    480682                if (cachedFile == null) {
     
    515717            }
    516718        }
    517 
    518719        activateJars(initialJars);
    519720    }
    520 
    521     private void checkTrustWithUser(JarSigner js) throws LaunchException {
    522         if (!js.getRootInCacerts()) { //root cert is not in cacerts
     721   
     722    /***
     723     * Checks for the jar that contains the main class. If the main class was
     724     * found, it checks to see if the jar is signed and whether it contains a
     725     * signed JNLP file
     726     *
     727     * @param jars Jars that are checked to see if they contain the main class
     728     * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match
     729     */
     730    private void checkForMain(List<JARDesc> jars) throws LaunchException {
     731
     732        // Check launch info
     733        if (mainClass == null) {
     734            LaunchDesc launchDesc = file.getLaunchInfo();
     735            if (launchDesc == null) {
     736                return;
     737            }
     738
     739            mainClass = launchDesc.getMainClass();
     740        }
     741
     742        // The main class may be specified in the manifest
     743
     744        // Check main jar
     745        if (mainClass == null) {
     746            JARDesc mainJarDesc = file.getResources().getMainJAR();
     747            mainClass = getMainClassName(mainJarDesc.getLocation());
     748        }
     749
     750        // Check first jar
     751        if (mainClass == null) {
     752            JARDesc firstJarDesc = jars.get(0);
     753            mainClass = getMainClassName(firstJarDesc.getLocation());
     754        }
     755
     756        // Still not found? Iterate and set if only 1 was found
     757        if (mainClass == null) {
     758
     759            for (JARDesc jarDesc: jars) {
     760                String mainClassInThisJar = getMainClassName(jarDesc.getLocation());
     761
     762                if (mainClassInThisJar != null) {
     763
     764                    if (mainClass == null) { // first main class
     765                        mainClass = mainClassInThisJar;
     766                    } else { // There is more than one main class. Set to null and break.
     767                        mainClass = null;
     768                        break;
     769                    }
     770                }
     771            }
     772        }
     773
     774        String desiredJarEntryName = mainClass + ".class";
     775
     776        for (int i = 0; i < jars.size(); i++) {
     777
     778            try {
     779                File localFile = tracker
     780                        .getCacheFile(jars.get(i).getLocation());
     781
     782                if (localFile == null) {
     783                    System.err.println("JAR " + jars.get(i).getLocation() + " not found. Continuing.");
     784                    continue; // JAR not found. Keep going.
     785                }
     786
     787                JarFile jarFile = new JarFile(localFile);
     788                Enumeration<JarEntry> entries = jarFile.entries();
     789                JarEntry je;
     790
     791                while (entries.hasMoreElements()) {
     792                    je = entries.nextElement();
     793                    String jeName = je.getName().replaceAll("/", ".");
     794                    if (jeName.equals(desiredJarEntryName)) {
     795                        foundMainJar = true;
     796                        verifySignedJNLP(jars.get(i), jarFile);
     797                        break;
     798                    }
     799                }
     800            } catch (IOException e) {
     801                /*
     802                 * After this exception is caught, it is escaped. This will skip
     803                 * the jarFile that may have thrown this exception and move on
     804                 * to the next jarFile (if there are any)
     805                 */
     806            }
     807        }
     808    }
     809
     810    /**
     811     * Gets the name of the main method if specified in the manifest
     812     *
     813     * @param location The JAR location
     814     * @return the main class name, null if there isn't one of if there was an error
     815     */
     816    private String getMainClassName(URL location) {
     817
     818        String mainClass = null;
     819        File f = tracker.getCacheFile(location);
     820
     821        if( f != null) {
     822            try {
     823                JarFile mainJar = new JarFile(f);
     824                mainClass = mainJar.getManifest().
     825                        getMainAttributes().getValue("Main-Class");
     826            } catch (IOException ioe) {
     827                mainClass = null;
     828            }
     829        }
     830
     831        return mainClass;
     832    }
     833
     834    /**
     835     * Returns true if this loader has the main jar
     836     */
     837    public boolean hasMainJar() {
     838        return this.foundMainJar;
     839    }
     840
     841    /**
     842     * Returns true if extension loaders have the main jar
     843     */
     844    private boolean hasMainInExtensions() {
     845        boolean foundMain = false;
     846
     847        for (int i = 1; i < loaders.length && !foundMain; i++) {
     848            foundMain = loaders[i].hasMainJar();
     849        }
     850
     851        return foundMain;
     852    }
     853
     854    /**
     855     * Is called by checkForMain() to check if the jar file is signed and if it
     856     * contains a signed JNLP file.
     857     *
     858     * @param jarDesc JARDesc of jar
     859     * @param jarFile the jar file
     860     * @throws LaunchException thrown if the signed JNLP file, within the main jar, fails to be verified or does not match
     861     */
     862    private void verifySignedJNLP(JARDesc jarDesc, JarFile jarFile)
     863            throws LaunchException {
     864
     865        JarCertVerifier signer = new JarCertVerifier();
     866        List<JARDesc> desc = new ArrayList<JARDesc>();
     867        desc.add(jarDesc);
     868
     869        // Initialize streams
     870        InputStream inStream = null;
     871        InputStreamReader inputReader = null;
     872        FileReader fr = null;
     873        InputStreamReader jnlpReader = null;
     874
     875        try {
     876            signer.verifyJars(desc, tracker);
     877
     878            if (signer.allJarsSigned()) { // If the jar is signed
     879
     880                Enumeration<JarEntry> entries = jarFile.entries();
     881                JarEntry je;
     882
     883                while (entries.hasMoreElements()) {
     884                    je = entries.nextElement();
     885                    String jeName = je.getName().toUpperCase();
     886
     887                    if (jeName.equals(TEMPLATE) || jeName.equals(APPLICATION)) {
     888
     889                        if (JNLPRuntime.isDebug())
     890                            System.err.println("Creating Jar InputStream from JarEntry");
     891
     892                        inStream = jarFile.getInputStream(je);
     893                        inputReader = new InputStreamReader(inStream);
     894
     895                        if (JNLPRuntime.isDebug())
     896                            System.err.println("Creating File InputStream from lauching JNLP file");
     897
     898                        JNLPFile jnlp = this.getJNLPFile();
     899                        URL url = jnlp.getFileLocation();
     900                        File jn = null;
     901
     902                        // If the file is on the local file system, use original path, otherwise find cached file
     903                        if (url.getProtocol().toLowerCase().equals("file"))
     904                            jn = new File(url.getPath());
     905                        else
     906                            jn = CacheUtil.getCacheFile(url, null);
     907
     908                        fr = new FileReader(jn);
     909                        jnlpReader = fr;
     910
     911                        // Initialize JNLPMatcher class
     912                        JNLPMatcher matcher;
     913
     914                        if (jeName.equals(APPLICATION)) { // If signed application was found
     915                            if (JNLPRuntime.isDebug())
     916                                System.err.println("APPLICATION.JNLP has been located within signed JAR. Starting verfication...");
     917                           
     918                            matcher = new JNLPMatcher(inputReader, jnlpReader, false);
     919                        } else { // Otherwise template was found
     920                            if (JNLPRuntime.isDebug())
     921                                System.err.println("APPLICATION_TEMPLATE.JNLP has been located within signed JAR. Starting verfication...");
     922                           
     923                            matcher = new JNLPMatcher(inputReader, jnlpReader,
     924                                    true);
     925                        }
     926
     927                        // If signed JNLP file does not matches launching JNLP file, throw JNLPMatcherException
     928                        if (!matcher.isMatch())
     929                            throw new JNLPMatcherException("Signed Application did not match launching JNLP File");
     930
     931                        this.isSignedJNLP = true;
     932                        if (JNLPRuntime.isDebug())
     933                            System.err.println("Signed Application Verification Successful");
     934
     935                        break;
     936                    }
     937                }
     938            }
     939        } catch (JNLPMatcherException e) {
     940
     941            /*
     942             * Throws LaunchException if signed JNLP file fails to be verified
     943             * or fails to match the launching JNLP file
     944             */
     945
     946            throw new LaunchException(file, null, R("LSFatal"), R("LCClient"),
     947                    R("LSignedJNLPFileDidNotMatch"), R(e.getMessage()));
     948
     949            /*
     950             * Throwing this exception will fail to initialize the application
     951             * resulting in the termination of the application
     952             */
     953
     954        } catch (Exception e) {
     955           
     956            if (JNLPRuntime.isDebug())
     957                e.printStackTrace(System.err);
     958
     959            /*
     960             * After this exception is caught, it is escaped. If an exception is
     961             * thrown while handling the jar file, (mainly for
     962             * JarCertVerifier.verifyJars) it assumes the jar file is unsigned and
     963             * skip the check for a signed JNLP file
     964             */
     965           
     966        } finally {
     967
     968            //Close all streams
     969            closeStream(inStream);
     970            closeStream(inputReader);
     971            closeStream(fr);
     972            closeStream(jnlpReader);
     973        }
     974
     975        if (JNLPRuntime.isDebug())
     976            System.err.println("Ending check for signed JNLP file...");
     977    }
     978
     979    /***
     980     * Closes a stream
     981     *
     982     * @param stream the stream that will be closed
     983     */
     984    private void closeStream (Closeable stream) {
     985        if (stream != null)
     986            try {
     987                stream.close();
     988            } catch (Exception e) {
     989                e.printStackTrace(System.err);
     990            }
     991    }
     992   
     993    private void checkTrustWithUser(JarCertVerifier jcv) throws LaunchException {
     994        if (JNLPRuntime.isTrustAll()){
     995            return;
     996        }
     997        if (!jcv.getRootInCacerts()) { //root cert is not in cacerts
    523998            boolean b = SecurityDialogs.showCertWarningDialog(
    524                     AccessType.UNVERIFIED, file, js);
     999                    AccessType.UNVERIFIED, file, jcv);
    5251000            if (!b)
    5261001                throw new LaunchException(null, null, R("LSFatal"),
    5271002                        R("LCLaunching"), R("LNotVerified"), "");
    528         } else if (js.getRootInCacerts()) { //root cert is in cacerts
     1003        } else if (jcv.getRootInCacerts()) { //root cert is in cacerts
    5291004            boolean b = false;
    530             if (js.noSigningIssues())
     1005            if (jcv.noSigningIssues())
    5311006                b = SecurityDialogs.showCertWarningDialog(
    532                         AccessType.VERIFIED, file, js);
    533             else if (!js.noSigningIssues())
     1007                        AccessType.VERIFIED, file, jcv);
     1008            else if (!jcv.noSigningIssues())
    5341009                b = SecurityDialogs.showCertWarningDialog(
    535                         AccessType.SIGNING_ERROR, file, js);
     1010                        AccessType.SIGNING_ERROR, file, jcv);
    5361011            if (!b)
    5371012                throw new LaunchException(null, null, R("LSFatal"),
     
    5831058     */
    5841059    protected PermissionCollection getPermissions(CodeSource cs) {
    585         Permissions result = new Permissions();
    586 
    587         // should check for extensions or boot, automatically give all
    588         // access w/o security dialog once we actually check certificates.
    589 
    590         // copy security permissions from SecurityDesc element
    591         if (security != null) {
    592             // Security desc. is used only to track security settings for the
    593             // application. However, an application may comprise of multiple
    594             // jars, and as such, security must be evaluated on a per jar basis.
    595 
    596             // set default perms
    597             PermissionCollection permissions = security.getSandBoxPermissions();
    598 
    599             // If more than default is needed:
    600             // 1. Code must be signed
    601             // 2. ALL or J2EE permissions must be requested (note: plugin requests ALL automatically)
    602             if (cs.getCodeSigners() != null &&
    603                     (getCodeSourceSecurity(cs.getLocation()).getSecurityType().equals(SecurityDesc.ALL_PERMISSIONS) ||
    604                      getCodeSourceSecurity(cs.getLocation()).getSecurityType().equals(SecurityDesc.J2EE_PERMISSIONS))) {
    605 
    606                 permissions = getCodeSourceSecurity(cs.getLocation()).getPermissions(cs);
    607             }
    608 
    609             Enumeration<Permission> e = permissions.elements();
    610             while (e.hasMoreElements())
    611                 result.add(e.nextElement());
    612         }
    613 
    614         // add in permission to read the cached JAR files
    615         for (int i = 0; i < resourcePermissions.size(); i++)
    616             result.add(resourcePermissions.get(i));
    617 
    618         // add in the permissions that the user granted.
    619         for (int i = 0; i < runtimePermissions.size(); i++)
    620             result.add(runtimePermissions.get(i));
    621 
    622         return result;
     1060        try {
     1061            Permissions result = new Permissions();
     1062
     1063            // should check for extensions or boot, automatically give all
     1064            // access w/o security dialog once we actually check certificates.
     1065
     1066            // copy security permissions from SecurityDesc element
     1067            if (security != null) {
     1068                // Security desc. is used only to track security settings for the
     1069                // application. However, an application may comprise of multiple
     1070                // jars, and as such, security must be evaluated on a per jar basis.
     1071
     1072                // set default perms
     1073                PermissionCollection permissions = security.getSandBoxPermissions();
     1074
     1075                // If more than default is needed:
     1076                // 1. Code must be signed
     1077                // 2. ALL or J2EE permissions must be requested (note: plugin requests ALL automatically)
     1078                if (cs == null) {
     1079                    throw new NullPointerException("Code source was null");
     1080                }
     1081                if (cs.getCodeSigners() != null) {
     1082                    if (cs.getLocation() == null) {
     1083                        throw new NullPointerException("Code source location was null");
     1084                    }
     1085                    if (getCodeSourceSecurity(cs.getLocation()) == null) {
     1086                        throw new NullPointerException("Code source security was null");
     1087                    }
     1088                    if (getCodeSourceSecurity(cs.getLocation()).getSecurityType() == null) {
     1089                        if (JNLPRuntime.isDebug()){
     1090                        new NullPointerException("Warning! Code source security type was null").printStackTrace();
     1091                        }
     1092                    }
     1093                    Object securityType = getCodeSourceSecurity(cs.getLocation()).getSecurityType();
     1094                    if (SecurityDesc.ALL_PERMISSIONS.equals(securityType)
     1095                            || SecurityDesc.J2EE_PERMISSIONS.equals(securityType)) {
     1096
     1097                        permissions = getCodeSourceSecurity(cs.getLocation()).getPermissions(cs);
     1098                    }
     1099                }
     1100
     1101                Enumeration<Permission> e = permissions.elements();
     1102                while (e.hasMoreElements()) {
     1103                    result.add(e.nextElement());
     1104                }
     1105            }
     1106
     1107            // add in permission to read the cached JAR files
     1108            for (int i = 0; i < resourcePermissions.size(); i++) {
     1109                result.add(resourcePermissions.get(i));
     1110            }
     1111
     1112            // add in the permissions that the user granted.
     1113            for (int i = 0; i < runtimePermissions.size(); i++) {
     1114                result.add(runtimePermissions.get(i));
     1115            }
     1116
     1117            // Class from host X should be allowed to connect to host X
     1118            if (cs.getLocation().getHost().length() > 0)
     1119                result.add(new SocketPermission(cs.getLocation().getHost(),
     1120                        "connect, accept"));
     1121
     1122            return result;
     1123        } catch (RuntimeException ex) {
     1124            if (JNLPRuntime.isDebug()) {
     1125                ex.printStackTrace();
     1126            }
     1127            throw ex;
     1128        }
    6231129    }
    6241130
     
    7191225                                    }
    7201226
    721                                     JarSigner signer = new JarSigner();
     1227                                    JarCertVerifier signer = new JarCertVerifier();
    7221228                                    List<JARDesc> jars = new ArrayList<JARDesc>();
    7231229                                    JARDesc jarDesc = new JARDesc(new File(extractedJarLocation).toURL(), null, null, false, false, false, false);
     
    7801286                            JarFile jarFile = new JarFile(localFile.getAbsolutePath());
    7811287                            Manifest mf = jarFile.getManifest();
    782                             classpaths.addAll(getClassPathsFromManifest(mf, jar.getLocation().getPath()));
     1288
     1289                            // Only check classpath if this is the plugin and there is no jnlp_href usage.
     1290                            // Note that this is different from proprietary plugin behaviour.
     1291                            // If jnlp_href is used, the app should be treated similarly to when
     1292                            // it is run from javaws as a webstart.
     1293                            if (file instanceof PluginBridge && !((PluginBridge) file).useJNLPHref()) {
     1294                                classpaths.addAll(getClassPathsFromManifest(mf, jar.getLocation().getPath()));
     1295                            }
     1296
    7831297                            JarIndex index = JarIndex.getJarIndex(jarFile, null);
    7841298                            if (index != null)
     
    9641478         * @param jars the jars to be verified.
    9651479         */
    966     private JarSigner verifyJars(List<JARDesc> jars) throws Exception {
    967 
    968         js = new JarSigner();
    969         js.verifyJars(jars, tracker);
    970         return js;
     1480    private JarCertVerifier verifyJars(List<JARDesc> jars) throws Exception {
     1481
     1482        jcv = new JarCertVerifier();
     1483        jcv.verifyJars(jars, tracker);
     1484        return jcv;
    9711485    }
    9721486
     
    9781492            Class result = null;
    9791493
    980             if (loaders[i] == this)
    981                 result = super.findLoadedClass(name);
    982             else
     1494            if (loaders[i] == this) {
     1495                final String fName = name;
     1496                try {
     1497                    result = AccessController.doPrivileged(
     1498                            new PrivilegedExceptionAction<Class<?>>() {
     1499                                public Class<?> run() {
     1500                                    return JNLPClassLoader.super.findLoadedClass(fName);
     1501                                }
     1502                            }, getAccessControlContextForClassLoading());
     1503                } catch (PrivilegedActionException pae) {
     1504                    result = null;
     1505                }
     1506            } else {
    9831507                result = loaders[i].findLoadedClassAll(name);
     1508            }
    9841509
    9851510            if (result != null)
     
    10951620     * @param desc the JARDesc for the new jar
    10961621     */
    1097     private void addNewJar(JARDesc desc) {
     1622    private void addNewJar(final JARDesc desc) {
    10981623
    10991624        available.add(desc);
     
    11051630                );
    11061631
    1107         URL remoteURL = desc.getLocation();
    1108         URL cachedUrl = tracker.getCacheURL(remoteURL);
    1109         addURL(remoteURL);
    1110         CachedJarFileCallback.getInstance().addMapping(remoteURL, cachedUrl);
     1632        // Give read permissions to the cached jar file
     1633        AccessController.doPrivileged(new PrivilegedAction<Void>() {
     1634            public Void run() {
     1635                Permission p = CacheUtil.getReadPermission(desc.getLocation(),
     1636                        desc.getVersion());
     1637
     1638                resourcePermissions.add(p);
     1639
     1640                return null;
     1641            }
     1642        });
     1643
     1644        final URL remoteURL = desc.getLocation();
     1645        final URL cachedUrl = tracker.getCacheURL(remoteURL); // blocks till download
     1646
     1647        available.remove(desc); // Resource downloaded. Remove from available list.
     1648       
     1649        try {
     1650
     1651            // Verify if needed
     1652
     1653            final JarCertVerifier signer = new JarCertVerifier();
     1654            final List<JARDesc> jars = new ArrayList<JARDesc>();
     1655            jars.add(desc);
     1656
     1657            // Decide what level of security this jar should have
     1658            // The verification and security setting functions rely on
     1659            // having AllPermissions as those actions normally happen
     1660            // during initialization. We therefore need to do those
     1661            // actions as privileged.
     1662
     1663            AccessController.doPrivileged(new PrivilegedExceptionAction<Void>() {
     1664                public Void run() throws Exception {
     1665                    signer.verifyJars(jars, tracker);
     1666
     1667                    if (signer.anyJarsSigned() && !signer.getAlreadyTrustPublisher()) {
     1668                        checkTrustWithUser(signer);
     1669                    }
     1670
     1671                    final SecurityDesc security;
     1672                    if (signer.anyJarsSigned()) {
     1673                        security = new SecurityDesc(file,
     1674                                SecurityDesc.ALL_PERMISSIONS,
     1675                                file.getCodeBase().getHost());
     1676                    } else {
     1677                        security = new SecurityDesc(file,
     1678                                SecurityDesc.SANDBOX_PERMISSIONS,
     1679                                file.getCodeBase().getHost());
     1680                    }
     1681
     1682                    jarLocationSecurityMap.put(remoteURL, security);
     1683
     1684                    return null;
     1685                }
     1686            });
     1687
     1688            addURL(remoteURL);
     1689            CachedJarFileCallback.getInstance().addMapping(remoteURL, cachedUrl);
     1690
     1691        } catch (Exception e) {
     1692            // Do nothing. This code is called by loadClass which cannot
     1693            // throw additional exceptions. So instead, just ignore it.
     1694            // Exception => jar will not get added to classpath, which will
     1695            // result in CNFE from loadClass.
     1696            e.printStackTrace();
     1697        }
    11111698    }
    11121699
     
    11171704        for (int i = 0; i < loaders.length; i++) {
    11181705            try {
    1119                 if (loaders[i] == this)
    1120                     return super.findClass(name);
    1121                 else
     1706                if (loaders[i] == this) {
     1707                    final String fName = name;
     1708                    return AccessController.doPrivileged(
     1709                            new PrivilegedExceptionAction<Class<?>>() {
     1710                                public Class<?> run() throws ClassNotFoundException {
     1711                                    return JNLPClassLoader.super.findClass(fName);
     1712                                }
     1713                            }, getAccessControlContextForClassLoading());
     1714                } else {
    11221715                    return loaders[i].findClass(name);
     1716                }
    11231717            } catch (ClassNotFoundException ex) {
    11241718            } catch (ClassFormatError cfe) {
     1719            } catch (PrivilegedActionException pae) {
    11251720            }
    11261721        }
     
    11281723        // Try codebase loader
    11291724        if (codeBaseLoader != null)
    1130             return codeBaseLoader.findClass(name);
    1131        
     1725            return codeBaseLoader.findClass(name, true);
     1726
    11321727        // All else failed. Throw CNFE
    11331728        throw new ClassNotFoundException(name);
     
    11511746        // add resources until found
    11521747        while (true) {
    1153             JNLPClassLoader addedTo = addNextResource();
     1748            JNLPClassLoader addedTo = null;
     1749           
     1750            try {
     1751                addedTo = addNextResource();
     1752            } catch (LaunchException e) {
     1753
     1754                /*
     1755                 * This method will never handle any search for the main class
     1756                 * [It is handled in initializeResources()]. Therefore, this
     1757                 * exception will never be thrown here and is escaped
     1758                 */
     1759
     1760                throw new IllegalStateException(e);
     1761            }
    11541762
    11551763            if (addedTo == null)
     
    11661774     * Finds the resource in this, the parent, or the extension
    11671775     * class loaders.
    1168      */
    1169     public URL getResource(String name) {
    1170         URL result = super.getResource(name);
    1171 
    1172         for (int i = 1; i < loaders.length; i++)
    1173             if (result == null)
    1174                 result = loaders[i].getResource(name);
     1776     *
     1777     * @return a <code>URL</code> for the resource, or <code>null</code>
     1778     * if the resource could not be found.
     1779     */
     1780    @Override
     1781    public URL findResource(String name) {
     1782        URL result = null;
     1783
     1784        try {
     1785            Enumeration<URL> e = findResources(name);
     1786            if (e.hasMoreElements()) {
     1787                result = e.nextElement();
     1788            }
     1789        } catch (IOException e) {
     1790            if (JNLPRuntime.isDebug()) {
     1791                e.printStackTrace();
     1792            }
     1793        }
    11751794       
    11761795        // If result is still null, look in the codebase loader
    11771796        if (result == null && codeBaseLoader != null)
    1178             result = codeBaseLoader.getResource(name);
     1797            result = codeBaseLoader.findResource(name);
    11791798
    11801799        return result;
     
    11821801
    11831802    /**
    1184      * Finds the resource in this, the parent, or the extension
    1185      * class loaders.
     1803     * Find the resources in this, the parent, or the extension
     1804     * class loaders. Load lazy resources if not found in current resources.
    11861805     */
    11871806    @Override
    11881807    public Enumeration<URL> findResources(String name) throws IOException {
    1189         Vector<URL> resources = new Vector<URL>();
    1190         Enumeration<URL> e;
     1808        Enumeration<URL> resources = findResourcesBySearching(name);
     1809
     1810        try {
     1811            // if not found, load all lazy resources; repeat search
     1812            while (!resources.hasMoreElements() && addNextResource() != null) {
     1813                resources = findResourcesBySearching(name);
     1814            }
     1815        } catch (LaunchException le) {
     1816            le.printStackTrace();
     1817        }
     1818
     1819        return resources;
     1820    }
     1821
     1822    /**
     1823     * Find the resources in this, the parent, or the extension
     1824     * class loaders.
     1825     */
     1826    private Enumeration<URL> findResourcesBySearching(String name) throws IOException {
     1827        List<URL> resources = new ArrayList<URL>();
     1828        Enumeration<URL> e = null;
    11911829
    11921830        for (int i = 0; i < loaders.length; i++) {
    1193 
    1194             if (loaders[i] == this)
    1195                 e = super.findResources(name);
    1196             else
     1831            // TODO check if this will blow up or not
     1832            // if loaders[1].getResource() is called, wont it call getResource() on
     1833            // the original caller? infinite recursion?
     1834
     1835            if (loaders[i] == this) {
     1836                final String fName = name;
     1837                try {
     1838                    e = AccessController.doPrivileged(
     1839                            new PrivilegedExceptionAction<Enumeration<URL>>() {
     1840                                public Enumeration<URL> run() throws IOException {
     1841                                    return JNLPClassLoader.super.findResources(fName);
     1842                                }
     1843                            }, getAccessControlContextForClassLoading());
     1844                } catch (PrivilegedActionException pae) {
     1845                }
     1846            } else {
    11971847                e = loaders[i].findResources(name);
    1198 
    1199             while (e.hasMoreElements())
    1200                 resources.add(e.nextElement());
     1848            }
     1849
     1850            final Enumeration<URL> fURLEnum = e;
     1851            try {
     1852                resources.addAll(AccessController.doPrivileged(
     1853                    new PrivilegedExceptionAction<Collection<URL>>() {
     1854                        public Collection<URL> run() {
     1855                            List<URL> resources = new ArrayList<URL>();
     1856                            while (fURLEnum != null && fURLEnum.hasMoreElements()) {
     1857                                resources.add(fURLEnum.nextElement());
     1858                            }
     1859                            return resources;
     1860                        }
     1861                    }, getAccessControlContextForClassLoading()));
     1862            } catch (PrivilegedActionException pae) {
     1863            }
    12011864        }
    12021865
     
    12091872        }
    12101873
    1211         return resources.elements();
     1874        return Collections.enumeration(resources);
    12121875    }
    12131876
     
    12421905     *
    12431906     * @return the classloader that resources were added to, or null
    1244      */
    1245     protected JNLPClassLoader addNextResource() {
     1907     * @throws LaunchException Thrown if the signed JNLP file, within the main jar, fails to be verified or does not match
     1908     */
     1909    protected JNLPClassLoader addNextResource() throws LaunchException {
    12461910        if (available.size() == 0) {
    12471911            for (int i = 1; i < loaders.length; i++) {
     
    12591923
    12601924        fillInPartJars(jars);
     1925        checkForMain(jars);
    12611926        activateJars(jars);
    12621927
     
    13061971
    13071972    protected SecurityDesc getCodeSourceSecurity(URL source) {
    1308         return jarLocationSecurityMap.get(source);
     1973        SecurityDesc sec=jarLocationSecurityMap.get(source);
     1974        if (sec == null && !alreadyTried.contains(source)) {
     1975            alreadyTried.add(source);
     1976            //try to load the jar which is requesting the permissions, but was NOT downloaded by standard way
     1977            if (JNLPRuntime.isDebug()) {
     1978                System.out.println("Application is trying to get permissions for " + source.toString() + ", which was not added by standard way. Trying to download and verify!");
     1979            }
     1980            try {
     1981                JARDesc des = new JARDesc(source, null, null, false, false, false, false);
     1982                addNewJar(des);
     1983                sec = jarLocationSecurityMap.get(source);
     1984            } catch (Throwable t) {
     1985                if (JNLPRuntime.isDebug()) {
     1986                    t.printStackTrace();
     1987                }
     1988                sec = null;
     1989            }
     1990        }
     1991        if (sec == null){
     1992            System.out.println(Translator.R("LNoSecInstance",source.toString()));
     1993        }
     1994        return sec;
    13091995    }
    13101996
     
    13472033     */
    13482034    private void addToCodeBaseLoader(URL u) {
     2035        if (u == null) {
     2036            return;
     2037        }
    13492038
    13502039        // Only paths may be added
     
    14032092        return result;
    14042093    }
     2094   
     2095    /**
     2096     * Increments loader use count by 1
     2097     *
     2098     * @throws SecurityException if caller is not trusted
     2099     */
     2100    private synchronized void incrementLoaderUseCount() {
     2101       
     2102        // For use by trusted code only
     2103        if (System.getSecurityManager() != null)
     2104            System.getSecurityManager().checkPermission(new AllPermission());
     2105       
     2106        useCount++;
     2107    }
     2108
     2109    /**
     2110     * Decrements loader use count by 1
     2111     *
     2112     * If count reaches 0, loader is removed from list of available loaders
     2113     *
     2114     * @throws SecurityException if caller is not trusted
     2115     */
     2116    public synchronized void decrementLoaderUseCount() {
     2117
     2118        // For use by trusted code only
     2119        if (System.getSecurityManager() != null)
     2120            System.getSecurityManager().checkPermission(new AllPermission());
     2121
     2122        useCount--;
     2123
     2124        if (useCount <= 0) {
     2125            synchronized(urlToLoader) {
     2126                urlToLoader.remove(file.getUniqueKey());
     2127            }
     2128        }
     2129    }
     2130
     2131    /**
     2132     * Returns an appropriate AccessControlContext for loading classes in
     2133     * the running instance.
     2134     *
     2135     * The default context during class-loading only allows connection to
     2136     * codebase. However applets are allowed to load jars from arbitrary
     2137     * locations and the codebase only access falls short if a class from
     2138     * one location needs a class from another.
     2139     *
     2140     * Given protected access since CodeBaseClassloader uses this function too.
     2141     *
     2142     * @return The appropriate AccessControlContext for loading classes for this instance
     2143     */
     2144    public AccessControlContext getAccessControlContextForClassLoading() {
     2145        AccessControlContext context = AccessController.getContext();
     2146
     2147        try {
     2148            context.checkPermission(new AllPermission());
     2149            return context; // If context already has all permissions, don't bother
     2150        } catch (AccessControlException ace) {
     2151            // continue below
     2152        } catch (ClassCircularityError cce) {
     2153            // continue below
     2154        }
     2155
     2156        // Since this is for class-loading, technically any class from one jar
     2157        // should be able to access a class from another, therefore making the
     2158        // original context code source irrelevant
     2159        PermissionCollection permissions = this.security.getSandBoxPermissions();
     2160
     2161        // Local cache access permissions
     2162        for (Permission resourcePermission : resourcePermissions) {
     2163            permissions.add(resourcePermission);
     2164        }
     2165
     2166        // Permissions for all remote hosting urls
     2167        for (URL u: jarLocationSecurityMap.keySet()) {
     2168            permissions.add(new SocketPermission(u.getHost(),
     2169                                                 "connect, accept"));
     2170        }
     2171
     2172        // Permissions for codebase urls (if there is a loader)
     2173        if (codeBaseLoader != null) {
     2174            for (URL u : codeBaseLoader.getURLs()) {
     2175                permissions.add(new SocketPermission(u.getHost(),
     2176                        "connect, accept"));
     2177            }
     2178        }
     2179
     2180        ProtectionDomain pd = new ProtectionDomain(null, permissions);
     2181
     2182        return new AccessControlContext(new ProtectionDomain[] { pd });
     2183    }
    14052184
    14062185    /*
     
    14122191        JNLPClassLoader parentJNLPClassLoader;
    14132192       
     2193        /**
     2194         * Classes that are not found, so that findClass can skip them next time
     2195         */
     2196        ConcurrentHashMap<String, URL[]> notFoundResources = new ConcurrentHashMap<String, URL[]>();
     2197
    14142198        public CodeBaseClassLoader(URL[] urls, JNLPClassLoader cl) {
    14152199            super(urls);
     
    14232207
    14242208        @Override
    1425         public Class<?> findClass(String name) throws ClassNotFoundException {
    1426             return super.findClass(name);
     2209        public Class<?> findClass(String name) throws ClassNotFoundException {
     2210            return findClass(name, false);
     2211        }
     2212
     2213        public Class<?> findClass(String name, boolean recursivelyInvoked) throws ClassNotFoundException {
     2214
     2215            if (!recursivelyInvoked) {
     2216                try {
     2217                    return parentJNLPClassLoader.findClass(name);
     2218                } catch (ClassNotFoundException cnfe) {
     2219                    // continue
     2220                }
     2221            }
     2222
     2223            // If we have searched this path before, don't try again
     2224            if (Arrays.equals(super.getURLs(), notFoundResources.get(name)))
     2225                throw new ClassNotFoundException(name);
     2226
     2227            try {
     2228                final String fName = name;
     2229                return AccessController.doPrivileged(
     2230                        new PrivilegedExceptionAction<Class<?>>() {
     2231                            public Class<?> run() throws ClassNotFoundException {
     2232                                return CodeBaseClassLoader.super.findClass(fName);
     2233                            }
     2234                        }, parentJNLPClassLoader.getAccessControlContextForClassLoading());
     2235            } catch (PrivilegedActionException pae) {
     2236                notFoundResources.put(name, super.getURLs());
     2237                throw new ClassNotFoundException("Could not find class " + name);
     2238            }
    14272239        }
    14282240
     
    14512263        @Override
    14522264        public Enumeration<URL> findResources(String name) throws IOException {
     2265
     2266            // If we have searched this path before, don't try again
     2267            if (Arrays.equals(super.getURLs(), notFoundResources.get(name)))
     2268                return (new Vector<URL>(0)).elements();
     2269
    14532270            if (!name.startsWith("META-INF")) {
    1454                 return super.findResources(name);
    1455             }
     2271                Enumeration<URL> urls = super.findResources(name);
     2272
     2273                if (!urls.hasMoreElements()) {
     2274                    notFoundResources.put(name, super.getURLs());
     2275                }
     2276
     2277                return urls;
     2278            }
     2279
    14562280            return (new Vector<URL>(0)).elements();
    14572281        }
     
    14592283        @Override
    14602284        public URL findResource(String name) {
     2285
     2286            // If we have searched this path before, don't try again
     2287            if (Arrays.equals(super.getURLs(), notFoundResources.get(name)))
     2288                return null;
     2289
     2290            URL url = null;
    14612291            if (!name.startsWith("META-INF")) {
    1462                 return super.findResource(name);
    1463             }
     2292                try {
     2293                    final String fName = name;
     2294                    url = AccessController.doPrivileged(
     2295                            new PrivilegedExceptionAction<URL>() {
     2296                                public URL run() {
     2297                                    return CodeBaseClassLoader.super.findResource(fName);
     2298                                }
     2299                            }, parentJNLPClassLoader.getAccessControlContextForClassLoading());
     2300                } catch (PrivilegedActionException pae) {
     2301                }
     2302
     2303                if (url == null) {
     2304                    notFoundResources.put(name, super.getURLs());
     2305                }
     2306
     2307                return url;
     2308            }
     2309
    14642310            return null;
    14652311        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPRuntime.java

    r348 r418  
    3030import javax.naming.ConfigurationException;
    3131import javax.net.ssl.HttpsURLConnection;
     32import javax.net.ssl.KeyManagerFactory;
    3233import javax.net.ssl.SSLContext;
    3334import javax.net.ssl.SSLSocketFactory;
     
    9495    private static UpdatePolicy updatePolicy = UpdatePolicy.ALWAYS;
    9596
    96     /** netx window icon */
    97     private static Image windowIcon = null;
    98 
    9997    /** whether initialized */
    10098    private static boolean initialized = false;
     
    124122    private static boolean forksAllowed = true;
    125123
     124    /** all security dialogs will be consumed and pretented as beeing verified by user and allowed.*/
     125    private static boolean trustAll=false;
     126
    126127    /** contains the arguments passed to the jnlp runtime */
    127128    private static List<String> initialArguments;
     
    132133    public static final String STDERR_FILE = "java.stderr";
    133134    public static final String STDOUT_FILE = "java.stdout";
     135
    134136
    135137    /**
     
    184186            checkHeadless();
    185187
    186         if (!headless && windowIcon == null)
    187             loadWindowIcon();
    188 
    189188        if (!headless && indicator == null)
    190189            indicator = new DefaultDownloadIndicator();
     
    192191        if (handler == null) {
    193192            if (headless) {
    194                 handler = new DefaultLaunchHandler();
     193                handler = new DefaultLaunchHandler(System.err);
    195194            } else {
    196                 handler = new GuiLaunchHandler();
     195                handler = new GuiLaunchHandler(System.err);
    197196            }
    198197        }
     
    222221            SSLSocketFactory sslSocketFactory;
    223222            SSLContext context = SSLContext.getInstance("SSL");
     223            KeyStore ks = KeyStores.getKeyStore(KeyStores.Level.USER, KeyStores.Type.CLIENT_CERTS);
     224            KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
     225            kmf.init(ks, KeyStores.getPassword());
    224226            TrustManager[] trust = new TrustManager[] { VariableX509TrustManager.getInstance() };
    225             context.init(null, trust, null);
     227            context.init(kmf.getKeyManagers(), trust, null);
    226228            sslSocketFactory = context.getSocketFactory();
    227229
     
    326328    public static boolean isWebstartApplication() {
    327329        return isWebstartApplication;
    328     }
    329 
    330     /**
    331      * Returns the window icon.
    332      */
    333     public static Image getWindowIcon() {
    334         return windowIcon;
    335     }
    336 
    337     /**
    338      * Sets the window icon that is displayed in Java applications
    339      * and applets instead of the default Java icon.
    340      *
    341      * @throws IllegalStateException if caller is not the exit class
    342      */
    343     public static void setWindowIcon(Image image) {
    344         checkExitClass();
    345         windowIcon = image;
    346330    }
    347331
     
    611595        } catch (Exception ex) {
    612596            throw new IllegalStateException("Missing resource bundle in netx.jar:net/sourceforge/jnlp/resource/Messages.properties");
    613         }
    614     }
    615 
    616     /**
    617      * Load the window icon.
    618      */
    619     private static void loadWindowIcon() {
    620         if (windowIcon != null)
    621             return;
    622 
    623         try {
    624             windowIcon = new javax.swing.ImageIcon((new sun.misc.Launcher())
    625                         .getClassLoader().getResource("net/sourceforge/jnlp/resources/netx-icon.png")).getImage();
    626         } catch (Exception ex) {
    627             if (JNLPRuntime.isDebug())
    628                 ex.printStackTrace();
    629597        }
    630598    }
     
    733701    }
    734702
     703    static void setTrustAll(boolean b) {
     704        trustAll=b;
     705    }
     706
     707    public static boolean isTrustAll() {
     708        return trustAll;
     709    }
     710
    735711}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/JNLPSecurityManager.java

    r348 r418  
    282282            //            }
    283283
    284             try {
    285                 super.checkPermission(perm);
    286             } catch (SecurityException se) {
    287 
    288                 //This section is a special case for dealing with SocketPermissions.
    289                 if (JNLPRuntime.isDebug())
    290                     System.err.println("Requesting permission: " + perm.toString());
    291 
    292                 //Change this SocketPermission's action to connect and accept
    293                 //(and resolve). This is to avoid asking for connect permission
    294                 //on every address resolve.
    295                 Permission tmpPerm = null;
    296                 if (perm instanceof SocketPermission) {
    297                     tmpPerm = new SocketPermission(perm.getName(),
    298                                                         SecurityConstants.SOCKET_CONNECT_ACCEPT_ACTION);
    299 
    300                     // before proceeding, check if we are trying to connect to same origin
    301                     ApplicationInstance app = getApplication();
    302                     JNLPFile file = app.getJNLPFile();
    303 
    304                     String srcHost = file.getSourceLocation().getAuthority();
    305                     String destHost = name;
    306 
    307                     // host = abc.xyz.com or abc.xyz.com:<port>
    308                     if (destHost.indexOf(':') >= 0)
    309                         destHost = destHost.substring(0, destHost.indexOf(':'));
    310 
    311                     // host = abc.xyz.com
    312                     String[] hostComponents = destHost.split("\\.");
    313 
    314                     int length = hostComponents.length;
    315                     if (length >= 2) {
    316 
    317                         // address is in xxx.xxx.xxx format
    318                         destHost = hostComponents[length - 2] + "." + hostComponents[length - 1];
    319 
    320                         // host = xyz.com i.e. origin
    321                         boolean isDestHostName = false;
    322 
    323                         // make sure that it is not an ip address
    324                         try {
    325                             Integer.parseInt(hostComponents[length - 1]);
    326                         } catch (NumberFormatException e) {
    327                             isDestHostName = true;
    328                         }
    329 
    330                         if (isDestHostName) {
    331                             // okay, destination is hostname. Now figure out if it is a subset of origin
    332                             if (srcHost.endsWith(destHost)) {
    333                                 addPermission(tmpPerm);
    334                                 return;
    335                             }
    336                         }
    337                     }
    338                 } else {
    339                     tmpPerm = perm;
    340                 }
    341 
    342                 if (tmpPerm != null) {
    343                     //askPermission will only prompt the user on SocketPermission
    344                     //meaning we're denying all other SecurityExceptions that may arise.
    345                     if (askPermission(tmpPerm)) {
    346                         addPermission(tmpPerm);
    347                         //return quietly.
    348                     } else {
    349                         throw se;
    350                     }
    351                 }
    352             }
     284            super.checkPermission(perm);
    353285        } catch (SecurityException ex) {
    354286            if (JNLPRuntime.isDebug()) {
     
    418350            app.addWindow(w);
    419351        }
    420 
    421         // change coffee cup to netx for default icon
    422         if (window instanceof Window)
    423             for (Window w = (Window) window; w != null; w = w.getOwner())
    424                 if (window instanceof Frame)
    425                     ((Frame) window).setIconImage(JNLPRuntime.getWindowIcon());
    426352
    427353        // todo: set awt.appletWarning to custom message
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/runtime/pac-funcs.js

    r348 r418  
    326326 */
    327327function dateRange() {
    328 
    329     // note: watch out for wrapping around of dates. date ranges, like
    330     // month=9 to month=8, wrap around and cover the entire year. this
    331     // makes everything more interesting
    332 
    333     var gmt;
    334         if (arguments.length > 1) {
    335                 if (arguments[arguments.length-1] === "GMT") {
    336                         gmt = true;
    337             arguments.splice(0,arguments.length-1);
    338         }
    339         }
     328    switch (arguments.length) {
     329       case 1: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0]);
     330       case 2: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0],arguments[1]);
     331       case 3: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0],arguments[1],arguments[2]);
     332       case 4: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0],arguments[1],arguments[2],arguments[3]);
     333       case 5: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0],arguments[1],arguments[2],arguments[3],arguments[4]);
     334       case 6: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]);
     335       case 7: return isDateInRange_internallForIcedTeaWebTesting(new Date(),arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6]); //GMT
     336       default:
     337           return false;
     338    }
     339}
     340
     341function isDateInRange_internallForIcedTeaWebTesting() {
    340342
    341343    function isDate(date) {
     
    414416
    415417    function inYearRange(today, year1, year2) {
    416         if (year1 <= today.getYear() && today.getYear() <= year2) {
     418        if (year1 <= today.getFullYear() && today.getFullYear() <= year2) {
    417419            return true;
    418420        } else {
     
    481483    function inYearMonthRange(today, month1, year1, month2, year2) {
    482484        if (year1 === year2) {
    483             if (today.getYear() === year1) {
     485            if (today.getFullYear() === year1) {
    484486               if (month1 <= today.getMonth() && today.getMonth() <= month2) {
    485487                   return true;
     
    492494        }
    493495        if (year1 < year2) {
    494             if (year1 <= today.getYear() && today.getYear() <= year2) {
    495                 if (today.getYear() === year1) {
     496            if (year1 <= today.getFullYear() && today.getFullYear() <= year2) {
     497                if (today.getFullYear() === year1) {
    496498                    if (today.getMonth() >= month1) {
    497499                        return true;
     
    499501                        return false;
    500502                    }
    501                 } else if (today.getYear() === year2) {
     503                } else if (today.getFullYear() === year2) {
    502504                    if (today.getMonth() <= month2) {
    503505                        return true;
     
    514516            return false;
    515517        }
    516 
    517518    }
    518519
    519520    function inYearMonthDateRange(today, date1, month1, year1, date2, month2, year2) {
    520521        if (year1 === year2) {
    521             if (year1 === today.getYear()) {
     522            if (year1 === today.getFullYear()) {
    522523                if ((month1 <= today.getMonth()) && (today.getMonth() <= month2)) {
    523524                    if (month1 === month2) {
     
    549550            }
    550551        } else if (year1 < year2) {
    551             if (year1 <= today.getYear() && today.getYear() <= year2) {
    552                 if (today.getYear() === year1) {
     552            if (year1 <= today.getFullYear() && today.getFullYear() <= year2) {
     553                if (today.getFullYear() === year1) {
    553554                    if (today.getMonth() === month1) {
    554555                        if (today.getDate() >= date1) {
     
    562563                        return false;
    563564                    }
    564                 } else if (today.getYear() === year2) {
    565                     if (today.getMonth() <= month2) {
    566 
    567                     } else {
    568                         return true;
    569                     }
    570                 } else {
    571                     return true;
    572                 }
    573             } else {
    574                 return false;
    575             }
    576         } else {
    577             return false;
    578         }
    579     }
    580 
     565                } else if (today.getFullYear() === year2) {
     566                    if (today.getMonth() === month2) {
     567                        if (today.getDate() <= date1) {
     568                            return true;
     569                        } else {
     570                            return false;
     571                        }
     572                    } else if (today.getMonth() < month2) {
     573                        return true;
     574                    } else {
     575                        return false;
     576                    }
     577                } else {
     578                    return true;
     579                }
     580            } else {
     581                return false;
     582            }
     583        } else {
     584            return false;
     585        }
     586    }
     587
     588    // note: watch out for wrapping around of dates. date ranges, like
     589    // month=9 to month=8, wrap around and cover the entire year. this
     590    // makes everything more interesting
     591
     592    var gmt;
     593        if (arguments.length > 2) {
     594                if (arguments[arguments.length-1] === "GMT") {
     595                        gmt = true;
     596            arguments.splice(0,arguments.length-1);
     597        }
     598        }
    581599    // TODO: change date to gmt, whatever
    582     var today = new Date();
     600    var today = arguments[0]
    583601
    584602    var arg1;
     
    589607    var arg6;
    590608
    591     switch (arguments.length) {
     609    switch (arguments.length-1) {
    592610        case 1:
    593             var arg = arguments[0];
     611            var arg = arguments[1];
    594612            if (isDate(arg)) {
    595613                if (today.getDate() === arg) {
     
    605623                }
    606624            } else { // year
    607                 if (today.getYear() === arg) {
     625                if (today.getFullYear() === arg) {
    608626                    return true;
    609627                } else {
     
    612630            }
    613631        case 2:
    614             arg1 = arguments[0];
    615             arg2 = arguments[1];
     632            arg1 = arguments[1];
     633            arg2 = arguments[2];
    616634            if (isDate(arg1) && isDate(arg2)) {
    617635                var date1 = arg1;
     
    635653            }
    636654        case 4:
    637             arg1 = arguments[0];
    638             arg2 = arguments[1];
    639             arg3 = arguments[2];
    640             arg4 = arguments[3];
     655            arg1 = arguments[1];
     656            arg2 = arguments[2];
     657            arg3 = arguments[3];
     658            arg4 = arguments[4];
    641659
    642660            if (isDate(arg1) && isMonth(arg2) && isDate(arg3) && isMonth(arg4)) {
     
    659677            }
    660678        case 6:
    661             arg1 = arguments[0];
    662             arg2 = arguments[1];
    663             arg3 = arguments[2];
    664             arg4 = arguments[3];
    665             arg5 = arguments[4];
    666             arg6 = arguments[5];
     679            arg1 = arguments[1];
     680            arg2 = arguments[2];
     681            arg3 = arguments[3];
     682            arg4 = arguments[4];
     683            arg5 = arguments[5];
     684            arg6 = arguments[6];
    667685            if (isDate(arg1) && isMonth(arg2) && isYear(arg3) &&
    668686                isDate(arg4) && isMonth(arg5) && isYear(arg6)) {
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/AccessWarningPane.java

    r348 r418  
    105105
    106106        try {
    107             publisher = file.getInformation().getVendor() != null ? file.getInformation().getVendor() : R("SNoAssociatedCertificate");
     107            publisher = file.getInformation().getVendor() != null ?
     108                    file.getInformation().getVendor() + " " + R("SUnverified") :
     109                    R("SNoAssociatedCertificate");
    108110        } catch (Exception e) {
    109111        }
     
    151153        }
    152154
    153         ImageIcon icon = new ImageIcon((new sun.misc.Launcher()).getClassLoader().getResource("net/sourceforge/jnlp/resources/warning.png"));
     155        ImageIcon icon = new ImageIcon((new sun.misc.Launcher()).getClassLoader().getResource("net/sourceforge/jnlp/resources/question.png"));
    154156        JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, SwingConstants.LEFT);
    155157        topLabel.setFont(new Font(topLabel.getFont().toString(),
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/CertWarningPane.java

    r348 r418  
    11/* CertWarningPane.java
    2    Copyright (C) 2008 Red Hat, Inc.
     2   Copyright (C) 2012 Red Hat, Inc.
    33
    44This file is part of IcedTea.
     
    9797        AccessType type = parent.getAccessType();
    9898        JNLPFile file = parent.getFile();
    99         Certificate c = parent.getJarSigner().getPublisher();
     99        Certificate c = parent.getCertVerifier().getPublisher();
    100100
    101101        String name = "";
     
    133133        }
    134134
    135         //Top label
     135        // Labels
    136136        String topLabelText = "";
     137        String bottomLabelText = parent.getCertVerifier().getRootInCacerts() ?
     138                                 R("STrustedSource") : R("SUntrustedSource");
    137139        String propertyName = "";
     140        String iconLocation = "net/sourceforge/jnlp/resources/";
     141        boolean alwaysTrustSelected = false;
    138142        if (certVerifier instanceof HttpsCertVerifier) {
    139             topLabelText = R("SHttpsUnverified") + " " +
    140                                  R("Continue");
     143            // HTTPS certs that are verified do not prompt for a dialog.
     144            // @see VariableX509TrustManager#checkServerTrusted
     145            topLabelText = R("SHttpsUnverified") + " " + R("Continue");
    141146            propertyName = "OptionPane.warningIcon";
     147            iconLocation += "warning.png";
    142148        } else
    143149            switch (type) {
     
    145151                    topLabelText = R("SSigVerified");
    146152                    propertyName = "OptionPane.informationIcon";
     153                    iconLocation += "question.png";
     154                    alwaysTrustSelected = true;
    147155                    break;
    148156                case UNVERIFIED:
    149157                    topLabelText = R("SSigUnverified");
    150158                    propertyName = "OptionPane.warningIcon";
     159                    iconLocation += "warning.png";
     160                    bottomLabelText += " " + R("SWarnFullPermissionsIgnorePolicy");
    151161                    break;
    152162                case SIGNING_ERROR:
    153163                    topLabelText = R("SSignatureError");
    154164                    propertyName = "OptionPane.warningIcon";
     165                    iconLocation += "warning.png";
     166                    bottomLabelText += " " + R("SWarnFullPermissionsIgnorePolicy");
    155167                    break;
    156168            }
     169
    157170        ImageIcon icon = new ImageIcon((new sun.misc.Launcher())
    158                                 .getClassLoader().getResource("net/sourceforge/jnlp/resources/warning.png"));
     171                                .getClassLoader().getResource(iconLocation));
    159172        JLabel topLabel = new JLabel(htmlWrap(topLabelText), icon, SwingConstants.LEFT);
    160173        topLabel.setFont(new Font(topLabel.getFont().toString(),
     
    163176        topPanel.setBackground(Color.WHITE);
    164177        topPanel.add(topLabel, BorderLayout.CENTER);
    165         topPanel.setPreferredSize(new Dimension(400, 60));
     178        topPanel.setPreferredSize(new Dimension(400, 75));
    166179        topPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    167180
     
    176189        alwaysTrust = new JCheckBox(R("SAlwaysTrustPublisher"));
    177190        alwaysTrust.setEnabled(true);
     191        alwaysTrust.setSelected(alwaysTrustSelected);
    178192
    179193        JPanel infoPanel = new JPanel(new GridLayout(4, 1));
     
    211225        add(buttonPanel);
    212226
    213         JLabel bottomLabel;
     227        JLabel bottomLabel = new JLabel(htmlWrap(bottomLabelText));;
    214228        JButton moreInfo = new JButton(R("ButMoreInformation"));
    215229        moreInfo.addActionListener(new MoreInfoButtonListener());
    216 
    217         if (parent.getJarSigner().getRootInCacerts())
    218             bottomLabel = new JLabel(htmlWrap(R("STrustedSource")));
    219         else
    220             bottomLabel = new JLabel(htmlWrap(R("SUntrustedSource")));
    221230
    222231        JPanel bottomPanel = new JPanel();
     
    224233        bottomPanel.add(bottomLabel);
    225234        bottomPanel.add(moreInfo);
    226         bottomPanel.setPreferredSize(new Dimension(500, 100));
     235        bottomPanel.setPreferredSize(new Dimension(600, 100));
    227236        bottomPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
    228237        add(bottomPanel);
     
    232241    private class MoreInfoButtonListener implements ActionListener {
    233242        public void actionPerformed(ActionEvent e) {
    234             SecurityDialog.showMoreInfoDialog(parent.getJarSigner(),
     243            SecurityDialog.showMoreInfoDialog(parent.getCertVerifier(),
    235244                                parent);
    236245        }
     
    245254                try {
    246255                    KeyStore ks = KeyStores.getKeyStore(Level.USER, Type.CERTS);
    247                     X509Certificate c = (X509Certificate) parent.getJarSigner().getPublisher();
     256                    X509Certificate c = (X509Certificate) parent.getCertVerifier().getPublisher();
    248257                    CertificateUtils.addToKeyStore(c, ks);
    249258                    File keyStoreFile = new File(KeyStores.getKeyStoreLocation(Level.USER, Type.CERTS));
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/CertificateUtils.java

    r348 r418  
    3939
    4040import java.io.BufferedInputStream;
     41import java.io.BufferedOutputStream;
    4142import java.io.File;
    4243import java.io.FileInputStream;
     44import java.io.FileOutputStream;
    4345import java.io.IOException;
    4446import java.io.PrintStream;
    4547import java.math.BigInteger;
     48import java.security.InvalidKeyException;
     49import java.security.Key;
    4650import java.security.KeyStore;
    4751import java.security.KeyStoreException;
     52import java.security.NoSuchAlgorithmException;
     53import java.security.NoSuchProviderException;
     54import java.security.SignatureException;
    4855import java.security.cert.Certificate;
    4956import java.security.cert.CertificateException;
    5057import java.security.cert.CertificateFactory;
    5158import java.security.cert.X509Certificate;
     59import java.util.Enumeration;
    5260import java.util.Random;
    5361
    5462import net.sourceforge.jnlp.runtime.JNLPRuntime;
    55 
    56 import sun.misc.BASE64Encoder;
     63import net.sourceforge.jnlp.runtime.Translator;
     64import net.sourceforge.jnlp.util.replacements.BASE64Encoder;
    5765import sun.security.provider.X509Factory;
    5866
     
    114122    }
    115123
     124    public static void addPKCS12ToKeyStore(File file, KeyStore ks, char[] password)
     125            throws Exception {
     126        BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
     127        KeyStore keyStore = KeyStore.getInstance("PKCS12");
     128        keyStore.load(bis, password);
     129
     130        Enumeration<String> aliasList = keyStore.aliases();
     131
     132        while (aliasList.hasMoreElements()) {
     133            String alias = aliasList.nextElement();
     134            Certificate[] certChain = keyStore.getCertificateChain(alias);
     135            Key key = keyStore.getKey(alias, password);
     136            addPKCS12ToKeyStore(certChain, key, ks);
     137        }
     138    }
     139
     140    public static void addPKCS12ToKeyStore(Certificate[] certChain, Key key, KeyStore ks)
     141            throws KeyStoreException {
     142        String alias = null;
     143
     144        // does this certificate already exist?
     145        alias = ks.getCertificateAlias(certChain[0]);
     146        if (alias != null) {
     147            return;
     148        }
     149
     150        // create a unique alias for this new certificate
     151        Random random = new Random();
     152        do {
     153            alias = new BigInteger(20, random).toString();
     154        } while (ks.getCertificate(alias) != null);
     155
     156        ks.setKeyEntry(alias, key, KeyStores.getPassword(), certChain);
     157    }
     158
    116159    /**
    117160     * Checks whether an X509Certificate is already in one of the keystores
     
    123166        for (int i = 0; i < keyStores.length; i++) {
    124167            try {
    125                 if (keyStores[i].getCertificateAlias(c) != null) {
    126                     if (JNLPRuntime.isDebug()) {
    127                         System.out.println(c.getSubjectX500Principal().getName() + " found in cacerts");
    128                     }
    129                     return true;
     168                // Check against all certs
     169                Enumeration<String> aliases = keyStores[i].aliases();
     170                while (aliases.hasMoreElements()) {
     171
     172                    // Verify against this entry
     173                    String alias = aliases.nextElement();
     174
     175                    if (c.equals(keyStores[i].getCertificate(alias))) {
     176                        if (JNLPRuntime.isDebug()) {
     177                            System.out.println(Translator.R("LCertFoundIn", c.getSubjectX500Principal().getName(), KeyStores.getPathToKeystore(keyStores[i].hashCode())));
     178                        }
     179
     180                        return true;
     181                    } // else continue
    130182                }
     183
    131184            } catch (KeyStoreException e) {
    132185                e.printStackTrace();
     
    149202        out.println(X509Factory.END_CERT);
    150203    }
     204
     205    public static void dumpPKCS12(String alias, File file, KeyStore ks, char[] password)
     206            throws Exception {
     207        Certificate[] certChain = ks.getCertificateChain(alias);
     208        Key key = ks.getKey(alias, KeyStores.getPassword());
     209        BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
     210        KeyStore keyStore = KeyStore.getInstance("PKCS12");
     211        keyStore.load(null, null);
     212        keyStore.setKeyEntry(alias, key, password, certChain);
     213        keyStore.store(bos, password);
     214    }
    151215}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/CertsInfoPane.java

    r348 r418  
    8585     */
    8686    void buildTree() {
    87         certPath = parent.getJarSigner().getCertPath();
     87        certPath = parent.getCertVerifier().getCertPath();
    8888        X509Certificate firstCert =
    8989                        ((X509Certificate) certPath.getCertificates().get(0));
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/KeyStores.java

    r348 r418  
    4848import java.security.cert.CertificateException;
    4949import java.util.ArrayList;
     50import java.util.HashMap;
    5051import java.util.List;
     52import java.util.Map;
    5153import java.util.StringTokenizer;
    5254
     
    7678    }
    7779
     80    public static final Map<Integer,String> keystoresPaths=new HashMap<Integer, String>();
     81
    7882    private static DeploymentConfiguration config = null;
    7983
     
    134138        try {
    135139            ks = createKeyStoreFromFile(new File(location), create, DEFAULT_PASSWORD);
     140            //hashcode is used instead of instance so when no references are left
     141            //to keystore, then this will not be blocker for garbage collection
     142            keystoresPaths.put(ks.hashCode(),location);
    136143        } catch (Exception e) {
    137144            e.printStackTrace();
    138145        }
    139146        return ks;
     147    }
     148
     149    public static String getPathToKeystore(int k) {
     150        String s = keystoresPaths.get(k);
     151        if (s == null) {
     152            return "unknown keystore location";
     153        }
     154        return s;
    140155    }
    141156
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/MoreInfoPane.java

    r348 r418  
    6262public class MoreInfoPane extends SecurityDialogPanel {
    6363
     64    private boolean showSignedJNLPWarning;
     65
    6466    public MoreInfoPane(SecurityDialog x, CertVerifier certVerifier) {
    6567        super(x, certVerifier);
     68        showSignedJNLPWarning= x.requiresSignedJNLPWarning();
    6669        addComponents();
    6770    }
     
    7376        ArrayList<String> details = certVerifier.getDetails();
    7477
     78        // Show signed JNLP warning if the signed main jar does not have a
     79        // signed JNLP file and the launching JNLP file contains special properties
     80        if(showSignedJNLPWarning)
     81            details.add(R("SJNLPFileIsNotSigned"));
     82           
    7583        int numLabels = details.size();
    7684        JPanel errorPanel = new JPanel(new GridLayout(numLabels, 1));
     
    8997            errorPanel.add(new JLabel(htmlWrap(details.get(i)), icon, SwingConstants.LEFT));
    9098        }
     99       
     100        // Removes signed JNLP warning after it has been used. This will avoid
     101        // any alteration to certVerifier.
     102        if(showSignedJNLPWarning)
     103            details.remove(details.size()-1);
    91104
    92105        JPanel buttonsPanel = new JPanel(new BorderLayout());
     
    106119    private class CertInfoButtonListener implements ActionListener {
    107120        public void actionPerformed(ActionEvent e) {
    108             SecurityDialog.showCertInfoDialog(parent.getJarSigner(),
     121            SecurityDialog.showCertInfoDialog(parent.getCertVerifier(),
    109122                                parent);
    110123        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityDialog.java

    r348 r418  
    4242import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
    4343import net.sourceforge.jnlp.security.SecurityDialogs.DialogType;
     44import net.sourceforge.jnlp.util.ImageResources;
    4445
    4546import java.awt.*;
     
    9394    private Object value;
    9495
    95     SecurityDialog(DialogType dialogType, AccessType accessType,
    96                 JNLPFile file, CertVerifier jarSigner, X509Certificate cert, Object[] extras) {
     96    /** Should show signed JNLP file warning */
     97    private boolean requiresSignedJNLPWarning;
     98
     99    SecurityDialog(DialogType dialogType, AccessType accessType,
     100                JNLPFile file, CertVerifier JarCertVerifier, X509Certificate cert, Object[] extras) {
    97101        super();
     102        setIconImages(ImageResources.INSTANCE.getApplicationImages());
    98103        this.dialogType = dialogType;
    99104        this.accessType = accessType;
    100105        this.file = file;
    101         this.certVerifier = jarSigner;
     106        this.certVerifier = JarCertVerifier;
    102107        this.cert = cert;
    103108        this.extras = extras;
    104109        initialized = true;
    105110
     111        if(file != null)
     112            requiresSignedJNLPWarning= file.requiresSignedJNLPWarning();
     113
    106114        initDialog();
    107115    }
     
    119127     */
    120128    SecurityDialog(DialogType dialogType, AccessType accessType,
    121                         JNLPFile file, CertVerifier jarSigner) {
    122         this(dialogType, accessType, file, jarSigner, null, null);
     129                        JNLPFile file, CertVerifier certVerifier) {
     130        this(dialogType, accessType, file, certVerifier, null, null);
    123131    }
    124132
     
    159167     * Shows more information regarding jar code signing
    160168     *
    161      * @param jarSigner the JarSigner used to verify this application
     169     * @param certVerifier the JarCertVerifier used to verify this application
    162170     * @param parent the parent option pane
    163171     */
    164172    public static void showMoreInfoDialog(
    165                 CertVerifier jarSigner, SecurityDialog parent) {
    166 
     173                CertVerifier certVerifier, SecurityDialog parent) {
     174
     175        JNLPFile file= parent.getFile();
    167176        SecurityDialog dialog =
    168                         new SecurityDialog(DialogType.MORE_INFO, null, null,
    169                                 jarSigner);
     177                        new SecurityDialog(DialogType.MORE_INFO, null, file,
     178                                certVerifier);
    170179        dialog.setModalityType(ModalityType.APPLICATION_MODAL);
    171180        dialog.setVisible(true);
     
    176185     * Displays CertPath information in a readable table format.
    177186     *
    178      * @param jarSigner the JarSigner used to verify this application
     187     * @param certVerifier the JarCertVerifier used to verify this application
    179188     * @param parent the parent option pane
    180189     */
    181     public static void showCertInfoDialog(CertVerifier jarSigner,
     190    public static void showCertInfoDialog(CertVerifier certVerifier,
    182191                SecurityDialog parent) {
    183192        SecurityDialog dialog = new SecurityDialog(DialogType.CERT_INFO,
    184                         null, null, jarSigner);
     193                        null, null, certVerifier);
    185194        dialog.setLocationRelativeTo(parent);
    186195        dialog.setModalityType(ModalityType.APPLICATION_MODAL);
     
    208217
    209218        String dialogTitle = "";
    210         if (dialogType == DialogType.CERT_WARNING)
    211             dialogTitle = "Warning - Security";
    212         else if (dialogType == DialogType.MORE_INFO)
     219        if (dialogType == DialogType.CERT_WARNING) {
     220            if (accessType == AccessType.VERIFIED)
     221                dialogTitle = "Security Approval Required";
     222            else
     223                dialogTitle = "Security Warning";
     224        } else if (dialogType == DialogType.MORE_INFO)
    213225            dialogTitle = "More Information";
    214226        else if (dialogType == DialogType.CERT_INFO)
     
    267279    }
    268280
    269     public CertVerifier getJarSigner() {
     281    public CertVerifier getCertVerifier() {
    270282        return certVerifier;
    271283    }
     
    370382        listeners.add(listener);
    371383    }
     384   
     385    public boolean requiresSignedJNLPWarning()
     386    {
     387        return requiresSignedJNLPWarning;
     388    }
    372389
    373390}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/SecurityDialogs.java

    r348 r418  
    181181     * @param accessType the type of warning dialog to show
    182182     * @param file the JNLPFile associated with this warning
    183      * @param jarSigner the JarSigner used to verify this application
     183     * @param certVerifier the JarCertVerifier used to verify this application
     184     *
     185     * @return true if the user accepted the certificate
    184186     */
    185187    public static boolean showCertWarningDialog(AccessType accessType,
    186             JNLPFile file, CertVerifier jarSigner) {
     188            JNLPFile file, CertVerifier certVerifier) {
    187189
    188190        if (!shouldPromptUser()) {
     
    194196        message.accessType = accessType;
    195197        message.file = file;
    196         message.certVerifier = jarSigner;
     198        message.certVerifier = certVerifier;
    197199
    198200        Object selectedValue = getUserResponse(message);
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/VariableX509TrustManager.java

    r348 r418  
    3838package net.sourceforge.jnlp.security;
    3939
     40import java.security.AccessController;
    4041import java.security.KeyStore;
     42import java.security.PrivilegedAction;
    4143import java.security.cert.Certificate;
    4244import java.security.cert.CertificateException;
     
    5456
    5557import com.sun.net.ssl.internal.ssl.X509ExtendedTrustManager;
     58import net.sourceforge.jnlp.runtime.JNLPRuntime;
    5659
    5760import net.sourceforge.jnlp.security.SecurityDialogs.AccessType;
     
    380383     * @return user's response
    381384     */
    382     private boolean askUser(X509Certificate[] chain, String authType,
    383                             boolean isTrusted, boolean hostMatched,
    384                             String hostName) {
    385         return SecurityDialogs.showCertWarningDialog(
     385    private boolean askUser(final X509Certificate[] chain, final String authType,
     386                            final boolean isTrusted, final boolean hostMatched,
     387                            final String hostName) {
     388        if (JNLPRuntime.isTrustAll()){
     389            return true;
     390        }
     391        final VariableX509TrustManager trustManager = this;
     392        return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
     393            @Override
     394            public Boolean run() {
     395                return SecurityDialogs.showCertWarningDialog(
    386396                        AccessType.UNVERIFIED, null,
    387                         new HttpsCertVerifier(this, chain, authType,
     397                        new HttpsCertVerifier(trustManager, chain, authType,
    388398                                              isTrusted, hostMatched,
    389399                                              hostName));
     400            }
     401        });
    390402    }
    391403
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/viewer/CertificatePane.java

    r348 r418  
    6767import javax.swing.JOptionPane;
    6868import javax.swing.JPanel;
     69import javax.swing.JPasswordField;
    6970import javax.swing.JScrollPane;
    7071import javax.swing.JTabbedPane;
     
    101102            new CertificateType(KeyStores.Type.CERTS),
    102103            new CertificateType(KeyStores.Type.JSSE_CERTS),
     104            new CertificateType(KeyStores.Type.CLIENT_CERTS)
    103105        };
    104106
     
    302304    }
    303305
     306    private char[] getPassword(final String label) {
     307        JPasswordField jpf = new JPasswordField();
     308        int result = JOptionPane.showConfirmDialog(parent,
     309                                new Object[]{label, jpf},  R("CVPasswordTitle"),
     310                                JOptionPane.OK_CANCEL_OPTION,
     311                                JOptionPane.INFORMATION_MESSAGE);
     312        if (result == JOptionPane.OK_OPTION)
     313            return jpf.getPassword();
     314        else
     315            return null;
     316    }
     317
    304318    /** Allows storing KeyStores.Types in a JComponent */
    305319    private static class CertificateType {
     
    365379                try {
    366380                    KeyStore ks = keyStore;
    367                     CertificateUtils.addToKeyStore(chooser.getSelectedFile(), ks);
     381                    if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) {
     382                        char[] password = getPassword(R("CVImportPasswordMessage"));
     383                        if (password != null) {
     384                            CertificateUtils.addPKCS12ToKeyStore(
     385                                       chooser.getSelectedFile(), ks, password);
     386                        } else {
     387                            return;
     388                        }
     389                    } else {
     390                        CertificateUtils.addToKeyStore(chooser.getSelectedFile(), ks);
     391                    }
    368392                    File keyStoreFile = new File(KeyStores
    369393                                        .getKeyStoreLocation(currentKeyStoreLevel, currentKeyStoreType));
     
    409433                                                        .get(selectedRow));
    410434                        if (alias != null) {
    411                             Certificate c = keyStore.getCertificate(alias);
    412                             PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath());
    413                             CertificateUtils.dump(c, ps);
     435                            if (currentKeyStoreType == KeyStores.Type.CLIENT_CERTS) {
     436                                char[] password = getPassword(R("CVExportPasswordMessage"));
     437                                if (password != null)
     438                                    CertificateUtils.dumpPKCS12(alias, chooser.getSelectedFile(), keyStore, password);
     439                            } else {
     440                                Certificate c = keyStore.getCertificate(alias);
     441                                PrintStream ps = new PrintStream(chooser.getSelectedFile().getAbsolutePath());
     442                                CertificateUtils.dump(c, ps);
     443                            }
    414444                            repopulateTables();
    415445                        }
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/security/viewer/CertificateViewer.java

    r348 r418  
    5252
    5353import net.sourceforge.jnlp.runtime.JNLPRuntime;
     54import net.sourceforge.jnlp.util.ImageResources;
    5455
    5556public class CertificateViewer extends JDialog {
     
    6263    public CertificateViewer() {
    6364        super((Frame) null, dialogTitle, true);
     65        setIconImages(ImageResources.INSTANCE.getApplicationImages());
    6466
    6567        Container contentPane = getContentPane();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/ServiceUtil.java

    r348 r418  
    236236                Object... extras) {
    237237
    238         if (app == null)
    239             app = JNLPRuntime.getApplication();
    240 
    241         boolean codeTrusted = true;
    242 
    243         StackTraceElement[] stack = Thread.currentThread().getStackTrace();
    244 
    245         for (int i = 0; i < stack.length; i++) {
    246 
    247             Class c = null;
    248 
    249             try {
    250                 c = Class.forName(stack[i].getClassName());
    251             } catch (Exception e1) {
    252                 try {
    253                     c = Class.forName(stack[i].getClassName(), false, app.getClassLoader());
    254                 } catch (Exception e2) {
    255                     System.err.println(e2.getMessage());
    256                 }
    257             }
    258 
    259             // Everything up to the desired class/method must be trusted
    260             if (c == null || // class not found
    261                     (c.getProtectionDomain().getCodeSource() != null && // class is not in bootclasspath
    262                     c.getProtectionDomain().getCodeSource().getCodeSigners() == null) // class is trusted
    263             ) {
    264                 codeTrusted = false;
    265             }
    266         }
    267 
    268         if (!codeTrusted) {
     238        boolean trusted = isSigned(app);
     239
     240        if (!trusted) {
    269241
    270242            if (!shouldPromptUser()) {
    271243                return false;
    272244            }
     245            if (app == null)
     246                app = JNLPRuntime.getApplication();
    273247
    274248            final AccessType tmpType = type;
     
    308282        });
    309283    }
     284   
     285    /**
     286     * Returns whether the app requesting a JNLP service is a trusted
     287     * application
     288     *
     289     * @param app
     290     *            the application which is requesting the check. If null, the
     291     *            current application is used.
     292     * @return true, if the app is a trusted application; false otherwise
     293     */
     294
     295    public static boolean isSigned(ApplicationInstance app) {
     296
     297        if (app == null)
     298            app = JNLPRuntime.getApplication();
     299
     300        StackTraceElement[] stack = Thread.currentThread().getStackTrace();
     301
     302        for (int i = 0; i < stack.length; i++) {
     303
     304            Class c = null;
     305
     306            try {
     307                c = Class.forName(stack[i].getClassName());
     308            } catch (Exception e1) {
     309                try {
     310                    c = Class.forName(stack[i].getClassName(), false,
     311                            app.getClassLoader());
     312                } catch (Exception e2) {
     313                    System.err.println(e2.getMessage());
     314                }
     315            }
     316
     317            // Everything up to the desired class/method must be trusted
     318            if (c == null || // class not found
     319                    (c.getProtectionDomain().getCodeSource() != null && // class is not in bootclasspath
     320                    c.getProtectionDomain().getCodeSource().getCodeSigners() == null) // class is trusted
     321            ) {
     322                return false;
     323            }
     324        }
     325        return true;
     326    }
    310327
    311328}
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/services/XPersistenceService.java

    r348 r418  
    5353
    5454        URL source = app.getJNLPFile().getCodeBase();
     55       
     56        if (!source.getHost().equalsIgnoreCase(location.getHost())
     57                && !ServiceUtil.isSigned(app)) // Allow trusted application to have access to data from a different host
     58            throw new MalformedURLException(
     59                    "Untrusted application cannot access data from a different host.");
    5560
    56         if (!source.getHost().equalsIgnoreCase(location.getHost()))
    57             throw new MalformedURLException("Cannot access data from a different host.");
    5861
    5962        // test for above codebase, not perfect but works for now
     
    7073        }
    7174
    72         if (!source.getFile().startsWith(requestPath))
    73             throw new MalformedURLException("Cannot access data below source URL path.");
     75        if (!source.getFile().startsWith(requestPath)
     76                && !ServiceUtil.isSigned(app)) // Allow trusted application to have access to data below source URL path
     77            throw new MalformedURLException(
     78                    "Cannot access data below source URL path.");
    7479    }
    7580
     
    123128
    124129        File file = toCacheFile(location);
    125         if (!file.exists())
     130        if (!file.exists()) {
    126131            throw new FileNotFoundException("Persistence store for "
    127132                    + location.toString() + " is not found.");
     133        }
    128134        FileUtils.createParentDir(file, "Persistence store for "
    129135                    + location.toString());
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/tools/KeyStoreUtil.java

    r348 r418  
    3434
    3535    // Class and methods marked as public so that they can be
    36     // accessed by JarSigner, which although lies in a package
     36    // accessed by JarCertVerifier, which although lies in a package
    3737    // with the same name, but bundled in tools.jar and loaded
    3838    // by another class loader, hence in a different *runtime*
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/BasicExceptionDialog.java

    r348 r418  
    8383        JOptionPane optionPane = new JOptionPane(mainPanel, JOptionPane.ERROR_MESSAGE);
    8484        final JDialog errorDialog = optionPane.createDialog(R("Error"));
     85        errorDialog.setIconImages(ImageResources.INSTANCE.getApplicationImages());
    8586
    8687        final JPanel quickInfoPanel = new JPanel();
  • trunk/icedtea-web/netx/net/sourceforge/jnlp/util/PropertiesFile.java

    r348 r418  
    3636    /** the header string */
    3737    String header = "netx file";
    38 
    39     /** lazy loaded on getProperty */
    40     boolean loaded = false;
     38   
     39    /** time of last modification, lazy loaded on getProperty */
     40    long lastStore;
    4141
    4242    /**
     
    6565     */
    6666    public String getProperty(String key) {
    67         if (!loaded)
     67        if (lastStore == 0)
    6868            load();
    6969
     
    7676     */
    7777    public String getProperty(String key, String defaultValue) {
    78         if (!loaded)
     78        if (lastStore == 0)
    7979            load();
    8080
     
    8888     */
    8989    public Object setProperty(String key, String value) {
    90         if (!loaded)
     90        if (lastStore == 0)
    9191            load();
    9292
     
    105105     * loaded; call this method before calling any method defined by
    106106     * a superclass.
     107     *
     108     * @return true, if file was (re-)loaded
     109     *         false, if file was still current
    107110     */
    108     public void load() {
    109         loaded = true;
     111    public boolean load() {
    110112
    111         InputStream s = null;
    112         try {
    113             if (!file.exists())
    114                 return;
     113        if (!file.exists()) {
     114            return false;
     115        }
    115116
     117        long currentStore = file.lastModified();
     118        long currentTime = System.currentTimeMillis();
     119
     120        /* (re)load file, if
     121         *  - it wasn't loaded/stored, yet (lastStore == 0)
     122         *  - current file modification timestamp has changed since last store (currentStore != lastStore) OR
     123         *  - current file modification timestamp has not changed since last store AND current system time equals current file modification timestamp
     124         *    This is necessary because some filesystems seems only to provide accuracy of the timestamp on the level of seconds!
     125         */
     126        if(lastStore == 0 || currentStore != lastStore || (currentStore == lastStore && currentStore / 1000 == currentTime / 1000)) {
     127            InputStream s = null;
    116128            try {
    117                 s = new FileInputStream(file);
    118                 load(s);
    119             } finally {
    120                 if (s != null) s.close();
     129
     130                try {
     131                    s = new FileInputStream(file);
     132                    load(s);
     133                } finally {
     134                    if (s != null) {
     135                        s.close();
     136                        lastStore=currentStore;
     137                        return true;
     138                    }
     139                }
     140            } catch (IOException ex) {
     141                ex.printStackTrace();
    121142            }
    122         } catch (IOException ex) {
    123             ex.printStackTrace();
    124143        }
     144
     145        return false;
    125146    }
    126147
     
    129150     */
    130151    public void store() {
    131         if (!loaded)
    132             return; // nothing could have changed so save unnecessary load/save
    133152
    134         OutputStream s = null;
     153        FileOutputStream s = null;
    135154        try {
    136155            try {
     156                file.getParentFile().mkdirs();
    137157                s = new FileOutputStream(file);
    138158                store(s, header);
     159
     160                // fsync()
     161                s.getChannel().force(true);
     162                lastStore = file.lastModified();
    139163            } finally {
    140164                if (s != null) s.close();
  • trunk/icedtea-web/netx/net/sourceforge/nanoxml/XMLElement.java

    r348 r418  
    11671167     *             xml file.
    11681168     */
    1169     public void sanitizeInput(InputStreamReader isr, PipedOutputStream pout) {
     1169    public void sanitizeInput(Reader isr, OutputStream pout) {
    11701170        try {
    11711171            PrintStream out = new PrintStream(pout);
     
    12211221                this.sanitizeCharReadTooMuch = next;
    12221222
    1223                 // If the next char is a ? or !, then we've hit a special tag,
     1223                // If the next chars are !--, then we've hit a comment tag,
    12241224                // and should skip it.
    1225                 if (prev == '<' && (next == '!' || next == '?')) {
    1226                     this.skipSpecialTag(0);
    1227                     this.sanitizeCharReadTooMuch = '\0';
     1225                if (ch == '<' && sanitizeCharReadTooMuch == '!') {
     1226                    ch = (char) this.reader.read();
     1227                    if (ch == '-') {
     1228                        ch = (char) this.reader.read();
     1229                        if (ch == '-') {
     1230                            this.skipComment();
     1231                            this.sanitizeCharReadTooMuch = '\0';
     1232                        } else {
     1233                            out.print('<');
     1234                            out.print('!');
     1235                            out.print('-');
     1236                            this.sanitizeCharReadTooMuch = ch;
     1237                            if (JNLPRuntime.isDebug()) {
     1238                                System.out.print('<');
     1239                                System.out.print('!');
     1240                                System.out.print('-');
     1241                            }
     1242                        }
     1243                    } else {
     1244                        out.print('<');
     1245                        out.print('!');
     1246                        this.sanitizeCharReadTooMuch = ch;
     1247                        if (JNLPRuntime.isDebug()) {
     1248                            System.out.print('<');
     1249                            System.out.print('!');
     1250                        }
     1251                    }
    12281252                }
    12291253                // Otherwise we haven't hit a comment, and we should write ch.
Note: See TracChangeset for help on using the changeset viewer.