CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: publishing

Just because I can should I use Private Office 365 CDN

This is about a topic brought up by Waldek Mastykarz: Just because you can should you use the Office 365 CDN. In my post I want to take a closer look at the private CDN option in Office 365. Please note, the whole thing is subject to change, and it reflects the circumstances at the time of writing – 2019-08-26.

I’ll skip the introduction of Office 365, let’s jump directly to the Private CDN option. Consider following scenarios.

I am developing SPFx solutions, is the Private Office 365 CDN something for me?

No, you can’t use private CDN for SPFx, because SPFx cannot handle changing Urls from a Private CDN.

I use Modern Team Sites and Communication Sites. Is the Private Office 365 CDN something for me?

No, the urls are changing. You cannot “hardcode” them. Automatic URL Rewrite works only on classic Publishing Sites.

I have Provider Hosted Add-Ins. Is the Private Office 365 CDN something for me?

No, the referrer needs to be a subdomain of


The whole point of having a private CDN is that it is not available for strangers. But when you enable it, you’ll see an eligible warning:

WARNING: This is a feature built on a 3rd party application with privacy and compliance standards that differ from the commitments outlined by the Microsoft Office365 Trust Center. Any data cached through this
service does not conform to the Microsoft Data Processing Terms (DPT) and is outside of the Microsoft Office365 Trust Center compliance boundaries.

The risk might be low, but if an attacker gets a url that looks like this: then it is just a matter of downloading within 30-90 minutes. That’s how long those tokens in the URL are valid.

Adding Referer: <subdomain> as a Request Header is needed to download a resource.

If you remove an asset from the private cdn origins, it takes up to 15 minutes for the link to be invalidated. Opposed to an immediate effect for a direct link to an asset in a document library.

To keep it more secure, the default private cdn origins should not be included, especially */SITEASSETS, Because site assets can have important information, and this makes every single site assets library vulnerable, asterisk means all.

Even the CDN Policies should be restrictive.

Overall, if the usage area is small, the performance gain is little, we should not enable it at all. Because: any cached data in a private Office 365 CDN is outside of the Microsoft Office365 Trust Center compliance boundaries.


I have tried the private CDN. My setup was a document library with three versions of a picture that was 2,4MB that I put to three different libraries:

  • privatecdnorigin/africa_private.jpg
  • publiccdnorigin/africa_public.jpg
  • nocdnorigin/africa_nocdn.jpg

On the publishing site I inserted three images on a page and compared the load time in the DevTools. During this test I had Cache Disabled. I got following results:

  • private, public, nocdn
  • 3.04s, 3.03s, 3.24s
  • 1.78s, 1.77s, 1.75s
  • 1.99s, 1,95s, 3.32s
  • 1.67s, 0.73s, 0.72s
  • 1.73s, 1.71s, 1.97s
  • 1.60s, 1.58s, 1.67s

So only once I got a bigger difference, otherwise it took the same time to load a picture from a document library without CDN.

To be fair, it is a very simple performance test. Tests with bigger files, different geographical locations would probably give a more detailed view of that. And still, without a URL Rewrite that is only present on Publishing sites, you cannot take use private cdn origins.


Private CDN in Office 365 can be interesting in future, but today, the usage is narrow (only publishing sites can refer to assets in a private CDN), the performance gain is little and lower security makes it to a bad choice.

javascript: Remove illegal characters in url

Illegal characters

Recently I needed to create valid urls for pages using javascript. Also this time I thought it must be some out-of-the-box code for that in SharePoint. The first thing I came up  was the “Add page” dialog.  I found that the actual dialog was in the _layouts virtual folder:


Bingo, it does the validation in the client side. This is the responsible javascript function that resides directly in the page:

function UpdateUrl() {
  var hiddenPageUrlLabelExtensionClientId = "<%=hiddenPageUrlLabelExtension.ClientID%>";
  var hiddenPageUrlLabelExtension = document.getElementById(hiddenPageUrlLabelExtensionClientId);
  var pageNamePreviewUrlLabelClientId = "<%=pageNamePreviewUrlLabel.ClientID%>";
  var pageNamePreviewUrlLabel = document.getElementById(pageNamePreviewUrlLabelClientId);
  if( pageNamePreviewUrlLabel != null ) {
    var nameInputTextBoxClientId = "<%=nameInput.ClientID%>";
    var nameInputTextBox = document.getElementById(nameInputTextBoxClientId);
    var allowSpaces = false;
    if( GetInnerText(hiddenPageUrlLabelExtension) != "" ) {
      var suggestUrlValue = "";
      for (var i=0; i < nameInputTextBox.value.length; i++) {
         var currentChar = nameInputTextBox.value.charAt(i);
         if (IndexOfIllegalCharInUrlLeafName(currentChar) == -1 
			&& !(currentChar == ' ' && allowSpaces == false) 
			&& currentChar != '.' && currentChar != '+') {
           suggestUrlValue += currentChar;
         else if (currentChar == ' ' 
			|| currentChar == '+' 
			|| (currentChar == '.' && i > 0 && i < (nameInputTextBox.value.length - 1))) {
          suggestUrlValue += '-';
      UpdatePreviewUrl( suggestUrlValue );
    } else {
      if( g_timerId != 0 ) {
      g_timerId = window.setTimeout(OnFriendlyUrlNameChanged, 500);

This function iterates through all the characters in the page url and removes the illegal characters. The space, plus sign and the dot become a hyphen. To determine if a character is illegal, it relies on another javascript function called: IndexOfIllegalCharInUrlLeafName. This function can be found in the init.js or init.debug.js:

function IndexOfIllegalCharInUrlLeafName(strLeafName) {
    for (var i = 0; i < strLeafName.length; i++) {
        var ch = strLeafName.charCodeAt(i);

        if (strLeafName.charAt(i) == '.' && (i == 0 || i == strLeafName.length - 1))
            return i;
        if (ch < 160 && (strLeafName.charAt(i) == '/' || !LegalUrlChars[ch]))
            return i;
    return -1;

This function checks a char against an array of all characters: LegalUrlChars from the same file: init.js.


To use this UpdateUrl function, we have to remove the references to the fields from the Add Page Dialog. Of course, we won’t overwrite this original function, we don’t want to break the SharePoint OOB functionality. Here is how my new function looks like:

var takana = {};
function takana.updateUrl(url) {
  var allowSpaces = false;
  if( url )
    var suggestUrlValue = "";
    var length = url.length;
    for (var i=0; i < length; i++)     {
       var currentChar = url.charAt(i);
       if (IndexOfIllegalCharInUrlLeafName(currentChar) == -1
            && !(currentChar == ' ' && allowSpaces == false)
            && currentChar != '.' && currentChar != '+') {
         suggestUrlValue += currentChar;
       else if (currentChar == ' '
            || currentChar == '+'
            || (currentChar == '.'
                     && i > 0
                   && i < (nameInputTextBox.value.length - 1))) {
         suggestUrlValue += '-';

Server Side

For those of you who want run this operation on the server, here is the code written in C#:

//" # % & * : < > ? \ / { } ~ |
var illegalChars = @"[""#%&\*:\<\>\?\\\/\{\}~\|]";

pageName = Regex.Replace(pageName, illegalChars, string.Empty);

var punctuation = @"[\s\.;\+]";
pageName = Regex.Replace(pageName, punctuation, "-");

//remove "--"
pageName = Regex.Replace(pageName, @"\-{2,}", "-");

pageName = string.Format("{0}.aspx", pageName);

//do it like the built-in dialog, lower case
pageName = pageName.ToLower();

Don’t forget to leave a comment if you find this post useful.

$ in cmssitemanager.js conflicts with $ in jQuery

In SharePoint 2010 if CMSSiteManager.js library is loaded besides jQuery, then much of stuff stops working. The reason is that the dollar sign ($) is used in cmssitemanager.js as well which conflicts with jQuery. Mostly it appears on pages where you load jQuery and have an image library with thumbnails. To avoid this, just replace all $ with jQuery in your custom scripts. A more crazy situation is when avoiding $ isn’t enough. It is when you load jQuery to page head automatically on all pages. The Asset picker (AssetPortalBrowser.aspx) invokes $ itself and gets with jQuery in conflict without you write a single line of custom javascript code. You usually get the following error:

Uncaught TypeError: Cannot set property 'display' of undefined

Or in IE:

Unable to set value of the property 'display': object is null or undefined

The solution

I found a good solution in Brad Curtis’ blog. Run in your script:


Brad Curtis creates an additional script file. But it is okay to have this line in your javascript file, so long you load this every time jQuery is loaded. So put this before your javascript code:

// this puts jquery into no conflict mode 
//which will remedy conflicts caused by jQuery when used
// with certan publishing features

If you use jQuery.noConflict, the dollar sign ($) is not available anymore! So replace all $ with jQuery. (Unless it is inside modules… another time about that…)

Update 2013-12-06

Thanks to Steve’s comment. Please consider to use closures where you pass jQuery as a parameter

(function($) {
  //do your jQuery stuff

Please, keep in mind, the $ in cmssitemanager.js has nothing to do with jQuery, unfortunately it uses the same variable name. The issue applies for SharePoint 2013, too.

Add content to a provisioned publishing page

We can use PublishingPageContent Property to write content to a page:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="">
 <Module Name="Pages" Url="$Resources:cmscore,List_Pages_UrlName;" >
 <File Path="Pages\Help.aspx" Url="Help.aspx" Type="GhostableInLibrary">
 <Property Name="Title" Value="Contoso Help Page" />
 <Property Name="PublishingPageLayout" Value="~SiteCollection/_catalogs/masterpage/ContosoPageLayout.aspx, Text page" />
 <Property Name="ContentType" Value="$Resources:cmscore,contenttype_welcomepage_name;" />
 <Property Name="PublishingPageContent" Value="hello world"/>
Daniel Chronlund Cloud Tech Blog

News, tips and thoughts for Microsoft cloud fans

Вула Чăвашла

VulaCV - Чăвашла вулаттаракан сайт

Discovering SharePoint

And going crazy doing it

Bram de Jager - Architect, Speaker, Author

Microsoft 365, SharePoint and Azure

SharePoint Dragons

Nikander & Margriet on SharePoint

Mai Omar Desouki

PFE @ Microsoft

Cameron Dwyer

Office 365, SharePoint, Azure, OnePlace Solutions & Life's Other Little Wonders


Me and My doings!

Share SharePoint Points !

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

Aryan Nava

DevOps, Cloud and Blockchain Consultant


SharePoint for everyone


Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint


Mostly what I know and share about...