title: Large file upload when using ssl and client certificates (uploadReadAheadSize) but dont want all data to be readahead
body: <p>I tried to search the internet/stack overflow and couldn't find any relevant answer that worked for me.</p>
  
  <p>I have an asp.net web api2 application (uses ssl only).
  I'm trying to allow large file upload (up to ~36mb) but unless i change uploadReadAheadSize to readahead this size I get an error from IIS that the request is too long. </p>
  
  <p>I don't want to set that attribute because then my data stream only arrives after IIS read it all already. </p>
  
  <p>My question is: <b>How can I do large file upload with asp.net hosted and <i>using ssl(!)</i> and web api 2 without having a large uploadreadaheadsize configured?</b> since it seems all the steps i've taken are insufficient.</p>
  
  <blockquote>
    <p>uploadReadAheadSize:</p>
    
    <p>Specifies the number of bytes that a Web server will read into a buffer and pass to an ISAPI extension or module. This occurs once per client request. The ISAPI extension or module receives any additional data directly from the client. The value must be between 0 and 2147483647.
    The default value is 49152.</p>
  </blockquote>
  
  <p>This is the error i get if i do not set uploadReadAheadSize and try to upload a large file over ssl:</p>
  
  <blockquote>
    <p>HTTP Error 413.0 - Request Entity Too Large</p>
    
    <p>Things you can try:
    The page was not displayed because the request entity is too large.</p>
    
    <p>Most likely causes:</p>
    
    <p>The Web server is refusing to service the request because the request entity is too large.
    The Web server cannot service the request because it is trying to negotiate a client certificate but the request entity is too large.
    The request URL or the physical mapping to the URL (i.e., the physical file system path to the URL's content) is too long.
    Things you can try:
    Verify that the request is valid.
     If using client certificates, try:</p>
    
    <p>Increasing system.webServer/serverRuntime@uploadReadAheadSize</p>
    
    <p>Configure your SSL endpoint to negotiate client certificates as part of the initial SSL handshake. (netsh http add sslcert ... clientcertnegotiation=enable)</p>
  </blockquote>
  
  <pre><code>Verify that the request is valid.
    If using client certificates, try:
      Increasing system.webServer/serverRuntime@uploadReadAheadSize
      Configure your SSL endpoint to negotiate client certificates as part of the initial SSL handshake. (netsh http add sslcert ... clientcertnegotiation=enable)
  </code></pre>
  
  <p>If I configure read-ahead to the size i want to allow, iis allows my request:</p>
  
  <pre><code>C:\Windows\SysWOW64&gt;C:\Windows\System32\inetsrv\appcmd set config ... -section:system.webServer/serverRuntime /uploadReadAheadSize:n /commit:apphost
  Applied configuration changes to section "system.webServer/serverRuntime" for "MACHINE/WEBROOT/APPHOST/..." at configuration commit path "MACHINE/WEBROOT/APPHOST"
  </code></pre>
  
  <p>I have this configured in web.config:</p>
  
  <pre><code>...
  &lt;httpRuntime targetFramework="4.5.1" maxRequestLength="36864"  /&gt; 
  ...
  </code></pre>
  
  <p>and </p>
  
  <pre><code>...
  &lt;system.webServer&gt;
      &lt;security&gt;
        &lt;requestFiltering&gt;
          &lt;requestLimits maxAllowedContentLength="37748736"&gt; 
  ...
  </code></pre>
  
  <p>I have a dummy controller that receives the file</p>
  
  <pre><code>[ControllerBufferlessAttribute()]
  public class UploadController : ApiController
  {
      public HttpResponseMessage Post([FromUri]string filename)
      {
          var selector = RequestContext.Configuration.Services.GetHostBufferPolicySelector();
              var isbufferless = string.Format("It is {0} that i'm bufferless but still IIS already read all the data before this context because of the readahead", selector is PolicySelectorBufferless);
              return new HttpResponseMessage(HttpStatusCode.InternalServerError) { ReasonPhrase = isbufferless };          
      }
  }
  </code></pre>
  
  <p>The attribute and policy:</p>
  
  <pre><code>public class ControllerBufferlessAttribute : Attribute, IControllerConfiguration
  {
      public void Initialize(HttpControllerSettings settings,
          HttpControllerDescriptor descriptor)
      {
          settings.Services.Replace(typeof(IHostBufferPolicySelector), new PolicySelectorBufferless());
      }
  }
  public class PolicySelectorBufferless : WebHostBufferPolicySelector
  {
      public override bool UseBufferedInputStream(object hostContext)
      {
          return false;
      }
      public override bool UseBufferedOutputStream(HttpResponseMessage response)
      {
          return base.UseBufferedOutputStream(response);
      }
  }
  </code></pre>
  
  <p>The content i get in a request</p>
  
  <blockquote>
    <p>It is True that i'm bufferless but still IIS already read all the data before this context because of the readahead</p>
  </blockquote>