0

I need to send a zipped database (payload ~10 MB) to a PHP web service using SSL.

The code worked fine for weeks, but suddently I get a ssl broken pipe exception (SSL Broken Pipe). I don't see any reason for the error - I did not changed the code and the server config is still the same (the IIS was able to handle the data-transfer by ssl before).

Currently I use the java.net.HttpsURLConnection (code below) - which alternative would you recommend me to use when sending a file from Android to a web service? It seems that the POST is not processed on the device.

Thanks in advance

try {
    final File compressedDb = new File(Environment.getExternalStorageDirectory() + "/" + Const.TMP_DIR + "/database.zip");
    String sourceFileUri = compressedDb.getPath();

final long compressedDbSize = compressedDb.length();
float optimized = ((float) _dbSize / (float) compressedDbSize) * 100f;
int dbKb = (int) (((float) _dbSize) / 1024f);
int dbCompKb = (int) ((float) compressedDbSize / 1024f);
compressionInfo = getString(R.string.compression) + ": " +
        dbKb + "kB " + getString(R.string.to) + " " + dbCompKb + "kB" + "<br>" +
        getString(R.string.saved) + ": " + (int) optimized + "%" + "<br>";

Log.i(TAG, "DB name=" + compressedDb.getName() + " size=" + compressedDb.length() / 1024 + "kB.");

HttpsURLConnection connection;
DataOutputStream dos;
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
File sourceFile = new File(sourceFileUri);
//                int maxBufferSize = 1024 * 1024;
int maxBufferSize = (int) sourceFile.length();

if (sourceFile.isFile()) {

    try {

        // open a URL connection to the Servlet
        FileInputStream fileInputStream = new FileInputStream(sourceFile);
        url = new URL(params[0]);

connection = (HttpsURLConnection) url.openConnection();
connection.setDoInput(true); // Allow Inputs
connection.setUseCaches(false); // Don't use a Cached Copy
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("ENCTYPE", "multipart/form-data");
connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
connection.setRequestProperty("the_database", sourceFileUri);

        dos = new DataOutputStream(connection.getOutputStream());

        dos.writeBytes(twoHyphens + boundary + lineEnd);
        dos.writeBytes("Content-Disposition: form-data; name=\"the_database\";" +
                "filename=\"" + sourceFileUri + "\"" + lineEnd);

        dos.writeBytes(lineEnd);

        // create a buffer of maximum size
        bytesAvailable = fileInputStream.available();

        bufferSize = Math.min(bytesAvailable, maxBufferSize);
        buffer = new byte[bufferSize];

        // read file and write it into form...
        bytesRead = fileInputStream.read(buffer, 0, bufferSize);

        int bytesTotal = bytesAvailable;

        Log.i(TAG, "maxBuffer=" + maxBufferSize +
                " | bytesTotal=" + bytesTotal + " | bytesAvailable=" + bytesAvailable);

        while (bytesRead > 0) {
            dos.write(buffer, 0, bufferSize);
            bytesAvailable = fileInputStream.available();
            bufferSize = Math.min(bytesAvailable, maxBufferSize);
            bytesRead = fileInputStream.read(buffer, 0, bufferSize);
            int progress = 100 - (int) (((float) bytesAvailable * 100 / (float) bytesTotal));
            publishProgress("" + progress);
        }

        // send multipart form data necessary after file data...
        dos.writeBytes(lineEnd);
        dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);

        // Responses from the server (code and message)
        int serverResponseCode = connection.getResponseCode();
        final String responseMessagePostDb = connection.getResponseMessage();

        fileInputStream.close();
        dos.flush();
        dos.close();

        if (responseMessagePostDb != null) {
            responseStrings.add("<br>");
            responseStrings.add("<b><u>" + getString(R.string.optimisation_string) + "</u></b>" + "<br>");
            responseStrings.add(params[1]);

            responseStrings.add("<b><u>" + getString(R.string.optimisation_database) + "</u></b>" + "<br>");
            responseStrings.add(compressionInfo);

            String response = (responseMessagePostDb.equals("OK") ? ("<font color=\"" + GREEN + "\">PASSED</font>") : "FAILED");

            responseStrings.add(getString(R.string.server_response) + ": " + response);
            return responseStrings;
            }

        } catch (Exception e) {
            Log.e(TAG, "doInBackground: " + e.getMessage());
            responseStrings.add("FAILED2"); // <- this exception is thrown
            responseStrings.add(e.getMessage());
            return responseStrings;
        }
    }
} catch (Exception ex) {
    Log.e(TAG, "doInBackground: " + ex.getMessage());
    responseStrings.add("FAILED3");
    responseStrings.add(ex.getMessage());
    return responseStrings;
}

Log.e(TAG, "doInBackground: " + "FAILED4");
responseStrings.add("FAILED4");
responseStrings.add("Unexpected Error...");
return responseStrings;
Martin Pfeffer
  • 12,471
  • 9
  • 59
  • 68
  • 1
    To the question "which alternative would you recommend", my library of choice is (as for lots of developers) [Retrofit](https://github.com/square/retrofit). – Xavier Rubio Jansana Aug 31 '17 at 08:24

1 Answers1

1

If your code worked up to this point, then logically, unless you have a race condition in your code, you're not going to see inconsistent results unless it isn't the code. In other words, if the server decided to enforce a connection timeout, your code would begin to fail seemingly without reason. Even the link to the problem involving a SSL Broken Pipe exception seems to imply that the reason is the server, not the client.

My advice would be to try to come up with various reasons for the failure which involve the server doing something it shouldn't and then testing each theory by altering your code. In other words, if the problem were a matter of timeout, time the operation and send a smaller file over the network and verify if that works. If it does, you have your problem. If it doesn't, then move on to the next theory.

Unfortunately not being a problem with the mentioned code, that makes this problem unsolveable without knowing further details.

Neil
  • 5,762
  • 24
  • 36