Wednesday, May 30, 2007

Do you want to save about 500kb traffic for every anonymous request to your MOSS 2007 Publishing Site?

There is no default way in MOSS 2007 where you can say: "I'm online visible for anonymous users, I don't want to load core.js, portal.js, init.js, ... every time a user is accessing a page". I was searching for this switch a long time, but it doesn't seems to exist.

 

Microsoft's proposal for this is to force a delayed loading of the core.js, which can be read here: http://support.microsoft.com/kb/933823/en-us or here: http://blogs.msdn.com/ecm/archive/2007/02/21/building-a-new-page-layout-which-does-not-reference-core-js-but-downloads-it-while-the-page-is-being-viewed-thereby-optimizing-response-time.aspx. This doesn't solve the problem, but is one way to speed up your pages.

 

A solution for this problem is a HTTP-Filter. This filter can be deployed in the /bin directory of your web application and has to be referenced in your web.config.

 

The solution below is not perfect, but it works and saves a lot of traffic, server load, time and money. And it enables you to publish lightweight pages with MOSS 2007.

 

Improvements for the code below would be a separation of the "tags to cleanup" in a configuration file and the usage of regular expressions. But with output cache enabled, this shouldn't be a performance issue.

 

Make sure to adapt this code for your own needs, as I'm removing e.g. ViewState and so on, which could possibly crash your MOSS applications.

MOSSCleanupModule.cs:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using Microsoft.SharePoint;
namespace HttpModules
{
   
public class MOSSCleanupModule : IHttpModule
   
{
      
public void Init(HttpApplication app)
      {
         app.ReleaseRequestState +=
new EventHandler(InstallResponseFilter);
      }

      private void InstallResponseFilter(object sender, EventArgs e)
      {
         HttpResponse response = HttpContext.Current.Response;
         HttpRequest request = HttpContext.Current.Request;
         if (response.ContentType == "text/html" && request.Url.AbsolutePath.EndsWith(".aspx") && !request.Url.AbsolutePath.Contains
            ("_layouts/"))
         {
            SPUser user = SPContext.Current.Web.CurrentUser;
            if (user == null || string.IsNullOrEmpty(user.LoginName))
            {
               response.Filter =
new MOSSCleanupFilter(response.Filter);
            } 
         }
      }

      public void Dispose()
      {
      }
   }
}



MOSSCleanupFilter.cs:

using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.IO;
namespace HttpModules
{
public class MOSSCleanupFilter : Stream
{
   private static string[] completeTagsToCleanup = new string[] 
   {
      "<meta name=\"GENERATOR\" content=\"Microsoft SharePoint\" />",
      "<input type=\"hidden\" name=\"__SPSCEditMenu\" id=\"__SPSCEditMenu\" value=\"true\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOWebPartPage_PostbackSource\" id=\"MSOWebPartPage_PostbackSource\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOTlPn_SelectedWpId\" id=\"MSOTlPn_SelectedWpId\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOTlPn_View\" id=\"MSOTlPn_View\" value=\"0\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOTlPn_ShowSettings\" id=\"MSOTlPn_ShowSettings\" value=\"False\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOGallery_SelectedLibrary\" id=\"MSOGallery_SelectedLibrary\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOGallery_FilterString\" id=\"MSOGallery_FilterString\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOTlPn_Button\" id=\"MSOTlPn_Button\" value=\"none\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOAuthoringConsole_FormContext\" id=\"MSOAuthoringConsole_FormContext\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOAC_EditDuringWorkflow\" id=\"MSOAC_EditDuringWorkflow\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOSPWebPartManager_DisplayModeName\" id=\"MSOSPWebPartManager_DisplayModeName\" value=\"Browse\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOWebPartPage_Shared\" id=\"MSOWebPartPage_Shared\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOLayout_LayoutChanges\" id=\"MSOLayout_LayoutChanges\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOLayout_InDesignMode\" id=\"MSOLayout_InDesignMode\" value=\"\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOSPWebPartManager_OldDisplayModeName\" id=\"MSOSPWebPartManager_OldDisplayModeName\" value=\"Browse\" />"+System.Environment.NewLine,
      "<input type=\"hidden\" name=\"MSOSPWebPartManager_StartWebPartEditingName\" id=\"MSOSPWebPartManager_StartWebPartEditingName\" value=\"false\" />"+System.Environment.NewLine,
      "_spBodyOnLoadWrapper();",
   };

   private static string[] tagsToCleanup = new string[] 
   {
      "<link rel=\"stylesheet\" type=\"text/css\" href=\"/_layouts/1033/styles/core.css?rev=",
      "<link rel=\"stylesheet\" type=\"text/css\" href=\"/Style%20Library/en-US/Core%20Styles/Band.css",
      "<link rel=\"stylesheet\" type=\"text/css\" href=\"/Style%20Library/en-US/Core%20Styles/Controls.css",
      "<link rel=\"stylesheet\" type=\"text/css\" href=\"/_layouts/1033/styles/HtmlEditorCustomStyles.css?rev=",
      "<link rel=\"stylesheet\" type=\"text/css\" href=\"/_layouts/1033/styles/HtmlEditorTableFormats.css?rev=",
      "<input type=\"hidden\" name=\"__REQUESTDIGEST\" id=\"__REQUESTDIGEST\"",
      "<input type=\"hidden\" name=\"__VIEWSTATE\" id=\"__VIEWSTATE\" value=",
   };

   private static string[] scriptsToCleanup = new string[] 
   {
      "<script type=\"text/javascript\" language=\"javascript\" src=\"/_layouts/1033/core.js?rev=",
      "<script src=\"/WebResource.axd?",
      "<script> var MSOWebPartPageFormName = 'aspnetForm'",
      "<script type=\"text/javascript\" language=\"javascript\" src=\"/_layouts/1033/init.js?rev=",
      "<script type=\"text/javascript\" language=\"javascript\" src=\"/_layouts/1033/init.js?rev=",
      "<script type=\"text/javascript\" language=\"javascript\" src=\"/_layouts/portal.js?rev=",
      "<script type=\"text/javascript\" language=\"javascript\" src=\"/_layouts/1033/ie55up.js?rev=",
      "<script type=\"text/javascript\" language=\"javascript\" src=\"/_layouts/1033/non_ie.js?rev=",
      "<script type=\"text/javascript\">"+System.Environment.NewLine+"<!--"+System.Environment.NewLine+"var __wpmExportWarning",
      "<script type=\"text/JavaScript\" language=\"JavaScript\">"+System.Environment.NewLine+"<!--"+System.Environment.NewLine+"var L_Menu_BaseUrl",
   };

   private Stream responseStream;
   
private long position;

   public MOSSCleanupFilter(Stream inputStream)
   {
      this.responseStream = inputStream;
   }

   public override void Write(byte[] buffer, int offset, int count)
   {
      StringBuilder html = new StringBuilder(System.Text.UTF8Encoding.UTF8.GetString(buffer, offset, count));
      foreach(string completeTagToClean in completeTagsToCleanup) 
      {
         this.CleanUp(html, completeTagToClean);
      }

      foreach (string tagToClean in tagsToCleanup)
      {
         this.CleanUp(html, tagToClean, ">");
      }

      foreach (string scriptToClean in scriptsToCleanup)
      {
         this.CleanUp(html, scriptToClean, "</script>");
      }

      byte
[] data = System.Text.UTF8Encoding.UTF8.GetBytes(html.ToString());
      responseStream.Write(data, 0, data.Length);
   }

   private void CleanUp(StringBuilder html, string search, string endTag)
   {
      int startPos = html.ToString().IndexOf(search);
      if (startPos != -1)
      {
         if (!string.IsNullOrEmpty(endTag))
         {
            int endPos = html.ToString().IndexOf(endTag, startPos);
            if (endPos != -1)
            {
               html.Remove(startPos, endPos - startPos + endTag.Length);
            }
         }
         else
         {
            html.Remove(startPos, search.Length);
         }
      }
   }

   private
void CleanUp(StringBuilder html, string search)
   {
      
this.CleanUp(html, search, null);
   }

   #region Filter overrides
   
   
public override bool CanRead
   {
      get
      {
         return true;
      }
   }

   public
override bool CanSeek
   {
      get
      {
         return true;
      }
    }

   public override bool CanWrite
   {
      get
      {
         return true;
      }
   }

   public override void Close()
   {
      responseStream.Close();
   }

   public override void Flush()
   {
      responseStream.Flush();
   }

   public override long Length
   {
      get
      {
         return 0;
      }
   }

   public override long Position
   {
      get
      {
         return position;
      }
      set
      {
         position =
value;
      }
   }

   public override long Seek(long offset, SeekOrigin origin)
   {
      return responseStream.Seek(offset, origin);
   }

   public override void SetLength(long length)
   {
      responseStream.SetLength(length);
   }

   public override int Read(byte[] buffer, int offset, int count)
   {
      return responseStream.Read(buffer, offset, count);
   }
   #endregion
   }
}



web.config:

<httpModules>
...

   <
add name="MOSSCleanupModule" type="HttpModules.MOSSCleanupModule, HttpModules, Version=1.0.0.1, Culture=neutral, PublicKeyToken=..."/>
...
</httpModules>

5/30/2007 5:34:44 PM (Mitteleuropäische Sommerzeit , UTC+02:00)
Awesome code ;-). Thank you for this.
Lreiner
11/9/2007 4:18:08 AM (Mitteleuropäische Zeit , UTC+01:00)
Thanks very much for posting this...I have experimented a little bit by using your basic Http module idea and some similar ideas to the following http://www.sharepointblogs.com/tommysegoro/archive/2007/10/21/xhtml-validated-compliant-sharepoint-website.aspx to render more compliant XHTML for anonymous users. Seems to work pretty well and seems much more elegant that overriding the render methods of pages.
1/1/2008 1:31:52 PM (Mitteleuropäische Zeit , UTC+01:00)
If I have Publishing web under Publishing site, anonymous works great for father (site) and still brings auth dialog for son (web). For other templates, like Team, it works without issues.Breaking the inheritance and explicit defining of anonymous access on son site doesn't help.
Yehiel
9/29/2008 4:54:31 PM (Mitteleuropäische Sommerzeit , UTC+02:00)
You have a very successful business.
10/31/2008 10:02:23 AM (Mitteleuropäische Zeit , UTC+01:00)
thank you for code
1/5/2009 3:52:20 AM (Mitteleuropäische Zeit , UTC+01:00)
wow gold website, [url=http://igs.com/]wow gold[/url] and [url=http://www.mygamesale.com/power-leveling/]wow power leveling[/url]
4/13/2009 10:08:20 AM (Mitteleuropäische Sommerzeit , UTC+02:00)
I am glad to talk with you and you give me great help! Thanks for that, I am wonderring if i can contact you via email when i meet problems?
4/21/2009 3:49:49 PM (Mitteleuropäische Sommerzeit , UTC+02:00)
[url=http://www.rzdvdcreator.com]avi to dvd[/url] [url=http://www.shanghaiescort.com.cn]shanghai escort[/url][url=http://www.shanghaiescorts.net.cn]shanghai escort[/url] [url=http://www.huayihats.com/felthats.html]felt hats[/url][url=http://www.nbuico.com/product-list-info-58.html]烘箱[/url][url=http://www.lvbao8.com.cn/lvbao.html]lv包[/url][url=http://www.cnyouxiang.com/ypsjhf.html]硬盘数据恢复[/url][url=http://www.cnyouxiang.com/ypsjhf.html]杭州数据恢复[/url] [url=http://www.360google.cn]google排名[/url][url=http://www.qsnet.cn/google.asp]google排名[/url][url=http://www.360google.cn/googlebm.htm]google左侧排名[/url][url=http://www.qsnet.cn/google.asp]google左侧排名[/url][url=http://www.360google.cn]google优化[/url][url=http://www.360google.cn]google推广[/url][url=http://www.360google.cn/googlebm.htm]google左侧推广[/url][url=http://www.gzbanjia8.com.cn/]广州搬家公司[/url] [url=http://www.gzbanjia8.com.cn/]广州搬家[/url][url=http://www.360google.cn/googlebm.htm]google左侧优化[/url][url=http://www.sh28.com.cn]上海搬家[/url][url=http://www.sh28.com.cn]上海搬家公司[/url] [url=http://www.sh28.com.cn/about.htm]上海搬场[/url][url=http://www.sh28.com.cn/about.htm]上海搬场公司[/url] [url=http://www.guowang.com/en/eabout.html]paper cutting machine[/url] [url=http://www.massageshanghai8.cn]shanghai massage[/url] [url=http://www.bhbzjx.cn/eproduct.html]Bag making Machine[/url][url=http://www.hongkongmassage.net.cn]massage hongkong[/url] [url=http://www.wanyuanbj.com/product.html]制袋机[/url][url=http://www.bhbzjx.cn/BagMakingMachine.html]bag making machine[/url] [url=http:// www.tglaser.net/index01.html]激光打标机[/url] [url=http:// www.tglaser.net/index01.html]激光焊接机[/url][url=http://www.tian-rui.com.cn]广告灯箱[/url][url=http://www.sinsobond.com/aluminum-composite-panel.html]aluminum composite panel[/url][url=http://www.yimixian.com]一米线[/url][url=http://www.chinapetfilm.com]pet收缩膜[/url]
6/22/2009 6:04:09 AM (Mitteleuropäische Sommerzeit , UTC+02:00)
rulette
7/31/2009 4:29:36 AM (Mitteleuropäische Sommerzeit , UTC+02:00)
[url=http://www.gold2key.com]Sell WoW Gold[/url]
[url=http://www.gold2key.com]Sell wow gold to us[/url]
[url=http://www.gold2key.com/default/sell.html]Sell World of Warcraft gold[/url]
[url=http://www.gold2key.com/default/cdkey.html]Trade wow gold for game card[/url]
[url=http://www.cheapwowgold2u.com]buy wow gold[/url]
[url=http://www.cheapwowgold2u.com/buygold.html]cheap wow gold[/url]
[url=http://www.cheapwowgold2u.com/buygold.html]wow gold buy[/url]
[url=http://www.cheapwowgold2u.com/buygold.html]wow gold paypal[/url]
[url=http://www.cheapwowgold2u.com/powerleveling.html]wow power level[/url]
[url=http://es.goldsales4u.com/buygold.html]compra barato WoW Gold[/url]
[url=http://es.goldsales4u.com/buygold.html]wow oro[/url]
[url=http://es.goldsales4u.com/buygold.html]rápido wow oro[/url]
[url=http://es.goldsales4u.com/buygold.html]wow oro más barato[/url]
[url=http://es.goldsales4u.com/powerleveling.html]wow power leveling[/url]
[url=http://es.goldsales4u.com/buygold.html]lotro comprar oro[/url]
2/17/2010 9:13:43 PM (Mitteleuropäische Zeit , UTC+01:00)
interessanti, thanx you admin
Name
E-mail
Home page

Comment (HTML not allowed)  

Enter the code shown (prevents robots):