I'm communicating with an out of spec server which does not recognize "+"
as a blank space in query strings - this was quite a problem as I am
passing actual filenames which I don't control and which may have spaces in
them!

The workaround I built was to copy format (and everything it calls) from
URLEncodedUtils and augment to pass down the blankAsPlus value, which I
then call explicitly by bypassing the built in encoder by sending in a raw
encoded querystring as part of the original url string I use for my client
retrieve/execution.

It turns out that this function:

private static String encodeFormFields (final String content, final Charset
charset);

needs to have a 'false' as the ultimate argument in the call to this
function:

private static String urlEncode(
final String content,
final Charset charset,
final BitSet safechars,
final boolean blankAsPlus);

There was apparently no consideration that this might be necessary outside
this private context. It's okay. I totally understand. I also understand
that you may not like the idea of being compatible with obviously out of
spec servers. But - it is my philosophical assertion that as a library
which may be used by many divers purposes, it is better to allow the user
to do whatever he wants, rather than to be quite so opinionated about it as
to make it impossible to bypass the blankAsPlus while encoding

My humble suggestion as thus - allow injection of blankAsPlus boolean
external to the class.  (I didn't chase *all* the format dependencies, but
would be easy enough to do with a refactor calc or simply add a
compatibility signature)

(this one is in UrlEncodedFormEntity.java - conform with api change and
compatibility constructor?  defer to you.)

-   public UrlEncodedFormEntity (
-       final Iterable <? extends NameValuePair> parameters,
-       final Charset charset) {
-       super(URLEncodedUtils.format(parameters,
-               charset != null ? charset : HTTP.DEF_CONTENT_CHARSET),
-               ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset));
-   }
+   public UrlEncodedFormEntity (
+       final Iterable <? extends NameValuePair> parameters,
+       final Charset charset) {
+       super(URLEncodedUtils.format(parameters,
+               charset != null ? charset : HTTP.DEF_CONTENT_CHARSET),
+               ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset),
+               false);
+   }
+   public UrlEncodedFormEntity (
+       final Iterable <? extends NameValuePair> parameters,
+       final Charset charset,
+       boolean blankAsPlus) {
+       super(URLEncodedUtils.format(parameters,
+               charset != null ? charset : HTTP.DEF_CONTENT_CHARSET),
+               ContentType.create(URLEncodedUtils.CONTENT_TYPE, charset),
+               blankAsPlus);
+   }


(this one is in URIBuilder.java - conform to api change - consider also
adding mode/flag in builder to turn this on/off? (I really like this idea))

     public static String encodeUrlForm(final List<NameValuePair> params) {
-        return format(params, Consts.UTF_8);
+        return format(params, Consts.UTF_8, false);
     }

(These are all in URLEncodedUtils.java - pass the value down in and default
on the public level with the old api.)

-    public static String format(
-          final Iterable<? extends NameValuePair> parameters,
-          final Charset charset) {
-        return format(parameters, '&', charset);
+    public static String format(
+          final Iterable<? extends NameValuePair> parameters,
+          final Charset charset) {
+        return format(parameters, '&', charset, false);
+    }
+    public static String format(
+          final Iterable<? extends NameValuePair> parameters,
+          final Charset charset,
+          boolean blankAsPlus) {
+        return format(parameters, '&', charset, blankAsPlus);
     }

-    public static String format(
-          final Iterable<? extends NameValuePair> parameters,
-          final char parameterSeparator,
-          final Charset charset) {
+    public static String format(
+          final Iterable<? extends NameValuePair> parameters,
+          final char parameterSeparator,
+          final Charset charset,
+          boolean blankAsPlus) {
         Args.notNull(parameters, "Parameters");
         final StringBuilder result = new StringBuilder();
         for (final NameValuePair parameter : parameters) {
-            final String encodedName =
encodeFormFields(parameter.getName(), charset);
-            final String encodedValue =
encodeFormFields(parameter.getValue(), charset);
+            final String encodedName =
encodeFormFields(parameter.getName(), charset, blankAsPlus);
+            final String encodedValue =
encodeFormFields(parameter.getValue(), charset, blankAsPlus);
             if (result.length() > 0) {
                 result.append(parameterSeparator);
             }

(And finally encodeFormFields itself.)

-    private static String encodeFormFields (final String content, final
Charset charset) {
+    private static String encodeFormFields(final String content, final
Charset charset, boolean blankAsPlus) {
         if (content == null) {
             return null;
         }
-        return urlEncode(content, charset != null ? charset :
Consts.UTF_8, wwwFormUrlSafe(), false);
+        return urlEncode(content, charset != null ? charset :
Consts.UTF_8, wwwFormUrlSafe(), blankAsPlus);
     }

If you'd like me to submit a pull request on this, point me to the code
repo you're using and I'll be happy to generate one.


-- 
Dog approved this message.

Reply via email to