Skip to Content
Author's profile photo Ariel Bravo Ayala

HTTP redirections in CPI

HTTP redirects are an everyday thing when it comes to visiting websites, mostly used in the form of URL redirections. Although HTTP redirects in API consumption are not as massive, they are still frequent. In this blog we will review, redirections in sender and receiver scenarios.

A little background

HTTP redirections are used for different purposes: to load balancing, to maintain backward compatibility, whilst a maintenance work is being done, etc. To a request, the server will respond with a 3XX HTTP code accompanied by a “Location” header, which is the new URL to be accessed.

There is a large list of precautions before following redirections: validation of cyclical calls, redirections to unencrypted sites, malicious redirections, method used, and so on. Due to these caveats, it is not surprising that CPI by default does not follow the redirects and instead, throws an exception (in fact, there is a escalation event, that allows you to classify this error for a consumer of alerts). Then, what if you -need- to follow a redirection? (side-note: as CPI is constantly evolving, this could be enabled directly by SAP in a future release)

 

1.- Following a redirection

In apache Camel, is not difficult to include and configure a clientConfig option for the AHC component. This configuration, will allow us to enable the redirections. However, I must confess that I couldn’t manage to configure this in CPI, as the communication channels temporarily overwrite the “CamelHttpQuery” header prior to a request execution. (If you have an idea, leave it in the comment section!)

Is there any workaround? Yes. For instance, it is possible to write a groovy script and handle the redirections there. The following script should follow a redirection. Please, consider this a simple/reference snippet as you should include the considerations given by the HTTP standard. Also, the used class (HttpURLConnection) also has features to deal with redirections.

def getRedirectedURL(originalUrl, httpMethod, currentHop, maxHops) {
	if (currentHop == maxHops) {
		throw new RuntimeException('Ops! Too many hops');
	}
	currentHop += 1;
	HttpURLConnection conn = new URL(originalUrl).openConnection();
	conn.setInstanceFollowRedirects(false); //We want to "explore" the redirections, so we can check them one-by-one
	conn.requestMethod = httpMethod; //Consider checking only "Safe-Methods"
	//Here you may validate whether the target URL is a "Safe" URL: Host, HTTPS, etc. (ValueMapping?)
		if(conn.responseCode in [301,302,307,308]) { //some redirections may changes the Http Method! (301,302)
		if (conn.headerFields.'Location') {
		  def targetUrl = conn.headerFields.Location.first();
		  DirtyLog.jumpList += targetUrl + "\n";
		  return getRedirectedURL(targetUrl,httpMethod,currentHop, maxHops);
		}
		else {
			throw new RuntimeException('Failed to retrive target URL');
		}
	}
	return originalUrl;
}

In my proof of concept, I’m using this script during the exception raised by CPI.

Original exception:

iFlow with the exception subprocess, using the script:

For my own testings, I’ve created a quick-n-dirty redirector app in NodeJs, you can download it from the following GitHub repository

 

2.- Redirecting from CPI

The early days of the then called “HCI” are now behind us… and in their passing, their left us with a naming conventions mess (with a few honorable exceptions and definitely not me!). A use case of HTTP redirections is to use them to correct and normalise endpoints while maintaining compatibility. (Assuming that the clients are able to handle redirections!)

An over simplified redirection implementation, simply requires to return an HTTP code 3XX and the target Location.  You can create you own groovy script to analyse things such us the http method, the path, etc. The following iFlows returns the code and location set by a content modifier and as a result, the client is redirected to a different iFlow:

 

As a result, Postman is being redirected and it consumed both iFlows:

Note the HTTP code: 200, this is the code provided by the second iFlow. On the other hand, by changing the default behaviour of Postman, is possible to ignore redirections. In this case, the second iFlow is not being called:

 

 

For more information, have a look into the HTTP standard:

https://tools.ietf.org/html/rfc7231#page-54

And this easy to read documentation:

https://developer.mozilla.org/en-US/docs/Web/HTTP/Redirections

Assigned Tags

      5 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Hari Sonnenahalli
      Hari Sonnenahalli

      Bravo-

      Hope all is well. I have a question regarding the redirecting http request in CPI. I have a scenario in which I need to make a call to get the redirect link and then download a GZIP file. I am trying to use your script but am unable to achieve the redirect. I am using the your script after first HTTP call. Please find the screenshot in the attachment. I think am missing something. Please it would be appreciated if you can help me with issue.

      Regards

      HS

       

      Author's profile photo Ariel Bravo Ayala
      Ariel Bravo Ayala
      Blog Post Author

      Hi, I appreciate this message comes long after your question, the problem I see is that you need to get the redirection URL before calling the request reply. Otherwise the request reply would end in an error.

      Author's profile photo Hari Sonnenahalli
      Hari Sonnenahalli

      Yes that is exactly I need help in doing it.

       

      Thankss

       

      HS

      Author's profile photo Raffael Herrmann
      Raffael Herrmann

      Hi Ariel,

      it's not directly related to the articles topic, but what is this "DirtyLog"-class you're using in the Groovy script? I couldn't find any JavaDocs nor information where we can see information written to these "logs".

      Best regards,
      Raffael

      Author's profile photo Shashank Mahajan
      Shashank Mahajan

      Hi Ariel,

      Nice post. Now that at the HTTP Adapter level we have a flag "Throw Exception On Failure" available, do you think we can leverage that for handling redirection? Say we uncheck that flag and use a routing condition to check if in response headers we have a 'Location' header available, we go ahead making another HTTP request but this time with the URL sent in the 'Location' response header.
      If you think it is a good idea, perhaps you can incorporate that as a workaround in your blog post since I'm sure it'll help the community as well.