Regular Expression Redirects in Web Server 7

The Sun Java System Web Server 7 Technology Preview was released today! There's a whole bunch of new stuff in 7, and you can use it free of charge.

One of the features I worked on is the <If> tag. As its name implies, <If> makes things conditional. There's a lot of hidden power in the <If> tag, though, especially when combined with regular expressions. When you pair <If> with the redirect SAF, you get some of the flexibility of Apache HTTP Server's mod_rewrite module.

In Web Server, features such as URL forwarding are implemented as Server Application Functions (SAFs). Back in 1994 when Web Server was named Mosaic Netsite, Rob McCool checked in the first version of the redirect SAF. In the decade that followed, redirect learned how to deal with path parameters and query strings. Beyond that, it was largely unchanged.

The redirect SAF lets you redirect URIs that match a certain prefix. (A URI is the part of the URL a web browser sends in its HTTP request.) You specify that prefix with the from parameter and the URL to redirect to with the either the url or url-prefix parameters. In Web Server 7, the from parameter is now optional. If from is omitted, all URIs are redirected. Obviously, that's not particularly useful by itself, but it means you can use <If> to decide which URIs to redirect.

For example, you might have used the following directive in obj.conf in Sun ONE Web Server 6.1:

NameTrans fn="redirect"
          from="/docs"
          url="http://docs.sun.com"

With Sun Java System Web Server 7, you can use a regular expression instead of the from parameter:

<If $uri =~ '\^/docs'>
NameTrans fn="redirect"
          url="http://docs.sun.com"
</If>

Given the weird syntax and additional line, I guess that's not really an improvement.

However, suppose you want to do something a little fancier; maybe you want to redirect all requests for /docs/partnumber to http://docs.sun.com/source/partnumber/index.html. With the <If> tag and regular expressions, you can do that:

<If $uri =~ '\^/docs/(.\*)'>
NameTrans fn="redirect"
          url="http://docs.sun.com/source/$1/index.html"
</If>

Here, the <If> tag assigns whatever value matches (.\*) to the variable $1. The $1 in the url parameter is dynamically replaced with the value from the original request. That means the above obj.conf snippet will cause a request for /docs/817-6248 to be redirected to http://docs.sun.com/source/817-6248/index.html. (You can get even fancier. For example, if you added a second set of parentheses to your regular expression, <If> would also create a variable named $2 whenever the regular expression matched the requested URI.)

I mentioned that the combination of <If> and redirect offers only some of the flexibility of mod_rewrite. That's true. However, unlike mod_rewrite, <If> can be used for things other than redirecting and rewriting URLs. In fact, <If> can be used in conjunction with any SAF, including 3rd party plugins. All told, Web Server 7 now offers a superset of mod_rewrite's functionality.

In the coming weeks I hope to write about other ways to use <If> and introduce other new features in Web Server 7. Why not try it out and let me know what you think?

Comments:

Chris, Having a varialble redirect destination is really great feature! I assume that variables only works within current <If> tag. Can you share the list of other "global" variables (like $uri) that are available and can be used in obj.conf? Thanks a lot! Alexander aka ttalex

Posted by ttalex on May 31, 2006 at 02:49 AM PDT #

Actually, you can use variables in any obj.conf directive, even those outside of <If> containers. (The $1, etc. regular expression backreference variables are only defined inside an <If> container, of course, because that's the only place you can eveluate a regular expression.)

Here's a list of predefined variables:

  • $n - Regular expression backreference (value of the nth capturing subpattern, n = 1...9), e.g. $1
  • $& - Value that matched a regular expression
  • $auth_group - Authenticated user's group (Alias for $vars{'auth-group'})
  • $auth_type - Authentication method (Alias for $vars{'auth-type'})
  • $auth_user - Authenticated user name (Alias for $vars{'auth-user'})
  • $browser - Web browser version (Alias for $headers{'user-agent'} if the client sent a User-agent header or an empty string if it did not)
  • $chunked - Boolean that indicates whether request body was sent using chunked encoding
  • $code - Response status code
  • $cookie{'name'} - Value of cookie name from request
  • $dns - Alias for $client{'dns'}
  • $env{'name'} - Value of the environment variable name (includes CGI/SHTML environment variables)
  • $headers{'name'} - Value of name from rq->headers, i.e. value of request header name where name is a lowercase string
  • $id - Virtual server ID as specified by the name attribute of the virtual-server element in server.xml
  • $internal - Boolean that indicates whether request was internally generated
  • $ip - Alias for $client{'ip'}
  • $keep_alive - Boolean that indicates whether the connection will be kept open
  • $keysize - Alias for $client{'keysize'}
  • $method - Request method (Alias for $reqpb{'method'})
  • $path - Requested path (either URI, partial path, or file system path depending on stage)
  • $path_info - Alias for $vars{'path-info'}
  • $ppath - Alias for $vars{'ppath'}
  • $protocol - Request protocol (Alias for $reqpb{'protocol'})
  • $query - Request query string (Alias for $reqpb{'query'})
  • $reason - Response reason phrase
  • $referer - Alias for $headers{'referer'}
  • $reqpb{'name'} - Value of name from rq->reqpb
  • $restarted - Boolean that indicates whether request has been restarted
  • $secret_keysize - Alias for $client{'secret-keysize'}
  • $server_url - Prefix for self-referencing URLs
  • $time - Time the request was received as the number seconds since 00:00:00 UTC, January 1, 1970
  • $time_day - Day of the month when request was received, "01" - "31"
  • $time_hour - Hours since midnight when request was received, "00" - "23"
  • $time_min - Minutes after the hour when request was received, "00" - "59"
  • $time_mon - Month of the year when request was received, "01" - "12"
  • $time_sec - Seconds after the minute when request was received, "00" - "61"
  • $time_wday - Week day when request was received, "0" - "6", where "0" corresponds to Sunday
  • $time_year - Four digit year when request was received
  • $type - Alias for $srvhdrs{'content-type'}
  • $uri - URI of the requested resource (Alias for $reqpb{'uri'})
  • $url - URL of the requested resource
  • $urlhost - Hostname client connected to
  • $vars{'name'} - Value of name from rq->vars
  • $security - Boolean that indicates whether a secure transport was used
  • $senthdrs - Boolean that indicates whether response headers have been sent
  • $srvhdrs{'name'} - Value of name from rq->srvhdrs, i.e. value of response header name where name is a lowercase string

You can also define your own variables using the <variable> element in server.xml.

Posted by Chris Elving on May 31, 2006 at 01:47 PM PDT #

Chris, Really great info! Thanks alot!!!

Posted by ttalex on May 31, 2006 at 11:30 PM PDT #

Hi, How can I use the above settings for Web Server 6.1?

Posted by Michael on January 24, 2007 at 03:04 AM PST #

Michael, these features are new in 7.0. Unfortunately, that means you need to upgrade in order to use them.

Posted by Chris Elving on January 24, 2007 at 09:12 AM PST #

Where in the obj.conf file does the redirect go?

Posted by Karl on March 22, 2007 at 12:28 AM PDT #

You'd typically add a new NameTrans fn="redirect" directive as the first NameTrans directive below the <Object name="default"> line.

Of course, it depends on what you're trying to do. If you want other NameTrans directives to take precedence, they should be listed first. You could even put NameTrans directives in other <Object>s.

Posted by Chris Elving on March 22, 2007 at 12:39 AM PDT #

What does it mean when my inquiry entries on address come back with 'redir..' at the end. This is bothering. Thank you, BonnIE

Posted by BonnIE on March 31, 2007 at 08:00 PM PDT #

Chris, This is great functionality at last for Sun One. It does sound as if this is a redirect rather than a rewrite, is this the case? I'm developing a site where I would like the clean URIs to remain in the browser location bar as is possible using mod_rewrite on Apache, is this possible with Sun One 7, or will the server simply redirect away from the friendly URI to the "real" one underneath? Many thanks, James

Posted by James on April 30, 2007 at 12:09 AM PDT #

You're right, James, this blog entry was about redirecting, not URL rewriting. Fortunately, Sun Java System Web Server 7.0 can do URL rewriting, too.

In my examples, redirects were done using the redirect SAF. You can use all the same <If> and regex magic with the new restart SAF. The restart SAF will restart processing internally, telling the server to pretend that the request was actually for a different URI. (There's also a new rewrite SAF, but it's for the more specific task of rewriting one file system path to another. It's useful for mass virtual hosting, but you probably don't want to use it for pretty URLs.)

Here's a quick example:

<If $uri = '/index.html'>
NameTrans fn="restart" uri="/index.php"
</If>

Posted by Chris Elving on April 30, 2007 at 10:51 AM PDT #

Chris, Fantastic news, many thanks - I was thinking I'd have to make do with a 404 handler to do this but I was a bit uneasy about the performance implications of this. Will have a play this afternoon, and thank you for such a quick response, James

Posted by James on April 30, 2007 at 10:35 PM PDT #

Hi, We are trying to configure our SUN ONE webserver 6.1 to redirect a URL eg: http://server1.com?id=123 to http://server2.com?newid=123. As you can see, this would a manipulation of query string parameter. Can this be done on 6.1? Thanks.

Posted by Dheepak on July 13, 2007 at 07:16 AM PDT #

/\* this little program helps me to understand the parameters I can use \*/
/\* in the if conditionals in the obj.conf \*/

/\* compile string: \*/
/\* cd <server_root>/samples/nsapi \*/
/\* cc -DNET_SSL -DSOLARIS -D_REENTRAN -DMCC_HTTPD -DXP_UNIX -DSPAPI20 -I../../include -c show_var.c \*/
/\* ld -G show_var.o -o show_var.so \*/

/\* insert following in magnus.conf: \*/
/\* Init fn="load-modules" shlib="<server_root>/samples/nsapi/show_var.so" funcs="show_var \*/

/\* insert following in obj.conf: \*/
/\* <If $uri =~ "\^/show_var"> \*/
/\* NameTrans fn="show_var" var="<VARIABLE TO DISPLAY>" \*/
/\* </If> \*/

/\* example of var: \*/
/\* "uri = $uri<br>url = $url<br>urlhost = $urlhost<br>ip = $ip<br>dns = $dns" \*/

#ifdef XP_WIN32
#define NSAPI_PUBLIC __declspec(dllexport)
#else /\* !XP_WIN32 \*/
#define NSAPI_PUBLIC
#endif /\* !XP_WIN32 \*/

#include <stdio.h>
#include <stdlib.h>
#include "nsapi.h"

int msg_and_exit(char \*msg, Session \*sn, Request \*rq) {

if (pblock_findval("content-type", rq->srvhdrs))
param_free(pblock_remove("content-type", rq->srvhdrs));
pblock_nvinsert("content-type", "text/html", rq->srvhdrs);

protocol_status(sn, rq, PROTOCOL_OK, NULL); // 200 response

protocol_start_response(sn, rq);

if (net_write(sn->csd, msg, strlen(msg)) == IO_ERROR)
return REQ_EXIT;
net_flush(sn->csd);

return REQ_PROCEED;
}

NSAPI_PUBLIC show_var(pblock \*pb, Session \*sn, Request \*rq) {

char \*var,\*msg;
int len;

msg = (char \*) MALLOC(1024);

/\*check program arguments\*/
var = pblock_findval("var",pb);
if (!var) {
len = util_sprintf(msg,"Program Error: Misconfigured\\n");
return msg_and_exit(msg,sn,rq);
}

len = util_sprintf(msg,"<html><body><h1>%s</h1></body></html>\\n",var);
return msg_and_exit(msg,sn,rq);
}

Posted by Curzio Della Santa on June 19, 2008 at 06:03 PM PDT #

Curzio, that's a neat idea, but you probably should not deploy that NSAPI plugin on a production website. It contains a potential buffer overflow that could allow an attacker to take control of the web server. It also doesn't HTML encode its output, so it could be used to launch cross-site scripting attacks.

Posted by Chris Elving on June 25, 2008 at 09:12 AM PDT #

I have avery specific query::

I am using Sun AM 7 + Webserver 7
AM is configured to protect "\*" i.e ALL apps are protected.

I give the following in "default" tag in obj.conf

<If $uri =~ '\^/myAppContext'>
NameTrans fn="redirect" url="http://abcserver001.clientdomain.com:4567/myAppContext"
</If>

The sso page has stopped comming & it directly takes me to the application first page. I.e. without asking for user / pwd.

Is there any other step I need to do ?

/Cheers

Posted by kanwaljit singh on July 01, 2008 at 09:49 PM PDT #

We got it working for the CU with help from Web Server team.

Posted by kanwaljit singh on January 26, 2009 at 01:42 PM PST #

Post a Comment:
  • HTML Syntax: NOT allowed
About

elving

Search

Categories
Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today