Wednesday, March 06, 2013

Rewriting URL in Domino using DSAPI

I will briefly describe what we were aiming to achieve. In order to open page with parameters Domino requires to add ?open or ?opendocument action and only after that Domino allows to add parameters. It's quite annoying for us due to some integration with another systems, those systems expect they can simply add parameters just after our pages, i.e.: http://www.host/page?parameter=123 etc. Also important reason - we simply do not like this ?open or ?opendocument in URL.

we want to be able to that:
www.host/page?opendocument&parameter=123 ==> www.host/page?parameter=123

I got couple helpful comments in my previous article about URL control in Domino, that helped me to look on different solutions, thanks guys. However I decided that those solutions a bit complicated to setup and they could do some impact on page load time.

I've been working on DSAPI solution last days and finally with some help I've made it! Now we have full control with our URLs, at least I've such feeling :). Let me share my small success to all of you.

Here you can find main steps you need to do. Please keep in mind, I've updated my code a bit as our logic has many rules when exactly to add parameters.

1. Enable flag to catch Rewrite URL event.
filterInitData->eventFlags = kFilterRewriteURL;
2. Link 'rewrite URL' event with you function.
DLLEXPORT unsigned int HttpFilterProc(FilterContext* context, unsigned int eventType, void* eventData) {
 switch (eventType) {
  case kFilterRewriteURL:
   return RewriteURL(context, (FilterMapURL *) eventData);
  default:
   return kFilterNotHandled;
 }
}
3. Finally the main logic, that makes URL rewriting.
int RewriteURL(FilterContext* context, FilterMapURL* pEventData) {
 FilterParsedRequestLine pReqData;
 unsigned int errid=0;

 // if there are no parameters in URL - nothing to do.
 if (strstr(pEventData->url, "?")==NULL) return kFilterNotHandled;
 // read request as we are going to update query.
 context->ServerSupport(context, kGetParsedRequest, &pReqData, NULL, NULL, &errid);
 // if query starts from opendocument - nothing to do
 if (strncmp(pReqData.pQueryUri, "opendocument", strlen("opendocument"))==0) return kFilterNotHandled;
 // adding opendocument before query and put result in pEventData->pathBuffer
 sprintf(pEventData->pathBuffer, "%s?opendocument&%s", pReqData.pPathUri, pReqData.pQueryUri);

 return kFilterHandledEvent;
}
Solution we did works like a charm and what is very important it does not affect page load time (we measured of course)

Related topics
DSAPI for Domino
Solution for Lotus Domino to the trailing slash problem
Replacement for DSAPI in Java/XPages

10 comments :

David Marko said...

Hello, maybe I misss the point but I think doing ...
www.host/page?opendocument&parameter=123 ==> www.host/page?parameter=123

... can be achieved using internet sites and substitution. We use this technique for many similar substitutions like www.host.cz/products/product-slug-name converts internaly to www.host.cz/apps/app.nsf/product.xsp?productname=product-slug-name .

For your case you should be able to define following substitution:

source: www.host/page?parameter=*
target: www.host/page?opendocument&parameter=*

In browser the user can use URL without ?openDocument, but internal this URl will be used ...

David Marko

Dmytro said...

I do not think it is possible. I ofc tried to use something like:

Incoming URL pattern: /header1?parameter=*
Replacement pattern: /test.nsf/all/header1?opendocument&parameter=*

it does not work. Your case (with www.host.cz/products/product-slug-name) will work, because you initial URL does not have parameters and as far as I know substitutions do not care about parameters. That is why we can't manage url with '?params' etc.

f.x. such case would work for us

Incoming URL pattern: /header1-*-*
Replacement pattern: /test.nsf/all/header1?opendocument&p1=*&p2=*

Dmytro said...

David could you please look if you have any example/demo where you do subst. with parameters? it would help me a lot :)

David Marko said...

Hmm, seems to be you are right. Just checked and we only used incoming URLs without '?' ... it was mostly the reason for substitution to make pretty URLs and avoid question marks. But never realised the '?' cant be used. The question mark is really treated in strange way as url path after question mark is completely omitted. I tried this example:

incoming: /create/shortcut*
replacement: /url_shortener.nsf/create_shortcut.xsp?n=*

For browser url like this: /create/shortcutXXX?n=12 it replaces 'n=*' with 'n=XXX' only ... so it really ignores question mark and everything behind ...

Dmytro said...

thanks for trying, I appreciate this. Anyway you know what to do now in such case, DSAPI can manage that

Petter Kjeilen said...

I have not tried this, but it could be worth a shot..

Have you tried setting DominoXURLProcess=1 in Notes.ini which will enable a Domino Web server's URL command parser to accept '!' as an alternative query component separator.

You can then try to use ! instead of ? in your substitution url

Dmytro said...

even if that work, that will not solve our problem.
We wanted to use special tracking system that adds by default '?utm_expid=12312312'. We are not able to control that external system so no chance for us to add ! instead of ?.

However thanks for tip, I will try anyway and get back in post about it.

Mark Demicoli said...

It's sad that there are very few tools that make use of this very powerful technique (DSAPI). Someone should write a rules-based engine for dealing with incoming URLS, or even an intruder-detection system for Domino (eg. Repeated bad URLs from an IP address triggers an alert. etc).

:) Just a thought.

Unknown said...

Do you have the DSAPI dll available for download?

I'm trying to integrate Dropbox to Notes/Domino, but their webhook uses a '?challenge=' as a part of the URL. And Even in Domino 10 I can't substitute the questionmark.

As the Dropbox do not accept a 301 redirect, I can't rewrite the url in cloudflare either.

This could really help me :-)

Dmytro said...

Hi Christian,

I have a project on github: https://github.com/dpastov/domino-dsapi-handler
there is also explanation how to build DLL (since it depends on your windows version).

If you need my assistance let me know.

p.s. I live in Dennmark (CPH) :-)