simonk
(Simon King)
October 28, 2024, 11:49am
4
Are you using a CDN on either of these sites? I have noticed that code highlighting is no longer working on my site, and I think it’s because of this:
The change which made this noticeable was most likely DEV: Modernise highlightjs loading (#24197) · discourse/discourse@0878dde · GitHub , which switched highlightjs to load via native import(), which requires CORS headers when fetching from a CDN.
But even before that change, you likely would have had some issues with things like custom Fonts (which also require CORS headers for cross-origin requests).
In theory, Discourse itself should be adding the CORS header to CDN responses. If it’s not, …
In my case, my CDN is not returning an Access-Control-Allow-Origin
header for the highlightjs file. I notice that Meta’s CDN does include that header, so I wonder what is different.
$ curl --silent -I https://d3bpeqsaub0i6y.cloudfront.net/highlight-js/meta.discourse.org/9797975efac87d28baa695ae13ca72ccaf5120f5.js | grep -i access-control
access-control-allow-origin: *
access-control-allow-methods: GET, HEAD, OPTIONS
However, those headers are not being served by the origin server:
$ curl --silent -I https://meta.discourse.org/highlight-js/meta.discourse.org/9797975efac87d28baa695ae13ca72ccaf5120f5.js | grep -i access-control
<no output>
As far as I can tell, Discourse is meant to add access-control headers to the highlightjs files:
# frozen_string_literal: true
class HighlightJsController < ApplicationController
skip_before_action :preload_json,
:redirect_to_login_if_required,
:redirect_to_profile_if_required,
:check_xhr,
:verify_authenticity_token,
only: [:show]
before_action :apply_cdn_headers, only: [:show]
def show
no_cookies
RailsMultisite::ConnectionManagement.with_hostname(params[:hostname]) do
current_version = HighlightJs.version(SiteSetting.highlighted_languages)
return redirect_to path(HighlightJs.path) if current_version != params[:version]
# note, this can be slightly optimised by caching the bundled file, it cuts down on N reads
However , those headers are only applied if the request is a “CDN request”:
return unless mini_profiler_enabled?
Rack::MiniProfiler.authorize_request
end
def check_xhr
# bypass xhr check on PUT / POST / DELETE provided api key is there, otherwise calling api is annoying
return if !request.get? && (is_api? || is_user_api?)
raise ApplicationController::RenderEmpty.new if !request.format&.json? && !request.xhr?
end
def apply_cdn_headers
if Discourse.is_cdn_request?(request.env, request.method)
Discourse.apply_cdn_headers(response.headers)
end
end
def self.requires_login(arg = {})
@requires_login_arg = arg
end
def self.requires_login_arg
end
mattr_accessor :redis
def self.is_parallel_test?
ENV["RAILS_ENV"] == "test" && ENV["TEST_ENV_NUMBER"]
end
CDN_REQUEST_METHODS ||= %w[GET HEAD OPTIONS]
def self.is_cdn_request?(env, request_method)
return if CDN_REQUEST_METHODS.exclude?(request_method)
cdn_hostnames = GlobalSetting.cdn_hostnames
return if cdn_hostnames.blank?
requested_hostname = env[REQUESTED_HOSTNAME] || env[Rack::HTTP_HOST]
cdn_hostnames.include?(requested_hostname)
end
def self.apply_cdn_headers(headers)
This only works if Discourse is configured with a separate host name for “CDN requests”.
1 Like