public function apiUploadFile(HTTPRequest $request)
    {
        $data = $request->postVars();

        // When updating files, replace on conflict
        $upload = $this->getUpload();
        $upload->setReplaceFile(true);

        // CSRF check
        $token = SecurityToken::inst();
        if (empty($data[$token->getName()]) || !$token->check($data[$token->getName()])) {
            $this->jsonError(400);
            return null;
        }
        $tmpFile = $data['Upload'];
        if (empty($data['ID']) || empty($tmpFile['name']) || !array_key_exists('Name', $data)) {
            $this->jsonError(400, _t(__CLASS__.'.INVALID_REQUEST', 'Invalid request'));
            return null;
        }

        // Check parent record
        /** @var File $file */
        $file = File::get()->byID($data['ID']);
        if (!$file) {
            $this->jsonError(404, _t(__CLASS__.'.FILE_NOT_FOUND', 'File not found'));
            return null;
        }
        $folder = $file->ParentID ? $file->Parent()->getFilename() : '/';

        // If extension is the same, attempt to re-use existing name
        if (File::get_file_extension($tmpFile['name']) === File::get_file_extension($data['Name'])) {
            $tmpFile['name'] = $data['Name'];
        } else {
            // If we are allowing this upload to rename the underlying record,
            // do a uniqueness check.
            $renamer = $this->getNameGenerator($tmpFile['name']);
            foreach ($renamer as $name) {
                $filename = File::join_paths($folder, $name);
                if (!File::find($filename)) {
                    $tmpFile['name'] = $name;
                    break;
                }
            }
        }

        if (!$upload->validate($tmpFile)) {
            $errors = $upload->getErrors();
            $message = array_shift($errors);
            $this->jsonError(400, $message);
            return null;
        }

        try {
            $tuple = $upload->load($tmpFile, $folder);
        } catch (Exception $e) {
            $this->jsonError(400, $e->getMessage());
            return null;
        }

        if ($upload->isError()) {
            $errors = implode(' ' . PHP_EOL, $upload->getErrors());
            $this->jsonError(400, $errors);
            return null;
        }

        $tuple['Name'] = basename($tuple['Filename']);
        return (new HTTPResponse(json_encode($tuple)))
            ->addHeader('Content-Type', 'application/json');
    }