1

After apache update, my server started dropping this error in URL queries, containing spaces:

AH10411: Rewritten query string contains control characters or spaces

URL looks as follows:

www.example.com/modulename/searchfuncname/filter,searchstring,quick fox jumps/

.htaccess as follows:

<IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.+)$ index.php?QueryString=%{REQUEST_URI} [B,L]
</IfModule>

I tried adding B flag, removing B flag, adding BNP flag and combinations of both or none.

Nothing helped. With any URL provided, server drops the very same error.

When I try to manually replace spaces with %20: www.example.com/modulename/searchfuncname/filter,searchstring,quick%20fox%20jumps/ server replaces them back, gives 403 responce and drops AH10411 error.

But for some reason, if I replace space with + sign, server works. Disregarding BPN flag.

I tried all the variants, described in this thread: AH10411 error: Managing spaces and %20 in apache mod_rewrite none worked.

MrWhite
  • 43,179
  • 8
  • 60
  • 84

2 Answers2

1
RewriteRule ^(.+)$ index.php?QueryString=%{REQUEST_URI} [B,L]

The B flag doesn't work here because you are not using a backreference (you are using the REQUEST_URI server variable instead). Try the following instead:

RewriteRule ^(.+)$ index.php?QueryString=/$1 [B,L]

When I try to manually replace spaces with "%20": /modulename/searchfuncname/filter,searchstring,quick%20fox%20jumps/ server replaces them back

This would make no difference, because this is identical to the first request. If you don't explicitly URL-encode the spaces in the initial request, the browser does this for you (when it makes the request) - in order to make a valid URL. (Look at the network traffic in the browser - you will see %20 regardless of whether you have manually encoded the space or not).

But yes, the RewriteRule pattern matches the URL-decoded URL-path anyway.

But for some reason, if I replace space with "+" sign, server works. Disregarding BPN flag.

%20 is a URL-encoded space, regardless of where it is used in the URL. However, a + in the URL-path is a literal + (plus). But, a + in the query string is a URL-encoded space (alternative encoding). So, yes, if you used + in the URL-path of the original request then it "bypasses" this problem. The BNP flag does not apply, since it is not encoding a space, it is simply copying a literal +.


UPDATE: Limit what is encoded

$_GET now doesn't break into array if URL is provided with addditional parameters like /fox/&tail=red

Probably because the & is being URL-encoded in the resulting query string. You can limit the encoding to spaces and ? only (requires Apache 2.4.26+). For example:

RewriteRule ^(.+)$ index.php?QueryString=/$1 "[B= ?,L]"

& will no longer be encoded in the backreference, so its special meaning in the query string will still apply.

NB: You can't encode only spaces (since spaces can't be used as the last character), hence the additional ? character. Consequently, the flags argument needs to be surrounded in double quotes.

MrWhite
  • 43,179
  • 8
  • 60
  • 84
  • this solution helps. kinda. unfortunately it also breaks the other functions. $_GET now doesn't break into array if URL is provided with addditional parameters like /fox/&tail=red – Yaroslav Ustinovsky Apr 04 '23 at 11:44
  • @YaroslavUstinovsky You can limit the encoding to prevent `&` being URL-encoded in the resulting query string. I've updated my answer. – MrWhite Apr 04 '23 at 12:13
  • 1
    Thanks! "[B= ?,L]" this last part did the trick. Thank you very much! – Yaroslav Ustinovsky Apr 04 '23 at 12:53
0

I had the same and due to circumstances I found the easy way:

#
# php-fpm can use .user.ini instead of .htaccess
#
<Files ".user.ini">
    Require all denied
</Files>
<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteOptions AllowAnyURI
    #
    # Authorization header for JWT backend
    #
    SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0

    #
    # Don't rewrite if dir/link/file exists
    #
    RewriteCond %{REQUEST_FILENAME} -f [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule .* - [L]

    #
    # Handle in route class...
    #
    RewriteCond %{HTTPS} off
    RewriteRule .* - [E=REQUEST_SCHEME:http]

    RewriteCond %{HTTPS} on
    RewriteRule .* - [E=REQUEST_SCHEME:https]

    RewriteRule ^/?(.*)$ /index.php?request=- [L,QSA]
</IfModule>

basically it is this setting: RewriteOptions AllowAnyURI