On Tue, 2022-05-10 at 18:13 -0400, Skylos wrote:
> 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.
>
>
As of version 5.0 HttpClient no longer uses the old `plus as blank`
encoding scheme.
Project code repositories can be found at the GitHub
https://github.com/apache/httpcomponents-core
https://github.com/apache/httpcomponents-client
Oleg
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]