title: Uploading Image as Multipart request using Volley?
body: <p>I'm trying to post my image using Volley but i'm unable to upload my image to the server. I always get <strong>com.volley.ServerError</strong>. When I capture the image upload request using Fiddler, it gives me a 500 status/error code.</p>
  
  <p>Here is my code for selecting image from gallery:</p>
  
  <pre><code>@Override
  public void onActivityResult(int requestCode, int resultCode, Intent data) {
      super.onActivityResult(requestCode, resultCode, data);
  
      if (data == null) {
          Toast.makeText(getActivity(), "No Image Selected", Toast.LENGTH_SHORT).show();
      } else if (requestCode == Constants.CHOICE_AVATAR_FROM_GALLERY &amp;&amp; resultCode == getActivity().RESULT_OK) {
          Bitmap avatar = getBitmapFromData(data);
  
  
          RestClient restClient = new RestClient(getActivity());
    restClient.stringRequest(Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID, Constants.PROFILE_UPDATE_IMAGE_URL, this, imageData);
  
  
  
          byte[] inputData=null;
          try {
              Bundle extra = data.getExtras();
              Uri _uri= Uri.parse(extra.get("src_uri").toString());
              InputStream iStream = getActivity().getContentResolver().openInputStream(_uri);
              inputData = getBytes(iStream);
              size = (inputData.length)/(1024*1024);
  
              Log.d("ImageArray", "uri:   " + size);
          } catch (Exception e) {
              e.printStackTrace();
          }
  
          if(size &lt; 3){
  
              imageView.setImageBitmap(avatar);
              Map&lt;String, String&gt; dataMap = new HashMap&lt;&gt;();
              dataMap.put("Email", Utility.sessionEmail(getActivity()));
  
              restClient.multiPartImageUploadRequest(Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID,
                      url, this, dataMap, inputData);
  
          }else {
              imageView.setImageResource(R.drawable.ic_camera);
              Toast.makeText(getActivity(), "Image size shuld not exceed 3 MB", Toast.LENGTH_SHORT).show();
          }
  
      }
  
  
  }
  
  public String getPath(Uri uri) {
      Cursor cursor = getActivity().getContentResolver().query(uri, null, null, null, null);
      cursor.moveToFirst();
      String document_id = cursor.getString(0);
      document_id = document_id.substring(document_id.lastIndexOf(":") + 1);
      cursor.close();
  
  
  
      cursor = getActivity().getContentResolver().query(
              android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
              null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null);
      cursor.moveToFirst();
      String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
      cursor.close();
  
      return path;
  }
  
  public void selectImage(View view) {
  
      Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
  
      intent.setType("image/*");
      intent.setAction(Intent.ACTION_GET_CONTENT);
      startActivityForResult(getCropIntent(intent), Constants.CHOICE_AVATAR_FROM_GALLERY);
  }
  
  
  private Intent getCropIntent(Intent intent) {
  
      intent.putExtra("crop", "true");
      intent.putExtra("aspectX", 1);
      intent.putExtra("aspectY", 1);
      intent.putExtra("outputX", 320);
      intent.putExtra("outputY", 320);
      intent.putExtra("return-data", true);
  
      return intent;
  }
  
  public Bitmap getBitmapFromData(Intent data) {
      Bitmap photo = null;
      Uri photoUri = data.getData();
  
  
      if (photoUri != null) {
          photo = BitmapFactory.decodeFile(photoUri.getPath());
          path = getPath(photoUri);
          uri = photoUri;
          Log.d("URI", "" + photoUri);
      }
      if (photo == null) {
          Bundle extra = data.getExtras();
          if (extra != null) {
              photo = (Bitmap) extra.get("data");
              ByteArrayOutputStream stream = new ByteArrayOutputStream();
              photo.compress(Bitmap.CompressFormat.JPEG, 90, stream);
  
          }
      }
      return photo;
  }
  </code></pre>
  
  <p>This is a method to handle upload <strong>POST</strong> request</p>
  
  <pre><code> public void multiPartImageUploadRequest(int id, String url, ResponseHandler handler, Map&lt;String, String&gt; data, byte[] image){
  
      int request_id = id;
      final ResponseHandler responseHandler = handler;
      final Map&lt;String, String&gt; params = data;
      final byte[] imageData = image;
  
      pDialog = new ProgressDialog(context);
      pDialog.setMessage("Uploading Image...");
      pDialog.show();
  
      VolleyMultipartRequest request = new VolleyMultipartRequest(Request.Method.POST, url,
              new Response.Listener&lt;NetworkResponse&gt;() {
          @Override
          public void onResponse(NetworkResponse response) {
              String resultResponse = new String(response.data);
              responseHandler.success(resultResponse, Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID);
              pDialog.dismiss();
  
          }
      }, new Response.ErrorListener() {
          @Override
          public void onErrorResponse(VolleyError error) {
              responseHandler.failure(error, Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID);
              pDialog.dismiss();
              error.printStackTrace();
          }
      }) {
          @Override
          protected Map&lt;String, String&gt; getParams() {
              return params;
          }
  
          @Override
          protected Map&lt;String, DataPart&gt; getByteData() {
              Map&lt;String, DataPart&gt; ImageParams = new HashMap&lt;&gt;();
              // file name could found file base or direct access from real path
              // for now just get bitmap data from ImageView
              ImageParams.put("", new DataPart("file_avatar.jpg", imageData, "image/jpeg"));
  
              return ImageParams;
          }
      };
      request.setRetryPolicy(new DefaultRetryPolicy(30*1000, 1, 1.0f));
  
      RestController.getInstance().addToRequestQueue(request);
  
  
  
  }
  </code></pre>
  
  <p><strong>VolleyMultipartRequest.java</strong></p>
  
  <pre><code>public class VolleyMultipartRequest extends Request&lt;NetworkResponse&gt; {
  
  
      private final String twoHyphens = "--";
      private final String lineEnd = "\r\n";
      private final String boundary = "apiclient-" + System.currentTimeMillis();
  
      private Response.Listener&lt;NetworkResponse&gt; mListener;
      private Response.ErrorListener mErrorListener;
      private Map&lt;String, String&gt; mHeaders;
  
  
      /**
       * Default constructor with predefined header and post method.
       *
       * @param url           request destination
       * @param headers       predefined custom header
       * @param listener      on success achieved 200 code from request
       * @param errorListener on error http or library timeout
       */
      public VolleyMultipartRequest(String url, Map&lt;String, String&gt; headers,
                                    Response.Listener&lt;NetworkResponse&gt; listener,
                                    Response.ErrorListener errorListener) {
          super(Method.POST, url, errorListener);
          this.mListener = listener;
          this.mErrorListener = errorListener;
          this.mHeaders = headers;
      }
  
      /**
       * Constructor with option method and default header configuration.
       *
       * @param method        method for now accept POST and GET only
       * @param url           request destination
       * @param listener      on success event handler
       * @param errorListener on error event handler
       */
      public VolleyMultipartRequest(int method, String url,
                                    Response.Listener&lt;NetworkResponse&gt; listener,
                                    Response.ErrorListener errorListener) {
          super(method, url, errorListener);
          this.mListener = listener;
          this.mErrorListener = errorListener;
      }
  
      @Override
      public Map&lt;String, String&gt; getHeaders() throws AuthFailureError {
          return (mHeaders != null) ? mHeaders : super.getHeaders();
      }
  
      @Override
      public String getBodyContentType() {
          return "multipart/form-data;boundary=" + boundary;
      }
  
      @Override
      public byte[] getBody() throws AuthFailureError {
          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          DataOutputStream dos = new DataOutputStream(bos);
  
          try {
              // populate text payload
              Map&lt;String, String&gt; params = getParams();
              if (params != null &amp;&amp; params.size() &gt; 0) {
                  textParse(dos, params, getParamsEncoding());
              }
  
              // populate data byte payload
              Map&lt;String, DataPart&gt; data = getByteData();
              if (data != null &amp;&amp; data.size() &gt; 0) {
                  dataParse(dos, data);
              }
  
              // close multipart form data after text and file data
              dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
  
              return bos.toByteArray();
          } catch (IOException e) {
              e.printStackTrace();
          }
          return null;
      }
  
      /**
       * Custom method handle data payload.
       *
       * @return Map data part label with data byte
       * @throws AuthFailureError
       */
      protected Map&lt;String, DataPart&gt; getByteData() throws AuthFailureError {
          return null;
      }
  
      @Override
      protected Response&lt;NetworkResponse&gt; parseNetworkResponse(NetworkResponse response) {
          try {
              return Response.success(
                      response,
                      HttpHeaderParser.parseCacheHeaders(response));
          } catch (Exception e) {
              return Response.error(new ParseError(e));
          }
      }
  
      @Override
      protected void deliverResponse(NetworkResponse response) {
          mListener.onResponse(response);
      }
  
      @Override
      public void deliverError(VolleyError error) {
          mErrorListener.onErrorResponse(error);
      }
  
      /**
       * Parse string map into data output stream by key and value.
       *
       * @param dataOutputStream data output stream handle string parsing
       * @param params           string inputs collection
       * @param encoding         encode the inputs, default UTF-8
       * @throws IOException
       */
      private void textParse(DataOutputStream dataOutputStream, Map&lt;String, String&gt; params, String encoding) throws IOException {
          try {
              for (Map.Entry&lt;String, String&gt; entry : params.entrySet()) {
                  buildTextPart(dataOutputStream, entry.getKey(), entry.getValue());
              }
          } catch (UnsupportedEncodingException uee) {
              throw new RuntimeException("Encoding not supported: " + encoding, uee);
          }
      }
  
      /**
       * Parse data into data output stream.
       *
       * @param dataOutputStream data output stream handle file attachment
       * @param data             loop through data
       * @throws IOException
       */
      private void dataParse(DataOutputStream dataOutputStream, Map&lt;String, DataPart&gt; data) throws IOException {
          for (Map.Entry&lt;String, DataPart&gt; entry : data.entrySet()) {
              buildDataPart(dataOutputStream, entry.getValue(), entry.getKey());
          }
      }
  
      /**
       * Write string data into header and data output stream.
       *
       * @param dataOutputStream data output stream handle string parsing
       * @param parameterName    name of input
       * @param parameterValue   value of input
       * @throws IOException
       */
      private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
          dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
          dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd);
          //dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
          dataOutputStream.writeBytes(lineEnd);
          dataOutputStream.writeBytes(parameterValue + lineEnd);
      }
  
      /**
       * Write data file into header and data output stream.
       *
       * @param dataOutputStream data output stream handle data parsing
       * @param dataFile         data byte as DataPart from collection
       * @param inputName        name of data input
       * @throws IOException
       */
      private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException {
          dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
          dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" +
                  inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd);
          if (dataFile.getType() != null &amp;&amp; !dataFile.getType().trim().isEmpty()) {
              dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd);
              Log.d("Name", inputName + "      " + dataFile.getFileName());
          }
          dataOutputStream.writeBytes(lineEnd);
  
          ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent());
          int bytesAvailable = fileInputStream.available();
  
          int maxBufferSize = 1024 * 1024;
          int bufferSize = Math.min(bytesAvailable, maxBufferSize);
          byte[] buffer = new byte[bufferSize];
  
          int bytesRead = fileInputStream.read(buffer, 0, bufferSize);
  
          while (bytesRead &gt; 0) {
              dataOutputStream.write(buffer, 0, bufferSize);
              bytesAvailable = fileInputStream.available();
              bufferSize = Math.min(bytesAvailable, maxBufferSize);
              bytesRead = fileInputStream.read(buffer, 0, bufferSize);
          }
  
          dataOutputStream.writeBytes(lineEnd);
      }
  
      /**
       * Simple data container use for passing byte file
       */
      public class DataPart {
          private String fileName;
          private byte[] content;
          private String type;
  
          /**
           * Default data part
           */
          public DataPart() {
          }
  
          /**
           * Constructor with data.
           *
           * @param name label of data
           * @param data byte data
           */
          public DataPart(String name, byte[] data) {
              fileName = name;
              content = data;
          }
  
          /**
           * Constructor with mime data type.
           *
           * @param name     label of data
           * @param data     byte data
           * @param mimeType mime data like "image/jpeg"
           */
          public DataPart(String name, byte[] data, String mimeType) {
              fileName = name;
              content = data;
              type = mimeType;
          }
  
          /**
           * Getter file name.
           *
           * @return file name
           */
          public String getFileName() {
              return fileName;
          }
  
          /**
           * Setter file name.
           *
           * @param fileName string file name
           */
          public void setFileName(String fileName) {
              this.fileName = fileName;
          }
  
          /**
           * Getter content.
           *
           * @return byte file data
           */
          public byte[] getContent() {
              return content;
          }
  
          /**
           * Setter content.
           *
           * @param content byte file data
           */
          public void setContent(byte[] content) {
              this.content = content;
          }
  
          /**
           * Getter mime type.
           *
           * @return mime type
           */
          public String getType() {
              return type;
          }
  
          /**
           * Setter mime type.
           *
           * @param type mime type
           */
          public void setType(String type) {
              this.type = type;
          }
      }
  }
  </code></pre>