Search code examples
java.netproxyurl-rewritingreverse-proxy

Reverse Proxy: Accessing .Net Web Application from Java Web Application


So here is the scenario which we have/want to implement:

  1. We have a java spring based web application deployed on apache tomcat.
  2. In our web application we will provide a 3rd party web application link which is .net based to user. On click of which user will be redirected to .net application but the domain and context root shown in the browser url will remain same that is of java application.
  3. We cannot ask 3rd party team to change anything in their application.
  4. Whatever we have to change should be in our code, also as far as we could we should refrain ourself from any apache tomcat level changes.

Here are the things which we implemented so far:

  1. We tried to implement reverse proxy using following link: https://github.com/mitre/HTTP-Proxy-Servlet
  2. So the basic funda was to call the 3rd party url as a webservice and edit the httpresponse and add our domain and context path to the urls in any file received as response. Though this is not a good solution and consumes lot of time and space but it does the job.

Issue Which we are facing:

  1. Everything is working fine except the ajax request in the .net application.
  2. The Error thrown is: Sys.WebForms.PageRequestManagerParserErrorException: The message received from the server could not be parsed. Common causes for this error are when the response is modified by calls to Response.Write(), response filters, HttpModules, or server trace is enabled.

Here is the code fragment for doing httpresponse modification task:

protected void copyResponseEntity(HttpResponse proxyResponse, HttpServletResponse servletResponse,
                                    HttpRequest proxyRequest, HttpServletRequest servletRequest)throws IOException {
  
    HttpEntity entity = new BufferedHttpEntity(proxyResponse.getEntity());
    if (entity.isChunked()) {
        InputStream is = entity.getContent();
            String proxyBody = EntityUtils.toString(entity);
              proxyBody = proxyBody.replaceAll("/.netContextRoot/", "/ourContextRoot/.netContextRoot/");
    
            InputStream stream = new ByteArrayInputStream(proxyBody.getBytes(StandardCharsets.UTF_8));
    
            OutputStream os = servletResponse.getOutputStream();
            byte[] buffer = new byte[10 * 1024];
            int read;
            while ((read = stream.read(buffer)) != -1) {
              os.write(buffer, 0, read);
              if (doHandleCompression || stream.available() == 0 /* next is.read will block */) {
                os.flush();
              }
            }
            // Entity closing/cleanup is done in the caller (#service)
          } else {
    
            String proxyBody = EntityUtils.toString(entity);
            proxyBody = proxyBody.replaceAll("/.netContextRoot/", "/ourContextRoot/.netContextRoot/");
    
            EntityUtils.updateEntity(proxyResponse, new StringEntity(proxyBody));
            HttpEntity entity2  =  proxyResponse.getEntity();
    
            OutputStream servletOutputStream = servletResponse.getOutputStream();
    
            entity2.writeTo(servletOutputStream);
    
    }
}

Can anybody help us out with this scenario, Also if you have any other solution without making any changes in apache level then pls do mention.

Thanks in Advance.


Solution

  • I finally found some answers to dodge PageRequestManagerParserErrorException.

    1. You can refer this link if you are allowed to make changes in 3rd party application:Do read the comments for better understanding.
    2. You can create a new application for only reverse proxy purpose having contextroot name same as the 3rd party's context root and deploy it in your applications domain, so you will not have to edit the body content of http response for setting up your application path. And then you can call this application from your older one as both will be in same domain.
    3. I did dig up a little bit in the PageRequestManagerParserErrorException and some how found out a flow, The event validation of .net triggers PageRequestManagerParserErrorException when it comes to know that you have edited the httpresponse and the logic they have used is that they just check up the length of httpresponse with the actual length of httpresponse. So if you somehow manage to edit the httpresponse without changing the response's length then boom You have achieved the task.

    Note:

    a) You can use this link to achieve reverse proxy: As this has only code level change, so its very simple to achieve and also there is no server level config changes required.

    b) PageRequestManagerParserErrorException occurs when you edit httpResponse before sending it to client and its triggered by eventValidation of .net.

    c) 1st solution is useless if you are not allowed to make any change in the 3rd party application just like mine scenario. For time being I went with the 3rd one as it did the job without much effort.