[Patch] Enable content compression for sync via HTTP

Discussion [Patch] Enable content compression for sync via HTTP

  • 2011年10月27日 10:26
     
      コードあり

    I'd like to share my solution to enable content compression for sync via HTTP.

    With just a few lines of code we can enable the sync client to leverage gzip compression for downloads if the server supports it, too. For the actual decompression you have to utilize any compression library. I have decided for well-known SharpZipLib.

    WP7Client: Microsoft.Syncronization.ClientServices.HttpCacheRequestHandler

            void ProcessRequest(AsyncArgsWrapper wrapper)
            {
    ...
    
                    // Set the method type
                    webRequest.Method = "POST";
                    webRequest.Accept = (base.SerializationFormat == SerializationFormat.ODataAtom) ? "application/atom+xml" : "application/json";
                    webRequest.ContentType = (base.SerializationFormat == SerializationFormat.ODataAtom) ? "application/atom+xml" : "application/json";
    
                    try
                    {
                        // Enable compression
                        webRequest.Headers[HttpRequestHeader.AcceptEncoding] = "gzip";
                    }
                    catch (ArgumentException)
                    {
                        // Pre-Mango OS throws: ArgumentException - The 'Accept-Encoding' header cannot be modified directly.
                    }
    ...       
            void OnUploadGetResponseCompleted(IAsyncResult asyncResult)
            {
    ...
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Stream responseStream = response.GetResponseStream();
    
                        // Decompress if required
                        if (response.Headers[HttpRequestHeader.ContentEncoding] != null && response.Headers[HttpRequestHeader.ContentEncoding].Contains("gzip"))
                        {
                            responseStream = new GZipInputStream(responseStream);
                        }
    
                        // Create the SyncReader
    ...
    
            void OnDownloadGetResponseCompleted(IAsyncResult asyncResult)
            {
    ...
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Stream responseStream = response.GetResponseStream();
    
                        // Decompress if required
                        if (response.Headers[HttpRequestHeader.ContentEncoding] != null && response.Headers[HttpRequestHeader.ContentEncoding].Contains("gzip"))
                        {
                            responseStream = new GZipInputStream(responseStream);
                        }
    
                        // Create the SyncReader
    ...
    

    There are plenty of good tutorials on how to enable IIS to do compression like the one from Scott Hanselmann about Enabling dynamic compression

    It is even possible to enable compression for uploads. All it takes is a little more patching of the client and a little patching of the server library.

    WP7Client: Microsoft.Syncronization.ClientServices.HttpCacheRequestHandler

     

            void OnUploadGetRequestStreamCompleted(IAsyncResult asyncResult)
            {
    ...
                    Stream requestStream = wrapper.WebRequest.EndGetRequestStream(asyncResult);
    
                    // Compress
                    wrapper.WebRequest.Headers[HttpRequestHeader.ContentEncoding] = "gzip";
                    requestStream = new GZipOutputStream(requestStream);
    ...
    
            void OnDownloadGetRequestStreamCompleted(IAsyncResult asyncResult)
            {
    ...
                    Stream requestStream = wrapper.WebRequest.EndGetRequestStream(asyncResult);
    
                    // Compress
                    wrapper.WebRequest.Headers[HttpRequestHeader.ContentEncoding] = "gzip";
                    requestStream = new GZipOutputStream(requestStream);
    ...
    


     

    SyncServiceLib: Microsoft.Synchronization.Services.RequestParser

            /// <summary>
            /// Read request details for Download/upload operations.
            /// </summary>
            private void ReadIncomingRequestDetails()
            {
    ...
                    SyncTracer.Info("Request HTTP method is POST");
    
                    if (null != _serviceHost.RequestHeaders[HttpRequestHeader.ContentEncoding] && _serviceHost.RequestHeaders[HttpRequestHeader.ContentEncoding].Contains("gzip"))
                    {
                        SyncTracer.Info("Request payload is gzipped");
                        ReadIncomingRequestStreamForPost(true);
                    }
                    else
                        // Parse request stream and populate members.
                        ReadIncomingRequestStreamForPost();
    ...
            private void ReadIncomingRequestStreamForPost(bool isGzipped = false)
            {
    ...
                try
                {
                    Stream inputStream = (isGzipped) ? new GZipInputStream(_serviceHost.RequestStream) : _serviceHost.RequestStream;
    
                    var reader = WebUtil.GetSyncReader(_serviceHost.GetRequestContentSerializationFormat(),
                                                       inputStream,
                                                       _configuration.TypeToTableGlobalNameMapping.Keys.ToArray());
    ...	
    
    

     

    Let me know how it works for you.


    Senior Jack of all trades

    • 種類を変更済み M.Bi 2011年10月27日 11:36
    • 編集済み M.Bi 2011年11月14日 7:56
    •