Secure use of IfModifiedSince HTTP header in PCL libraries

    Suddenly the connection was lostWe are developing an application for several platforms, we create the entire platform-independent part using PCL, trying to achieve the maximum level of reuse of components. For communication with the server, the HttpWebRequest class is used which implements all the functionality necessary from the transport level.

    Recently, the protocol has been optimized, it has become possible to reduce the amount of data transmitted indicating the horizon of relevance. This optimization has been implemented using the processing of the IfModifiedSince HTTP header, but the IfModifiedSince property is not available for the HttpWebRequest object in the PCL. This did not seem to be a problem. The header was added directly to the request header collection.

    request.Headers[HttpRequestHeader.IfModifiedSince] = timeStamp.ToString();
    

    After testing the solution on a WindowsPhone application, I was convinced of its working capacity, but all unit tests of the transport level gave errors. Having studied the problem, I found that the WebHeaderCollection implementation for the Windows platform does not allow setting this header directly and requires developers to use the HttpWebRequest.IfModifiedSince property, which is not available in PCL assemblies.

    To solve this, I created an extension method for the HttpWebRequest class that implements the following logic:

    When we first access the method, we try to add a header to the collection of request headers, if this fails, using reflection we look for the IfModifiedSince field in the request object, create and cache a delegate for installation property values.

    In subsequent calls to the method, use the cached delegate to set the value of the IfModifiedSince header.

    namespace System.Net
    {
    	public static class NetExtensions
    	{
    		private static Action _setIfMofifiedSince;
    		public static void SetIfModifiedSince(this HttpWebRequest request, DateTime value)
    		{
    			Guard.NotNull(request);
    			if (_setIfMofifiedSince != null)
    			{
    				_setIfMofifiedSince(request, value);
    				return;
    			}
    			try
    			{
    				request.Headers[HttpRequestHeader.IfModifiedSince] = value.ToString();
    				return;
    			}
    			// ReSharper disable once EmptyGeneralCatchClause
    			catch
    			{
    			}
    			var property = request.GetType().GetRuntimeProperty("IfModifiedSince");
    			if (property != null
    				&& property.CanWrite)
    			{
    				var method = property.SetMethod;
    				if (method != null)
    				{
    					_setIfMofifiedSince = (Action)method.CreateDelegate(typeof(Action));
    				}
    			}
    			if (_setIfMofifiedSince == null)
    			{
    				throw new Exception("Unable to set IfModifiedSince");
    			}
    			_setIfMofifiedSince(request, value);
    		}
    	}
    }
    


    Using this extension method, the code remains easy to read and understand.

    request.SetIfModifiedSince(timeStamp);
    

    Also popular now: