Local file writing by signed applets blocked by Safari

Local file writing by signed applets is blocked on Safari, due to a November 2013 Safari security change.

Steps to reproduce:

Expected behavior:

The expected behavior is what is seen on Windows and on Firefox on the Macintosh.

Actual behavior:

Regression:

This appeared at the same time as an inability to read local files, as demonstrated at "Local file reading by signed applets blocked by Safari" and the inability of a signed Java applet in Safari to launch new browser windows using Runtime.getRuntime().exec.  

Workarounds:

Firefox is not affected, but the issue in Safari can be fixed as follows: Safari > Preferences > Security > Manage Website Settings… > Java > (your site) > Run in Unsafe Mode > Trust

Source code:

import java.awt.*;
import java.applet.*;
import java.io.*;
import java.net.*;
import java.awt.event.*;

public class localFileWrite extends Applet implements ActionListener {

Button button;
boolean macOS;
boolean windowsOS;
String userHome;
URL rootOnClientURL;
String reportString;

public void init()
{
   setBackground(new Color(255, 240, 200));
   button = new Button("Write file"); // file creation doesn't work from init, so a button and actionPerformed are used
   button.addActionListener(this);
   add(button);
   macOS = (System.getProperty("os.name").startsWith("Mac"));
   windowsOS = (System.getProperty("os.name").startsWith("Win"));
   userHome = System.getProperty("user.home");
   try
   {
     if (macOS) rootOnClientURL = new URL("file", "", "//" + System.getProperty("user.home") + "/");
     else if (windowsOS) rootOnClientURL = new URL("file:/" + userHome.replace('\\', '/') + "/AppData/LocalLow/");
   }
   catch (Exception e)
   {
     System.out.println("Couldn't form URL");
     rootOnClientURL = null;
   }
}

public void actionPerformed(ActionEvent ae)
{
   if (ae.getSource() == button)
   {
     try
     {
       String fileString = new URL(rootOnClientURL + "localFile.txt").getFile();
       fileString = getLocalFileForm(fileString);
       FileOutputStream fos = new FileOutputStream(fileString);
       BufferedOutputStream bos = new BufferedOutputStream(fos, 32768);
       DataOutputStream dos = new DataOutputStream(bos);
       dos.writeUTF("Test file contents");
        dos.close();
       bos.close();
       fos.close();
        reportString = "Writing a local file worked.";
      }
     catch (Exception e)
     {
       reportString = "Writing a local file didn't work. The Exception is: " + e.getMessage();
     }
     repaint();
   }
}

final String getLocalFileForm(String string)
{
   if (!macOS) while (string.startsWith("/")) string = string.substring(1);
   string = string.replace ('/', File.separatorChar);
   StringBuffer out = new StringBuffer(string.length());
   for (int i=0; i<string.length(); i++)
   {
     char c = string.charAt(i);
     if (c == '+') out.append(' '); // + is a space
     else if (c == '%') // e.g. %20 is a space
     {
       int c1 = Character.digit(string.charAt(++i), 16);
       int c2 = Character.digit(string.charAt(++i), 16);
       out.append((char) (c1*16 + c2));
     }
     else out.append(c);
   }
   return (out.toString());
}

public void paint(Graphics g)
{
   g.drawString("rootOnClientURL = " + rootOnClientURL, 10, 40);
   g.drawString(reportString, 10, 70);
}
} // END OF Class localFileWrite

If you have any insights or comments about this page please contact Mickey Segal.  A listing of  many Java resources is at this link.