Pergunta

Consider the following case:

  • A web server is running a .NET app with <sessionState cookieless="AutoDetect" />.
  • A client is POSTing data to it using a simple HttpWebRequest (no cookies).

This seemingly simple case causes major failure.

Since .NET can't determine if the requesting agent (HttpWebRequest) supports cookies, it responds to the POST request with a 302 Found redirect to the same location with:

  • a cookie named AspxAutoDetectCookie in the response
  • a query parameter named AspxAutoDetectCookie in the forwarded location

The requesting agent is then supposed to request the new location, which HttpWebRequest does. When .NET sees AspxAutoDetectCookie in the query string, it knows this is a re-request, and it can determine if cookies are supported by seeing if a cookie named AspxAutoDetectCookie is in the request headers.

The problem is that most requesting agents (web browsers, HttpWebRequest) treat a 302 Found as if it is a 303 See Other and make the re-request a GET, regardless of the original HTTP method! Any data sent in the initial POST request is not forwarded.

The correct response should be a 307 Temporary Redirect, which does not change the request method. (A POST request to location X redirects to a POST request to location Y.)

Is there any way to change this behaviour in .NET so POST requests are not destroyed?

Information on 3xx redirection

Foi útil?

Solução

The only solution I can see to this is to append AspxAutoDetectCookie=1 to all POST requests.

This way, ASP.NET will never redirect the request and we can dodge the 302 vs 307 question altogether. If cookies are embedded in the request, ASP.NET will detect that cookies are supported, and if no cookies are embedded, it will assume they aren't.

Outras dicas

Are there any issues in using cookieless="UseDeviceProfile"? You may use it as a workaround solution.

You also see the issue if cookiless=true. You really helped me out. I couldn't even figure out what was causing this issue until I removed the line setting sessionstate cookilesss to true from my web.config, saw the problem fixed, googled my results and found this page. You helped explain why removing this line fixed the problem. Can you let me know if you find a solution that doesn't involve changing the way I use session state?

I Know the thread is old but, another viable solution is to create and HTTP Module to fix http post over cookieless.

Here is one i use

            using System;
            using System.Collections.Specialized;
            using System.Web;
            using System.Web.SessionState;
            using System.IO;
            using System.Text;

            namespace CustomModule
            {
              public sealed class CookielessPostFixModule : IHttpModule
              {
                public void Init (HttpApplication application)
                {
                  application.EndRequest += new
                              EventHandler(this.Application_EndRequest);
                }
                private string ConstructPostRedirection(HttpRequest req,
                                                        HttpResponse res)
                {
                  StringBuilder build = new StringBuilder();
                  build.Append(
              "<html>\n<body>\n<form name='Redirect' method='post' action='");
                  build.Append(res.ApplyAppPathModifier(req.Url.PathAndQuery));
                  build.Append("' id='Redirect' >");
                  foreach (object obj in req.Form)
                  {
                    build.Append(string.Format(
              "\n<input type='hidden' name='{0}' value = '{1}'>",
                      (string)obj,req.Form[(string)obj]));
                  }
                  build.Append(
              "\n<noscript><h2>Object moved <input type='submit' value='here'></h2></noscript>");
                  build.Append(@"</form>"+
                  "<script language='javascript'>"+
                  "<!--"+
                  "document.Redirect.submit();"+
                  "// -->"+
                  "</script>");
                  build.Append("</body></html>");
                  return build.ToString();
                }
                private bool IsSessionAcquired
                {
                  get
                  {
                    return (HttpContext.Current.Items["AspCookielessSession"]!=null && 
                    HttpContext.Current.Items["AspCookielessSession"].ToString().Length>0);
                  }
                }
                private string ConstructPathAndQuery(string[] segments)
                {
                  StringBuilder build = new StringBuilder(); 

                  for (int i=0;i<segments.Length;i++)
                  {
                    if (!segments[i].StartsWith("(") 
                             && !segments[i].EndsWith(")"))
                      build.Append(segments[i]);
                  }
                  return build.ToString();
                }
                private bool IsCallingSelf(Uri referer,Uri newpage)
                {
                  if(referer==null || newpage==null)
                    return false;
                  string refpathandquery = ConstructPathAndQuery(
                                                    referer.Segments);
                  return refpathandquery == newpage.PathAndQuery;
                }
                private bool ShouldRedirect
                {
                  get
                  {
                    HttpRequest req = HttpContext.Current.Request;

                    return (!IsSessionAcquired
                                && req.RequestType.ToUpper() == "POST"
                      && !IsCallingSelf(req.UrlReferrer,req.Url));
                  }
                }
                private void Application_EndRequest(Object source, EventArgs e)
                {
                  HttpRequest req = HttpContext.Current.Request;
                  HttpResponse res = HttpContext.Current.Response;
                  if (!ShouldRedirect) return;
                  res.ClearContent();
                  res.ClearHeaders();
                  res.Output.Flush();
                  char[] chr = ConstructPostRedirection(req,res).ToCharArray();
                  res.Write(chr,0,chr.Length);
                }
                public void Dispose()
                {}
              }
            }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top