I'm trying to only allow incoming requests to /multi if the Content-Type request header starts with multipart/form-data, while requests to other POST, PUT, or DELETE endpoints must always have the application/json Content-Type.
When doing the following in my web roots .htaccess file (no root access):
# Enforce multipart/form-data content type for /multi routes
RewriteCond %{REQUEST_URI} ^/multi [NC]
RewriteCond %{HTTP:Content-Type} !^multipart/form-data; [NC]
RewriteRule ^ - [R=400,L,END]
Enforce JSON content type for all other POST, PUT, and DELETE endpoints
RewriteCond %{REQUEST_METHOD} ^(POST|PUT|DELETE)$
RewriteCond %{HTTP:Content-Type} !^application/json [NC]
RewriteCond %{REQUEST_URI} !^/multi [NC]
RewriteRule ^ - [R=400,L,END]
... and then sending a POST /multi with Content-Type: multipart/form-data, I get Apache's 400 Bad Request Response. When I remove the second rewrite block, the request gets through. Why is the second rewrite block applied when sending a POST /multi with Content-Type: multipart/form-data, although I have the RewriteCond %{REQUEST_URI} !^/multi [NC] condition in it, which should prevent it from being applied?
When I check the apache error logs while sending the request with the second rewrite block enabled, I have no error log at all. When I check the Apache Dom Log, I simply have that an incoming request to /multi yielded the 400 response. So it indeed seems to be to the fact that the second rewrite rule is applied, which makes no sense to me.
Full .htaccess File
# Prevent files whose name starts with ".ht" from frontend access
<FilesMatch "^\.ht">
Require all denied
</FilesMatch>
Set global Rules for document root directory
Options Indexes FollowSymLinks
Require all granted
Specify rewrite rules
RewriteEngine On
Authorization Header seems to be stripped by default, hence explicitly enable it
Doing it via the rewrite rule is not the native way of doing it, and would need an improved rule to avoid that an
Authorization HTTP header with an empty value is still passed to PHP
RewriteCond %{HTTP:Authorization} ^(.*)
RewriteRule .* - [e=HTTP_AUTHORIZATION:%1]
CGIPassAuth On
Enforce multipart/form-data content type for /multi route
RewriteCond %{REQUEST_URI} ^/multi [NC]
RewriteCond %{HTTP:Content-Type} !^multipart/form-data; [NC]
RewriteRule ^ - [R=400,L,END]
Enforce JSON content type for all other POST, PUT, and DELETE endpoints (return a 400 Bad Request otherwise)
RewriteCond %{REQUEST_METHOD} ^(POST|PUT|DELETE)$
RewriteCond %{HTTP:Content-Type} !^application/json [NC]
RewriteCond %{REQUEST_URI} !^/multi [NC]
RewriteRule ^ - [R=400,L,END]
Route all incoming requests through index.php, except if it's for existing files
RewriteBase /
RewriteRule ^index.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . /index.php [L]
Ensure that png images, javascript and css files are all delivered with correct mime type. mod_mime must be enabled.
AddType application/javascript .js
AddType image/png .png
AddType text/css .css
Add an 'Expires' HTTP header for all accessed js, css and png image files. mod_expires must be enabled.
ExpiresActive On
ExpiresByType image/png "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType text/css "access plus 1 year"
Also add a Cache-Control HTTP header for the same cache lifetime of 1 year, to cover all browsers. mod_headers needed.
<FilesMatch ".(js|css|png)$">
Header set Cache-Control "public, max-age=31536000"
</FilesMatch>
Define Image Uploads directory, to be able to access img uploads while uploads are kept outside from document root
RewriteRule ^images/(.*)$ /uploads/imgs/$1 [L]
Ensure that all icons are delivered with the image/jpeg MIME type
RewriteRule ^icons/ - [E=CONTENT_TYPE:image/png]