Problem

If you upload an image trough the WYSIWYG editor (CK) the image you uploaded is inserted in the HTML with the absolute path (including protocol and domain).

This can be an issue:

  • If you have a setup where 2 domains point to the same instance (e.g. drupal.be & drupal.fr).
  • And you upload an image trough CK editor on the drupal.be website.
  • You use the Basic HTML profile with the "Restrict images to this site" filter enabled.
  • The image will be inserted in the html as <img src="http://drupal.be/path/to/the/image.png" />
  • After saving the node the node will be rendered, the "Restrict images to this site" filter will validate the domain of the URL, approve it and alter the src to a relative path.
  • This works as expected

But what if:

  • The cache gets cleared.
  • And a user accesses the node as first through the drupal.fr domain.
  • The HTML of the node is send trough the "Restrict images to this site" filter.
  • The domain of the image src in the HTML does not match the domain the code is filtered in.
  • The src of the image is replaced by the insecure message
  • This is not expected behaviour!

In fact, since the rendered node is cached, it will be shown as insecure image on both domains!

Proposed resolution

During file upload the image should be inserted with a relative src.

Change the submit submitForm() method in the \Drupal\editor\Form\EditorImageDialog class:

Remove the Domain (and port) from the rendered URL:

$form_state['values']['attributes']['src'] = file_create_url($file->getFileUri());
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

zero2one’s picture

Status: Active » Needs review
FileSize
1.05 KB

Hereby the patch that fixes the issue:

  • It removes the domain (and optional port number) from the image src URL before the image is inserted into the HTML.
zero2one’s picture

I improved the patch: it did not support websites running on a specific port number.

It's a ugly fix, there should be a core function that removes the domain (and optional port) from an URL.

See also https://drupal.org/node/2076847

zero2one’s picture

Improved the code more: the replace pattern replaces now the domain and an optional port.

Wim Leers’s picture

#2076847: FilterHtmlImageSecure incorrectly flags images coming from site URLs with ports in them as insecure got committed in the mean time — yay :)


Changes:

Wim Leers’s picture

Issue summary: View changes

Updated issue summary.

Gábor Hojtsy’s picture

Issue summary: View changes

Would it make sense to have a function for this since its the same logic as in filter module?

Wim Leers’s picture

#5: That might make sense, yes. What about file_transform_url_relative()? Hopefully you can think of something better.

Gábor Hojtsy’s picture

I don't think this would be in file module would it. That name sounds confusing for that. It would be in filter module, no?

Wim Leers’s picture

#7: But wouldn't it be a lot stranger to put file handling functionality in filter.module? Despite filter.module being the only one in need of this functionality in core, I can imagine contrib modules wanting to use this too. And it's clearly within the responsibilities of the file system, in my opinion.

Gábor Hojtsy’s picture

Yeah I don't feel strongly about it, but it looks to me like its filtering the URL for better display, may also apply to non-file module handled files (eg. theme). Anyway, its fine either way, there is no really clear place for it to go IMHO.

Wim Leers’s picture

So instead of duplicating the same URL manipulation in another location in Drupal core, this issue now proposes a minor API addition. Test coverage added.

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me :)

Wim Leers’s picture

Issue tags: +Spark, +CKEditor in core, +sprint

Status: Reviewed & tested by the community » Needs work

The last submitted patch, 10: editor_image_upload_relative_path-2099205-10.patch, failed testing.

Wim Leers’s picture

Status: Needs work » Needs review
FileSize
6.14 KB
1.13 KB

I can't reproduce this locally, so adding debug output to figure out why testbot is failing.

Status: Needs review » Needs work
Wim Leers’s picture

Status: Needs work » Needs review
FileSize
497 bytes
497 bytes

Adding even more debug output.

Status: Needs review » Needs work
Wim Leers’s picture

Status: Needs work » Needs review
FileSize
6.18 KB

Sigh… I accidentally created an interdiff instead of a patch. Let's try again.

Status: Needs review » Needs work
Wim Leers’s picture

Status: Needs work » Needs review
FileSize
6.18 KB
671 bytes

Okay so the reason testbot is failing is that getHttpHost() returns 'drupaltestbot1838:'. That is in fact… a value that contradicts the contract of the function. WTF.

    /**
     * Returns the HTTP host being requested.
     *
     * The port name will be appended to the host if it's non-standard.
     *
     * @return string
     *
     * @api
     */
    public function getHttpHost()
    {
        $scheme = $this->getScheme();
        $port   = $this->getPort();

        if (('http' == $scheme && $port == 80) || ('https' == $scheme && $port == 443)) {
            return $this->getHost();
        }

        return $this->getHost().':'.$port;
    }

How is this possible? The protocol must be 'http' and the port must be 80.

Adding two more debug() statements, to output the scheme and port.

Status: Needs review » Needs work
Wim Leers’s picture

Status: Needs work » Needs review
FileSize
6.35 KB

Sigh, for some reason that patch was in fact the #18 patch. The interdiff was correct though. This was the intended patch…

Status: Needs review » Needs work
Wim Leers’s picture

Assigned: zero2one » Wim Leers
Status: Needs work » Needs review
FileSize
6.52 KB
2.37 KB

So apparently on testbot, Request::getPort() === NULL… hence the test failures!

Hence the only thing I can do is work around that problem. Which is easy enough, but comes with a bit more code than the original.

Gábor Hojtsy’s picture

Status: Needs review » Reviewed & tested by the community

Still looks good, testbot specialties aside :)

webchick’s picture

Status: Reviewed & tested by the community » Fixed
Issue tags: +Needs followup

Committed and pushed to 8.x, but let's get an upstream issue filed about getPort() because that is wacktastical.

Wim Leers’s picture

Issue tags: -sprint, -Needs followup

Alright, upstream issue filed: https://github.com/symfony/symfony/issues/9604

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

Wim Leers’s picture

Note this had some consequences for retrieving entities via REST too: #2630076: Inline images: how to calculate the absolute file URL.