1

I'm having a problem with picture uploading in Internet Explorer 7, 8 and 9 (haven't tested other versions). It works fine in FF and Chrome, but for some reason the picture is uploaded wrong when i try to upload in any versions of IE.

What i mean by that is that the file gets uploaded in the right directory with the right name, but i cant open it in any picture editing programs.

Furthermore when i open the picutre in Notepad++ i see that the picture got some meta data displaying like:

-----------------------------7db1f6c907fe Content-Disposition: form-data; name="qqfile"; filename="jingjang.jpg" Content-Type: image/jpeg

(hashcode here)

-----------------------------7db1f6c907fe--

If i remove the code the picture works fine! So can anyone tell me what is generating the code and how do i stop it? :)

I use Valums Ajax Upload on my JSP page:

var imageFolder = "images/upload/<%=user.getUsername()%>/temp/";
new qq.FileUploader({

element: document.getElementById('TempUploadButton'),
action: 'OctetStreamReader',
debug: false,
multiple: false,
params: {"type" : "user"},

onComplete: function(id, fileName) {    
    var d = new Date();
    $("#UserPageAvatarPic a img").attr("src", imageFolder+"<%=user.getUsername()%>.jpg?cache="+d.getTime() );
},
onSubmit : function(id, fileName) {
    // hide all prev elements
    $('#TempUploadButton ul.qq-upload-list li').each(function() {
        $(this).hide();
    });
}

});

And OctetStreamReader as my servlet

    public class OctetStreamReader extends HttpServlet {

private static final long serialVersionUID = 6748857432950840322L;
private static final String DESTINATION_DIR_PATH = "files";
private static String realPath;
UserService userService = UserService.getService();

/**
 * {@inheritDoc}
 * @param config
 * @throws ServletException
 */
@Override
public void init(ServletConfig config) throws ServletException {
    super.init(config);
    realPath = getServletContext().getRealPath(DESTINATION_DIR_PATH) + "/";
}

/** 
 * Handles the HTTP <code>POST</code> method.
 * @param request servlet request
 * @param response servlet response
 * @throws ServletException if a servlet-specific error occurs
 * @throws IOException if an I/O error occurs
 */
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
        throws ServletException {
    User user = userService.getUser(((Integer) request.getSession().getAttribute("user")).intValue());
    String type = request.getParameter("type");
    String username = user.getUsername();
    PrintWriter writer = null;
    InputStream is = null;
    FileOutputStream fos = null;
    type = "user";
    try {
        writer = response.getWriter();
    } catch (IOException ex) {
        log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
    }

    try {
        String filename = "";
        if (type.equals("user")) {
            realPath = getServletContext().getRealPath("/images/upload/" + username + "/temp/");
            is = request.getInputStream();
            String strDirectoy = getServletContext().getRealPath("/images/upload/" + username + "/temp/" );
            boolean success = (new File(strDirectoy)).mkdir();
            File f1 = new File(strDirectoy);
            File[] children = f1.listFiles();
            filename = username + ".jpg";
        }
        if (type.equals("post"))  {
            realPath = getServletContext().getRealPath("/images/upload/" + username + "/post/");
            is = request.getInputStream();
            String strDirectoy = getServletContext().getRealPath("/images/upload/" + username + "/post/" );
            boolean success = (new File(strDirectoy)).mkdir();
            File f1 = new File(strDirectoy);
            File[] children = f1.listFiles();
            filename = Calendar.getInstance().getTimeInMillis()+".jpg";
        }
        if (type.equals("editpost"))  {
            realPath = getServletContext().getRealPath("/images/upload/" + username + "/editpost/");
            is = request.getInputStream();
            String strDirectoy = getServletContext().getRealPath("/images/upload/" + username + "/editpost/" );
            boolean success = (new File(strDirectoy)).mkdir();
            File f1 = new File(strDirectoy);
            File[] children = f1.listFiles();
            filename = Calendar.getInstance().getTimeInMillis() + ".jpg";
        }


        fos = new FileOutputStream(new File(realPath + "/" + filename), false);
        IOUtils.copy(is, fos);
        response.setStatus(response.SC_OK);
        writer.print("{success: true, filename: \"" + filename + "\"}");
    } catch (FileNotFoundException ex) {
        response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
        writer.print("{success: false}");
        log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
    } catch (IOException ex) {
        response.setStatus(response.SC_INTERNAL_SERVER_ERROR);
        writer.print("{success: false}");
        log(OctetStreamReader.class.getName() + "has thrown an exception: " + ex.getMessage());
    } finally {
        try {
            fos.close();
            is.close();
        } catch (IOException ignored) {
        }
    }
 writer.flush();
    writer.close();
}
}

Also in fileuploader.js i tried to change the Content Type from application/octet-stream to multipart/form-data

        /**
 * Sends the file identified by id and additional query params to the server
 * @param {Object} params name-value string pairs
 */    
_upload: function(id, params){
    var file = this._files[id],
        name = this.getName(id),
        size = this.getSize(id);

    this._loaded[id] = 0;

    var xhr = this._xhrs[id] = new XMLHttpRequest();
    var self = this;

    xhr.upload.onprogress = function(e){
        if (e.lengthComputable){
            self._loaded[id] = e.loaded;
            self._options.onProgress(id, name, e.loaded, e.total);
        }
    };

    xhr.onreadystatechange = function(){            
        if (xhr.readyState == 4){
            self._onComplete(id, xhr);                    
        }
    };

    // build query string
    params = params || {};
    params['qqfile'] = name;
    var queryString = qq.obj2url(params, this._options.action);

    xhr.open("POST", queryString, true);
    xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    xhr.setRequestHeader("X-File-Name", encodeURIComponent(name));
    xhr.setRequestHeader("Content-Type", "multipart/form-data");
    xhr.send(file);
},
Sergey K.
  • 24,894
  • 13
  • 106
  • 174
Emil Kaminski
  • 1,886
  • 2
  • 16
  • 26

2 Answers2

1

Use this:

InputStream is = null;
         // Check that we have a file upload request
        boolean isMultipart = ServletFileUpload.isMultipartContent(request);
        // Create a factory for disk-based file items
        if (isMultipart) {
            FileItemFactory factory = new DiskFileItemFactory();
            // Create a new file upload handler
            ServletFileUpload upload = new ServletFileUpload(factory);
            try {
                // Parse the request
                ArrayList<DiskFileItem> files = (ArrayList<DiskFileItem>) upload.parseRequest(request);
                if (!files.isEmpty()) {
                    is = files.get(0).getInputStream();
                }
            } catch (FileUploadException ex) {
                Logger.getLogger(OctetStreamReader.class.getName()).log(Level.SEVERE, null, ex);
            }
        } else {
            is = request.getInputStream();
        }
1

HTML file uploads use by default the multipart/form-data request encoding (this is in order to be able to upload multiple files and/or to mix normal input field values in one request). You're however not parsing and extracting the individual form data parts from the request body, instead you're reading and writing the entire request body plain unmodified to a file.

is = request.getInputStream();
fos = new FileOutputStream(new File(realPath + "/" + filename), false);
IOUtils.copy(is, fos);

This is indeed not ever going to work. That you said that it works in FF/Chrome is beyond me. Perhaps you're misinterpreting the results or do not have tested it in those browsers with binary files at all.

You need to use Apache Commons FileUpload to extract the parts from a multipart/form-data request. Or, when you're already on Servlet 3.0, you could also use the Servlet API provided HttpServletRequest#getParts() method.

See also:


Unrelated to the concrete problem, you've another problem with the code posted so far. You're storing uploaded files in the web content of the expanded WAR. This is far from a solid permanent storage location. Everytime when you redeploy a new WAR, all those files will get lost. You'd need to backup them everytime which is plain clumsy and error prone. Rather store them in a fixed location outside the expanded WAR folder.

See also:

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Thank you for answer. I dont quite understand what you mean by why the way i do it should not work. I got the OctetStreamReader.java from valums homepage together with the whole package and only modified it a little:[link](http://valums.com/ajax-upload/) Also i tried using Apache Commons FileUpload and it worked fine when i submitted the picture together with the form using: But it did not work with the Ajax Uploader and i kinda need a dynamic pic upload before submitting the whole form. Thats why i tried to go back to this – Emil Kaminski Oct 17 '11 at 22:56