Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Problem/Motivation
There is/was a check in FileWidgetAjaxController
which protected against broken POST requests.
This could happen in case file uploads are too big so that the POST request body gets truncated
$form_parents = explode('/', $request->query->get('element_parents'));
$form_build_id = $request->query->get('form_build_id');
$request_form_build_id = $request->request->get('form_build_id');
if (empty($request_form_build_id) || $form_build_id !== $request_form_build_id) {
// Invalid request.
drupal_set_message(t('An unrecoverable error occurred. The uploaded file likely exceeded the maximum file size (@size) that this server supports.', array('@size' => format_size(file_upload_max_size()))), 'error');
$response = new AjaxResponse();
$status_messages = array('#type' => 'status_messages');
return $response->addCommand(new ReplaceCommand(NULL, $this->renderer->renderRoot($status_messages)));
}
Proposed resolution
Ensure that the form build ID is rendered as early as possible.
Possible ways:
- Ensure that its documentation that we want to render it first
- Decrease the weight of the $form['form_build_id'] element as much as possible
- Render it early in the template, and document that templates should render it first
Remaining tasks
User interface changes
API changes
Comment | File | Size | Author |
---|---|---|---|
#3 | 2507019-2.patch | 1.04 KB | effulgentsia |
#1 | 2507019-1.patch | 1.24 KB | effulgentsia |
Comments
Comment #1
effulgentsia CreditAttribution: effulgentsia at Acquia commentedFirstly, curious if there's any test coverage for it. If not, this will pass, which I suspect is the case.
Comment #2
effulgentsia CreditAttribution: effulgentsia at Acquia commentedSecondly, I manually tested (on PHP 5.5 on MAMP) uploading a file that's bigger than php.ini's
post_max_size
. Regardless of whetherupload_max_filesize
is bigger, equal, or smaller thanpost_max_size
, the behavior is the same, which is that all of $_POST is empty, regardless of whether the other elements are before or after the file element. That is consistent with PHP's documented behavior.So, retitling this issue, since it's not necessarily a settled conclusion that the order of the element matters.
However, I did not test situations of a request body truncated prior to PHP, such as from an aborted connected from the client or something like suhosin on the server. It's possible that order matters in such a case, in which case, we need to decide whether we want the element coming through successfully (by ordering it before the file element) or not (by ordering it after). Or maybe, we want 'form_build_id' early in the form and some other element (e.g., 'form_truncation_check') late in the form. Before going down that road of messing with order through, let's see if PHP takes care of things for us, by e.g., automatically detecting if the request body length is less than the Content-Length header and giving us an empty $_POST for us (wouldn't that be nice).
If the only purpose of checking $form_build_id is to cover the case of an empty $_POST due to a file larger than post_max_size, then it's unnecessary to compare it against the one from the query string. This patch should provide the same protection, but allow removal of the query string one, which is necessary for #2500527: Rewrite \Drupal\file\Controller\FileWidgetAjaxController::upload() to not rely on form cache.
Comment #3
effulgentsia CreditAttribution: effulgentsia at Acquia commentedPatch for #2.
Comment #4
effulgentsia CreditAttribution: effulgentsia at Acquia commentedAlso, the current protection being only in FileWidgetAjaxController is problematic due to:
Comment #5
dawehnerIf I understood your previous comments is that the point is to protected against the case
where your uploaded file has nearly post_max_size / so there is no not enough bytes left for the full other rest of the form data ...
Comment #6
effulgentsia CreditAttribution: effulgentsia at Acquia commentedNo, I think even there PHP will empty out all of $_POST. The only thing I'm unsure of is what happens when it's not PHP that applies post_max_size, but something prior to PHP truncating the request body. Then the request body length will be less than the 'Content-Length' header, but I don't know if PHP gives you an empty $_POST for that, or ignores the header and parses the incomplete body anyway. If the latter, then we may need a hidden input element at the end of the form to detect that.
Comment #7
catchAdding related issue. A long time since I've looked at that one, but that also results in silent truncation (or did at the time that issue was active).
Comment #8
dawehnerDid a little bit of manual research. I copied the file upload request to CURL and manipulated sent POST data.
Given that Content-Length is optional and in case is just used to determine how much bytes of the request is read.
Comment #9
Damien Tournoud CreditAttribution: Damien Tournoud at Centarro commentedThere seem to be a lot of misunderstandings here. An HTTP server really should not process an incomplete HTTP message. If something in the chains allows an incomplete HTTP message to be processed, it is a bug in that something.
Can we understand what is happening and identify which infrastructure that are affected? Do we have a setup somewhere that is affected?
Comment #10
Damien Tournoud CreditAttribution: Damien Tournoud at Centarro commentedFor information,
RFC7230
defines an incomplete message as:Comment #11
Damien Tournoud CreditAttribution: Damien Tournoud at Centarro commentedAbout @dawehner#8:
^ This is not possible. You cannot submit an HTTP message body without either a
Content-Length
or using a chunked transfer encoding (which carries the length information by itself).^ This is not possible, or it means that you are actually using chunked transfer encoding without knowing it. If you were not using chunked transfer encoding, the request would just block until there is sufficient data.
^ That is expected.
Comment #18
jhedstromThis has gone a long time without comment, and there is much discussion about the direction since the last posted patch.
Comment #25
smustgrave CreditAttribution: smustgrave at Mobomo commented