2009-02-19 9 views
13

J'ai une page aspx où je permet à un utilisateur de télécharger un fichier et je veux limiter la taille de téléchargement de fichier à 10 Mo. IIS7, .NET 3.5. J'ai configuré ce qui suit dans mon fichier web.config:Où puis-je attraper et gérer maxAllowedContentLength dépassé dans IIS7?

<location path="foo.aspx"> 
    <system.web> 
     <!-- maxRequestLength: kbytes, executionTimeout:seconds --> 
     <httpRuntime maxRequestLength="10240" executionTimeout="120" /> 
     <authorization> 
      <allow roles="customRole"/> 
      <!-- Deny everyone else --> 
      <deny users="*"/> 
     </authorization> 
    </system.web> 
    <system.webServer> 
     <security> 
      <requestFiltering> 
       <!-- maxAllowedContentLength: bytes --> 
       <requestLimits maxAllowedContentLength="10240000"/> 
      </requestFiltering> 
     </security> 
     <handlers accessPolicy="Read, Script"> 
      <add name="foo" path="foo.aspx" verb="POST" 
       type="System.Web.UI.PageHandlerFactory" 
       preCondition="integratedMode" /> 
     </handlers>  
    </system.webServer> 
</location> 

J'ai un module de gestion des erreurs personnalisée qui implémente IHttpModule. J'ai constaté que lorsque maxRequestLength est dépassé, HttpApplication.Error est en effet élevé. Toutefois, lorsque je joue avec maxAllowedContentLength, l'événement HttpApplication.Error n'est pas déclenché et l'utilisateur est redirigé vers une page 404.13. J'ai attaché avec Visual Studio avec des exceptions de première chance activées rien n'est lancé.

Mon premier réflexe est de vérifier la longueur du contenu de l'en-tête lors d'un événement antérieur - y a-t-il des recommandations/bonnes pratiques concernant l'endroit où je fais cela? PostLogRequest? EndRequest?

Répondre

14

Après avoir regardé le ASP.NET Application Life Cycle Overview for IIS 7.0 et fait ma propre expérimentation, je suppose que la validation de la requête est faite en interne par IIS avant que l'un des événements ne soit déclenché.

Il semble que seules LogRequest, PostLogRequest, EndRequest, PreSendRequestContent et PreSendRequestHeaders sont déclenchés après la validation interne avec cette erreur. J'ai décidé d'attacher un gestionnaire d'événement à l'événement HttpApplication.EndRequest dans mon gestionnaire d'erreur personnalisé et de vérifier le code d'état 404.13 sur POST et gérer comme j'ai besoin de le gérer, ce qui dans mon cas est de rediriger vers le page d'appel qui va vérifier Server.GetLastError() et afficher une erreur amicale à l'utilisateur final.

private void application_EndRequest(object sender, EventArgs e) 
{ 
    HttpRequest request = HttpContext.Current.Request; 
    HttpResponse response = HttpContext.Current.Response; 

    if ((request.HttpMethod == "POST") && 
     (response.StatusCode == 404 && response.SubStatusCode == 13)) 
    { 
     // Clear the response header but do not clear errors and 
     // transfer back to requesting page to handle error 
     response.ClearHeaders(); 
     HttpContext.Current.Server.Transfer(
      request.AppRelativeCurrentExecutionFilePath); 
    } 
} 

Je serais heureux de recevoir vos commentaires sur cette approche et les alternatives.

+0

Veuillez noter que la réponse de sunflowerpower ne fonctionne que si le mode pipeline géré est défini sur Intégré. Au moins c'est pourquoi j'ai expérimenté – Marvin

+0

Je remarque que cette solution ne gère pas correctement l'authentification. Lorsque j'appelle Server.Transfer, les routines de vérification d'authentification de la page cible échouent car la propriété HttpContext.Current.User est NULL. Cela ne semble pas provenir de l'effacement des en-têtes, car la sortie de cette ligne entraîne toujours le problème. Y at-il un moyen de contourner cela? Ce n'est pas une solution autrement. – Triynko

+0

J'ai mis le code d'erreur de @Triynko dans votre gestionnaire d'événements. J'utilise Umbraco - je ne suis pas sûr que ce soit significatif mais c'est le seul endroit où j'ai été capable d'attraper des exceptions 'Maximum request length exceeded' pour le moment. J'ai aussi dû appeler 'Response.ClearContent();' pour enlever le YSOD. 'Application_Error' ne se déclenche pas pour cette exception (bien que ce soit le cas pour RequestValidation) et je n'ai pas pu obtenir 'OnError' pour déclencher un UserControl ou une Masterpage. Impossible de trouver une page réelle. ;) –

3

La méthode la plus simple consiste à la gérer dans la méthode OnError de la page elle-même.

Je pense que cela ne fonctionne que dans .NET 4.0, car la propriété WebEventCode est documentée comme NEW dans .NET 4.0.

protected override void OnError(EventArgs e) 
{ 
    Exception err = Server.GetLastError(); 
    if (err is HttpException) 
    { 
     if ((err as HttpException).WebEventCode == 3004) 
     { 
      Context.Items["error"] = "File exceeded maximum allowed length."; 
      Server.Transfer(Context.Request.Url.LocalPath); 
      return; 
     } 
    } 
    base.OnError(e); 
} 

protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); 
    if (!IsPostBack) 
    { 
     string error = Context.Items["error"] as string; 
     if (!string.IsNullOrEmpty(error)) 
      showErrorMessage(error); 
    } 
} 

Ce que je ne faisais que:

  • obtenir la dernière erreur avec Server.GetLastError
  • vérifier qu'il est une "longueur maximale de la demande dépassé." erreur (WebEventCode == 3004).
  • ajoute une valeur de collections Context.Items pour signaler la demande comme une erreur
  • transfert de la demande revenir à la page elle-même avec Server.Transfer (Context.Request.Url.LocalPath)
  • vérifie la méthode OnLoad de la Page pour l'indicateur d'erreur et affiche un message si présent

Ceci garantit que l'erreur est entièrement gérée sur la page demandée, et la page est capable de signaler des erreurs. Notez également que même si le navigateur finit par recevoir une réponse correcte, le navigateur peut prendre le temps de télécharger la totalité de la requête avant de gérer la réponse du serveur et de l'afficher. Ce comportement est probablement défini comme faisant partie de l'interaction serveur/navigateur dans le protocole HTTP, il est donc peu probable que l'on puisse faire grand-chose à ce sujet.

+0

Parfois, il retourne le code '0'. –

+0

J'ai utilisé ceci pour le contrôle ... http://stackoverflow.com/a/665591/221683 –