I wrote an IHttpModule that compresses my response using gzip (I return a lot of data.) in order to reduce response size. It is working great as long as the web service doesn't throw an exception. In case an exception is thrown, the exception is gzipped but the Content-encoding header disappears and the client doesn't know to read the exception.
Why is the header missing? I need to get the exception in the client.
Here is the module:
public class JsonCompressionModule : IHttpModule
{
public JsonCompressionModule()
{
}
public void Dispose()
{
}
public void Init(HttpApplication app)
{
app.BeginRequest += new EventHandler(Compress);
}
private void Compress(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
HttpRequest request = app.Request;
HttpResponse response = app.Response;
try
{
//Ajax Web Service request is always starts with application/json
if (request.ContentType.ToLower(CultureInfo.InvariantCulture).StartsWith("application/json"))
{
//User may be using an older version of IE which does not support compression, so skip those
if (!((request.Browser.IsBrowser("IE")) && (request.Browser.MajorVersion <= 6)))
{
string acceptEncoding = request.Headers["Accept-Encoding"];
if (!string.IsNullOrEmpty(acceptEncoding))
{
acceptEncoding = acceptEncoding.ToLower(CultureInfo.InvariantCulture);
if (acceptEncoding.Contains("gzip"))
{
response.AddHeader("Content-encoding", "gzip");
response.Filter = new GZipStream(response.Filter, CompressionMode.Compress);
}
else if (acceptEncoding.Contains("deflate"))
{
response.AddHeader("Content-encoding", "deflate");
response.Filter = new DeflateStream(response.Filter, CompressionMode.Compress);
}
}
}
}
}
catch (Exception ex)
{
int i = 4;
}
}
}
Here is the web service:
[WebMethod]
public void DoSomething()
{
throw new Exception("This message get currupted on the client because the client doesn't know it gzipped.");
}
You should try to deal with the exception in page_error or in application_error event handlers.
I don't know what happens to the header but you probably can simulate and debug the Compress method by dividing by zero inside your application.
Check this link about global exception handling in ASP.NET
Related
I have set iis up so that http redirects to https which is working as it should. The problem is that if I type the url into the browser without http - such as:
example.com/page.aspx?id=1 then it redirects without the parameters - like this:
https://example.com/page.aspx
I am sure that it is some problem in the way iis is redirecting from http to https because if I look in chrome debugger then the url is changed to:
https://example.com/page.aspx
so this happens before my asp.net page is even called.
I have no rewrite rules in my web.config file instead I am using my own class that inherits from IHttpModule:
class LinkModule : IHttpModule
{
string realQueryString = "";
public LinkModule()
{
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
public void Dispose() { }
private void context_BeginRequest(object sender, EventArgs e)
{
HttpRequest request = ((HttpApplication)sender).Request;
HttpContext context = ((HttpApplication)sender).Context;
string applicationPath = request.ApplicationPath;
string requestPath = request.Url.AbsolutePath.Substring(applicationPath.Length);
string path = HttpContext.Current.Request.Path;
//string host = HttpContext.Current.Request.ServerVariables["HTTP_HOST"];
realQueryString = context.Request.QueryString.ToString();
string requesturi = request.Url.AbsoluteUri.Substring(applicationPath.Length);
LoadTemplate(ref requestPath);
context.RewritePath(applicationPath + requestPath);
}
private void LoadTemplate(ref string path)
{
if (path.IndexOf("showproduct.aspx", StringComparison.CurrentCultureIgnoreCase) != -1)
{
path = string.Format("/frontarea/product/index{0}", !string.IsNullOrEmpty(realQueryString) ? "?" + realQueryString : "");
return;
}
}
}
I have an android app which is making api requests to my server running Spring MVC. The RestController works fine when I make a request from the browser but it responds with 404 when I am making requests from android. Not sure why
Here is code snippet from Android app making requests
public class AsyncFetch extends AsyncTask<Pair<String, String>, String, String> {
public ProgressDialog pdLoading;
private HttpURLConnection conn;
private String urlStr;
private String requestMethod = "GET";
public AsyncFetch(String endpoint, Context ctx)
{
pdLoading = new ProgressDialog(ctx);
Properties reader = PropertiesReader.getInstance().getProperties(ctx, "app.properties");
String host = reader.getProperty("host", "10.0.2.2");
String port = reader.getProperty("port", "8080");
String protocol = reader.getProperty("protocol", "http");
String context = reader.getProperty("context", "");
this.urlStr = protocol+"://"+host+":"+port+context+endpoint;
}
#Override
protected void onPreExecute() {
super.onPreExecute();
//this method will be running on UI thread
pdLoading.setMessage("\tLoading...");
pdLoading.setCancelable(false);
pdLoading.show();
}
#Override
protected String doInBackground(Pair<String, String>... params) {
URL url;
try {
url = new URL(urlStr);
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return e.toString();
}
try {
conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(READ_TIMEOUT);
conn.setConnectTimeout(CONNECTION_TIMEOUT);
conn.setRequestMethod(requestMethod);
conn.setDoOutput(true);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
return e1.toString();
}
try {
int response_code = conn.getResponseCode();
// Check if successful connection made`enter code here`
if (response_code == HttpURLConnection.HTTP_OK) {
// Read data sent from server
InputStream input = conn.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
StringBuilder result = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
result.append(line);
}
// Pass data to onPostExecute method
return (result.toString());
} else {
return ("unsuccessful");
}
} catch (IOException e) {
e.printStackTrace();
return e.toString();
} finally {
conn.disconnect();
}
}
Spring MVC Controller
#RestController
public class ApiController {
#RequestMapping(value = "homefeed", method=RequestMethod.GET)
public String homefeed(#RequestParam(value="userId", required = false) Integer id, #RequestParam(value="search", required = false) String search, #RequestParam(value="page", required = false, defaultValue = "0") Integer page) { ... }
}
localhost:8080/api/homefeed -- works
127.0.0.1:8080/api/homefeed -- works
My Public IP:8080/api/homefeed -- does not works
10.0.2.2:8080/api/homefeed -- android emulator to localhost -- does not work
10.0.2.2:8080/Some resource other than the api endpoint -- works
Any help is highly appreciable, have wasted quiet some time in debugging.
I am writing one class with the help of HTTPModule to check userIdentity in session before he access any page.If the variable in the session is null or empty i am redirecting the user in session expired page.
Code in Class:
public class SessionUserValidation : IHttpModule
{
public void Dispose()
{
}
public void Init(HttpApplication application)
{
application.PreRequestHandlerExecute += new
EventHandler(application_PreRequestHandlerExecute);
}
private void application_PreRequestHandlerExecute(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
IHttpHandler handler = application.Context.Handler;
Page reqPage = handler as Page;
if (reqPage != null)
{
reqPage.PreInit += new EventHandler(CustomModule_Init);
}
}
private void CustomModule_Init(object sender, EventArgs e)
{
Page Page = sender as Page;
if (!Page.Request.Url.ToString().Contains("mySessionExpired.aspx") &&
!Page.Request.Url.ToString().Contains("myLogin.aspx"))
{
if (HttpContext.Current.Session["encryptedUserId"] == null)
{
HttpContext.Current.Response.Redirect("../Modulenames/mySessionExpired.aspx", false);
}
}
}
}
everything is working fine , only issue is that its adding some kind of encryption in URL for which my Breadcrumbs are not working in the page. The url transforms like :
://thewebsite/Project/(S(jnd4o5ljdgs0vq1zd4niby4a))/Pages/mySessionExpired.aspx
no idea why this fragment of text has been added ... please help
--Attu
I'm tring to add an error message to a CustomValidator by catching a potentail script attack implementing IHttpHandler im using the below method, but it just seems to kill the page as the page ends up blank, any ideas?
public override void ProcessRequest(HttpContext context)
{
try
{
base.ProcessRequest(context);
}
catch (HttpRequestValidationException ex)
{
DisplayCustomMessageInValidationSummary("< or > characters are not allowed");
}
}
private void DisplayCustomMessageInValidationSummary(string message)
{
CustomValidator CustomValidatorCtrl = new CustomValidator();
CustomValidatorCtrl.IsValid = false;
CustomValidatorCtrl.ErrorMessage = message;
this.Page.Controls.Add(CustomValidatorCtrl);
}
Thanks
Darren
Back in the ASP classic days when i needed to write out the name/value pairs of forms submitted by POST i thru this loop into the page:
on error resume next
for each x in Request.Form
Response.AppendToLog x & "=" & Request(x)
next
It threw all the form fields and values into the log just as GETs are. Does IIS7 .net give me any better method? (this is for the dev/testing portion of the project i don't have any concern about the space or cycles used to accomplish this).
thx
You can create an http module to log all posts. It allows you to log outside of the pages, a single point of logging instead of having to add the logic to all pages where you want to log activity.
Here you have some of the code. You would have to avoid logging viewstate since is tons of useless information. So you have to add some logic to achieve this.
public class ActivityLogModule: IHttpModule
{
public void Init(HttpApplication application)
{
application.EndRequest += (new EventHandler(this.Application_EndRequest));
}
private void Application_EndRequest(Object source, EventArgs e)
{
HttpApplication application = (HttpApplication)source;
HttpContext context = application.Context;
if (RecordActivity(context))
{
ActivityLogger.Instance.Log(application.Context.User.Identity.Name,
application.Context.Request.Url.AbsoluteUri,
application.Context.Request.Form.ToString());
}
}
public void Dispose(){}
protected bool RecordActivity(HttpContext context)
{
if (!context.Request.RequestType.Equals("POST"))
{
return false;
}
return true;
}
}
You could have something like this:
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
LogPostValues();
}
private void LogPostValues()
{
string logPath = #"C:\PostedValuesLog.txt";
StringBuilder sb = new StringBuilder();
sb.AppendFormat("Logging: {0}", Request.Path);
sb.Append("Form Values");
foreach (string key in Request.Form)
{
string val = Request.Form[key];
sb.AppendFormat("{0} = {1}<br/>", key, val);
}
sb.Append(Environment.NewLine);
sb.Append("QueryString Values");
foreach (string key in Request.QueryString)
{
string val = Request.QueryString[key];
sb.AppendFormat("{0} = {1}<br/>", key, val);
}
sb.Append(Environment.NewLine);
sb.Append(Environment.NewLine);
sb.Append(Environment.NewLine);
File.AppendAllText(logPath, sb.ToString());
}
This is a crude method though and shouldn't really be used in production code. However, as this is just for development & testing, it should suffice to track what data is being posted to your page via the querystring and form.