Response Buffer Limit Exceeded for certain users - asp-classic

I'm editing a classic ASP website and previously I was getting an error of "Response Buffer Limit Exceeded" when the code was trying to redirect to a different page with variables being passed through via the URL.
I later found that this was being caused by one of the variables having no value, and so after fixing that the error no longer appeared. However it recently came to light that the error was still appearing in certain situations, again where this specific variable value wasn't available. In this case though it only seems to be occurring for specific users, for example I've seen the error happen to someone else, but when I try the same thing it doesn't happen.
Are there any settings or anything that could be impacting this on a per user basis? Or is it just coincidence that some are getting this while others aren't?
UPDATE...
I've put in some code below that is setting the page to redirect to. It is taking values from the current page query string and placing them in variables. The variable that was previously causing problems was the last one (var_search). When a button is pressed it encodes the page path and passes it to a different piece of code.
After that code has finished it's tasks it then does a Response.Redirect with the given URL, and it's at this point that it returns the error.
this_page = "auth.asp?type=" & var_type & "&frm_page_title=" & var_page_title & "&frm_date_from=" & var_date_from & "&frm_date_to=" & var_date_to & var_all_views & "&frm_report=" & var_report & "&frm_search=" & var_search
Server.URLEncode(this_page)

Related

Loosing session variable data from one page to the other in VB.NET

I am a bit new to VB.NET. I have a page that sets 2 session variables and does a redirect to second page. The second pages is at least using one of the session variables. I can tell because on the second page, if the session variable is not correct the user is redirected to an access denied page. The second page also uses the session variable in question. It will read it an fill a gridview based on the value of the variable. I set the variable like so
Session("ID") = Convert.ToInt32(a_value)
and on the second page I retrieve the variable like this
a_page_variable = Session("ID")
What I find strange is that when I run this code in visual studio it works as expected but when I deploy and run it, I get 0 from my session variable instead of the true value of "a_value". I have tried a few things like making sure the data types match up from page to page and trying different ways to retrieve the variable such as
Session("userID")
and
CType(Session.Item("userID"), Int32)
I've also tried to see what is coming in to the second page by using
Response.Write
I also tried to use SQL Profiler to see what kind of call is being made to fill the gridview but I haven't had any luck. The gridview gives me an empty dataset and the Profiler does not detect a call being made from the application. I thought working with session variables was pretty straight forward but obviously, I am missing something.
Thanks for your help,
Billy
One possibility (and the only one that could be guessed at with how little information we have) could be the response.redirect causing the application to terminate due to an exception.
When redirecting, you want to always pass a false, and then call complete request.
Response.Redirect(urlstring, False)
Response.CompleteRequest()
not following these steps can cause exceptions, which may drop session.
Additionally, resolve virtual paths, as some browsers (mobile especially) can see those redirects as new requests entirely, thus generating new session tokens.
Dim urlstring As String
urlstring = Page.ResolveUrl("~/default.aspx")
that said, there are a number of possible causes for this situation.
Application Pool restarts
App Domain restarted
Code changing value unexpectedly
AV tinkering with files
deployed to web farm
With the description provided above, we just don't have enough information to really troubleshoot.
Thank you ADyson, Stephen Wrighton and everyone else who took a stab at helping me figure this out. I was able to find out what was going on by adding code that wrote to a log file on the server. Found the logging code here. I found that I never reached the code that set the session variable and that is the reason it never populated on the second page. I was trying to get the logon name for the user by using Environment.UserName which will return the user name of the person who is currently logged on to the operating system. But what I really wanted to do was get the logon name of the user that was visiting my site. For this I used User.Identity.Name. This works great when you need to know which user from an Active Directory domain is visiting your site.

What response code is appropriate for this situation?

I'm developing a webgame. As part of the game, you start out with a limited set of features, and you unlock more of them as you play.
For instance, you unlock /fields as part of step 3 in the tutorial. But what if you just navigate to /fields in the address bar?
I'm trying to work out what would be the best status code to respond with.
403 seems ideal since the user is forbidden from accessing the page until they unlock it.
404 also makes sense since the page technically "doesn't exist" until it is unlocked and also prevents users from being able to tell the difference between a page that doesn't exist and one that they just haven't unlocked yet.
But in both cases I've had some users report issues with the browser cacheing the 403/404 result and not letting them access the page even after unlocking it unless they purge the cache entirely.
I'm wondering if I should keep using 403 or 404, or should I use an unused 4XX code such as 442 with a custom statusText, or even jokingly send HTTP/1.1 418 I'm A Teapot in response to a user poking around where they shouldn't be.
I need a good, solid reason why one option should be used over the others.
tl;dr 409 Conflict would be an idea, but perhaps you have problems with caching. In this case a cache-buster to force a reload will work.
Long explanation
Perhaps a 409 Conflict status code would make sense:
10.4.10 409 Conflict
The request could not be completed due to a conflict with the current state of the resource. This code is only allowed in situations where it is expected that the user might be able to resolve the conflict and resubmit the request. The response body SHOULD include enough information for the user to recognize the source of the conflict. Ideally, the response entity would include enough information for the user or user agent to fix the problem; however, that might not be possible and is not required.
Conflicts are most likely to occur in response to a PUT request. For example, if versioning were being used and the entity being PUT included changes to a resource which conflict with those made by an earlier (third-party) request, the server might use the 409 response to indicate that it can't complete the request. In this case, the response entity would likely contain a list of the differences between the two versions in a format defined by the response Content-Type.
It would make sense, because the resource is only available after the user did the tutorial. Before that the resource is in an «invalid» state. And the user is able to resolve this conflict by completing the tutorial.
Later I investigated the case a little more and I discovered that the devil is in the detail. Let's read the specification for 403 Forbidden and 404 Not Found.
10.4.4 403 Forbidden
The server understood the request, but is refusing to fulfill it. Authorization will not help and the request SHOULD NOT be repeated. If the request method was not HEAD and the server wishes to make public why the request has not been fulfilled, it SHOULD describe the reason for the refusal in the entity. This status code is commonly used when the server does not wish to reveal exactly why the request has been refused, or when no other response is applicable.
Important is the specification that «the request SHOULD NOT be repeated». A browser which never re-requests a 403 page might do the right thing. However, let's continue with 404:
10.4.5 404 Not Found
The server has not found anything matching the Request-URI. No indication is given of whether the condition is temporary or permanent.
[omitted]
Now we have a problem! Why would your 404 pages be cached if the specification allows them to be temporary?
Perhaps in your setup you have caching configured not correctly for your 403 and 404 pages. If this is so, please consult this answer on StackOverflow. It gives a detailed answer about caching 4xx pages.
If you don't want to mess with caching headers, use a so-called cache-buster and pass the system time like this (assuming PHP as your web language):
<a href="/fields?<?php echo time(); ?>">
This produces URLs like /fields?1361948122, increasing every second. It's a variant of the solution proposed by Markus A.
I assume the querystring 1361948122 is ignored by your resource. If it is not, pass the cache-buster in a querystring parameter instead, for example t=1361948122 and make sure that the parameter t is not evaluated by your resource.
In terms of the intended purpose of the HTTP error codes, I would definitely go with 403 Forbidden, because the page does exist (404 is out), but the user is forbidden to access it for now (and this restriction is not due to a resource conflict, like concurrent modification, but due to the user's account status, i.e. 409 is out as well in my opinion). Another sensible option based on it's intended purpose could have been 401, but as nalply already noted in his comment, this code triggers some, if not all, browsers to display a login dialog, as it implies that using the standard web-authentication mechanism can resolve the issue. So, it would definitely not be an option for you here.
Two things seem a little "misfitting" in the description of 403, so let me address them:
Authorization will not help ...: This only talks about the authorization mechanism inside the HTTP protocol and is meant to distinguish 403 from 401. This statement does not apply to any form of custom authorization or session state management.
... the request SHOULD NOT be repeated ...: A request must always be seen in the session context, so if the session context of the user changes (he unlocks a feature) and then he retries accessing the same resource, that is a different request, i.e. there is no violation of this suggestion.
Of course, you could also define your own error code, but since it probably won't be reserved in any official way, there is no guarantee that some browser manufacturer isn't going to intentionally or accidentally use exactly that code to trigger a specific (debugging) action. It's unlikely, but not disallowed.
418 could be OK, too, though. :)
Of course, if you would like to specifically obscure the potential availability of features, you could also decide to use 404 as that is the only way to not give a nosy user any hints.
Now, to your caching issue:
Neither one of these status codes (403, 404, 409, 418) should trigger the browser to cache the page against your will more than any other. The problem is that many browser simply try to cache everything like crazy to be extra snappy. Opera is the worst here in my opinion. I've been pulling my hair out many times over these things. It SHOULD be possible to work it all out with the correct header settings, but I've had situations where either the browser or the server or some intermediate proxy decided to ignore them and break my page anyways.
The only sure-fire way that I have found so far that absolutely positively guarantees a reload is to add a dummy request parameter like /fields?t=29873, where 29873 is a number that is unique for every request you make within any possibly relevant time scales. On the server, of course, you can then simply ignore this parameter. Note that it is not enough to simply start at 1 when your user first opens your page and then count up for following requests, as browsers might keep the cache around across page-reloads.
I do my web-development in Java (both server and client-side using GWT) and I use this code to generate the dummy "numbers":
private static final char[] base64chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_.".toCharArray();
private static int tagIndex = 0;
/**
* Generates a unique 6-character tag string that is guaranteed to not repeat
* for about 400 days, if this function is, on average, not called more often
* than twice every millisecond.
*
* #return the tag string
*/
public static String nowTag() {
int tag = (int) ((System.currentTimeMillis() >>> 5)); // adjust
char[] result = new char[6];
result[5] = base64chars[(tagIndex++) & 63];
result[4] = base64chars[tag & 63];
tag >>>= 6;
result[3] = base64chars[tag & 63];
tag >>>= 6;
result[2] = base64chars[tag & 63];
tag >>>= 6;
result[1] = base64chars[tag & 63];
tag >>>= 6;
result[0] = base64chars[tag & 63];
return new String(result);
}
It uses the system's clock in combination with a counter to be able to provide up to about two guaranteed unique values every ms. You might not need this speed, so you can feel free to change the >>> 5 that I marked with "adjust" to fit your needs. If you increase it by 1, your rate goes down by a factor of two and your uniqueness time-span doubles. So, for example, if you put >>> 8 instead, you can generate about 1 value every 4 ms and the values should not repeat for 3200 days. Of course, this guarantee that the values will not repeat will go away if the user messes with the system clock. But since these values are not generated sequentially, it is still very unlikely that you will hit the same number twice. The code generates a 6-character text-string (base64) rather than a decimal number to keep the URLs as short as possible.
Hope this helps. :)
I feel there is no need to throw an error code, in spite you just display a message like
You have to be Level XX to access this page or something funny like Come back when you grow-up
with code 200-OK itself, so there will be no cache problem and objective is also achieved.

having trouble reading header values in classic ASP

This is all internal servers and software, so I'm very limited on my options, but this is where I'm at. This is already a band-aid to a workaround but I have no choice, so I'm just trying to make it work.
I have a simple .asp file on my server that is protected by a service that will handle the user authentication (I have no control over this service). When a user goes to this .asp file, it requires them to authenticate via the service, and the service then redirects them to the .asp.
The service is inserting custom values in to the http header that allow me to identify who has logged in (I need it further down the line). When I use the asp to view the ALL_RAW and ALL_HTTP values from the header, I can see all the custom values. But when I try to call these values specifically I get nothing.
I ran this simple loop:
<%
for each x in Request.ServerVariables
response.write("<B>" & x & ":</b> " & Request.ServerVariables(x) & "<p />")
next
%>
and all the keys display including the custom ones. But none of the custom values will. The values are the part I need.
the only thing I can find unique about the custom values is that they look slightly different in the ALL_RAW value, but they all look correct in the ALL_HTTP. As best I can tell, they are formatted correctly. the only formatting differences between the standard and custom values are case and underscores instead of hyphens.
Why can I not read these custom values?
I found my answer.
When I ran this loop
<%
for each x in Request.ServerVariables
response.write("<B>" & x & ":</b> " & Request.ServerVariables(x) & "<p />")
next
%>
it would return a list of all the names that were in the header and their values. The custom value I was looking for would show as name "HTTP_CUSTOM_ID" and I could see it, with it's value in the ALL_HTTP and ALL_RAW, but when I tried to pull that specific value, it would return an empty string. The solution I stumbled on (by talking to someone else here at work who had gone through a similar situation with the same service I was trying to accommodate is to use:
<%=Request.ServerVariables("HEADER_CUSTOM_ID")%>
When viewing the full header, nothing led me to use the HEADER prefix instead of the HTTP, in fact, it led me opposite. And I never found any mention of this anywhere searching online either. So I'm posting my own answer to my question here so it is on the web.
For the sake of expedience, why not just parse Request.ServerVariables("ALL_RAW") yourself?
There is a better way than parsing each item yourself. Look at the values in Request.ServerVariables("ALL_HTTP") and find the header you need but named a bit different.
All HTTP headers start with HTTP_. I was looking for If-None-Match and it was in the collection as HTTP_IF_NONE_MATCH. To get the value I used Request.ServerVariables("HTTP_IF_NONE_MATCH").

Why does a percent symbol in a get request break my site?

I feel pretty stupid for asking this, but I'm doing a form where the user enters some input and sometimes the input is a percent symbol, say 5%. When this gets passed along as part of a GET request, like this:
http://kburke.org/project/company_x/?id=4&var1=1&ops=23255&cashflow=25000&growth=5%25&pv=100000&roe=20&profitmargin=30&roe=80&turnover=2
I get a 404 Page Not Found error. When I remove the query string pair
&growth=5%25
the page loads fine. Can someone help explain what the problem is?
Edit: I tried removing all of the Javascript from the page and the server still craps out. I also just tried running it in MAMP as
http://localhost:8888/project/company_x/?id=4&var1=1&ops=23255&cashflow=25000&growth=5%25&pv=100000&roe=20&profitmargin=30&roe=80&turnover=2
and it worked fine. I'm wondering if it's a problem with my own server. When I open Firebug to the console and run the page, I see an error very briefly and then the 404 page loads - is there a way I can pause the redirect so I can read the error message?
Check out URL ENCODING. The "%" character in a url means something special.
You encode the space character ' ' as %20 in a url.
You encode the percent character '%' as %25 in a url.
So after your url gets to the script, your argument 'growth' will equal "5%".
I tried messing around with your url and it appears that your script is crashing when it tries to parse the growth argument, and your web site is hiding that crash from you by sending you to the 404 page. I'd post your script code if you need more help.

Using endResponse in a Response.Redirect

While performing a response.redirect in an ASP.NET page, I received the error:
error: cannot obtain value
for two of the variables being passed in (one value being retrieved from the querystring, the other from viewstate)
I've never seen this error before, so I did some investigating and found recommendations to use the "False" value for "endResponse"
e.g. Response.Redirect("mypage.aspx", False)
This worked.
My question is: what are the side-effects of using "False" for the "endResponse" value in a response.redirect?
i.e. are there any effects on the server's cache? Does the page remain resident in memory for a period? Will it affect different users viewing the same page? etc.
Thanks!
From this other question and this blog post, the recommended pattern is-
Response.Redirect(url, false);
Context.ApplicationInstance.CompleteRequest();
This avoids the expensive ThreadAbortException/Response.End. Some code will be executed after the CompleteRequest(), but ASP.Net will close the request as soon as it is convenient.
Edit- I think this answer gives the best overview. Note that if you use the pattern above, code after the redirect will still be executed.
An MSDN blog post that might answer your question:
The drawback to using [Response.Redirect(url, false)] is that the page will continue to process on the server and be sent to the client. If you are doing a redirect in Page_Init (or like) and call Response.Redirect(url, false) the page will only redirect once the current page is done executing. This means that any server side processing you are performing on that page WILL get executed.
Response.Redirect(..., true) results in a ThreadAbortException.
depending on your exception handling setup you might get your log filled with error messages one for each redirect.

Resources