/**
  * Decodes form parameters that are sent double encoded by performing one decode step on their
  * values, if their restlet framework decoded value starts with an "%".
  *
  * @param request a restlet request
  * @throws IOException did not occur during tests but may.
  * @throws IllegalArgumentException if an Encode representation is received.
  */
 void decodeFormParamsIfDoubleEncoded(Request request) throws IOException {
   Representation r = request.getEntity();
   if (r instanceof EncodeRepresentation)
     throw new IllegalArgumentException(
         "Received an Encode representation."
             + " This filter must be after the Encoder filter. please check your filter chain order.");
   if (!(r instanceof EmptyRepresentation)) {
     ContentType c = new ContentType(r);
     if (MediaType.APPLICATION_WWW_FORM.equals(c.getMediaType(), true)) {
       Form form = new Form(r);
       Form newform = new Form(r);
       Map<String, String> valuesMap = form.getValuesMap();
       for (Map.Entry<String, String> e : valuesMap.entrySet()) {
         if (DBG) ThreadLocalStopwatch.now("" + e.getKey() + " - " + e.getValue());
         String shouldBeDecodedValue = e.getValue();
         if (shouldBeDecodedValue.startsWith("%")) {
           shouldBeDecodedValue = URLDecoder.decode(e.getValue(), DECODER_CHAR_SET);
           totalDecodings.incrementAndGet();
           if (DBG) {
             ThreadLocalStopwatch.now("DECODED " + request.getResourceRef());
             ThreadLocalStopwatch.now(
                 "DECODED "
                     + totalDecodings.get()
                     + " : "
                     + e.getKey()
                     + " - "
                     + shouldBeDecodedValue);
           }
         }
         newform.add(e.getKey(), shouldBeDecodedValue);
       }
       // we must always set the entity, because above getEntitiy call causes
       // NPEs later if repeated by the framework.
       request.setEntity(newform.encode(), c.getMediaType());
     }
   }
 }
  @Override
  public void write(OutputStream outputStream) throws IOException {
    if (isMultipart()) {
      for (FormData data : getEntries()) {
        // Write the boundary line
        outputStream.write(("--" + getMultipartBoundary()).getBytes());
        HeaderUtils.writeCRLF(outputStream);

        // Write the optional content type header line
        if (MediaType.TEXT_PLAIN.equals(data.getMediaType())) {
          // Write the content disposition header line
          String line = "Content-Disposition: form-data; name=\"" + data.getName() + "\"";
          outputStream.write(line.getBytes());
          HeaderUtils.writeCRLF(outputStream);
        } else {
          // Write the content disposition header line
          String line =
              "Content-Disposition: form-data; name=\""
                  + data.getName()
                  + "\"; filename=\""
                  + data.getFilename()
                  + "\"";
          outputStream.write(line.getBytes());
          HeaderUtils.writeCRLF(outputStream);

          // Write the content type header line
          line = "Content-Type: " + ContentType.writeHeader(data.getValueRepresentation());
          outputStream.write(line.getBytes());
          HeaderUtils.writeCRLF(outputStream);
        }

        // Write the data content
        HeaderUtils.writeCRLF(outputStream);
        data.getValueRepresentation().write(outputStream);
        HeaderUtils.writeCRLF(outputStream);
      }

      // Write the final boundary line
      outputStream.write(("--" + getMultipartBoundary() + "--").getBytes());
      HeaderUtils.writeCRLF(outputStream);
    } else {
      Representation formRep =
          new StringRepresentation(
              getQueryString(), MediaType.APPLICATION_WWW_FORM, null, CharacterSet.UTF_8);
      formRep.write(outputStream);
    }
  }