The methods you will probably be using most are the relative URI methods, and they are shown in Listing 11.1.. Listing 11.1 Java Relative URI API static java.lang.String getRelativeUrija
Trang 1All the methods we use in this class are static methods The methods you will probably be
using most are the relative URI methods, and they are shown in Listing 11.1
Listing 11.1 Java Relative URI API
static java.lang.String getRelativeUri(java.lang.String path)
static java.lang.String getRelativeUri(java.lang.String path,
boolean encode)
static java.lang.String getRelativeUri(java.lang.String path,
java.util.Map<java.lang.String,java.lang.String> queryParams)
static java.lang.String getRelativeUri(java.lang.String path,
java.util.Map<java.lang.String,java.lang.String> queryParams,
java.lang.String fragment)
The relative URI methods each take in a path The path can come in two flavors: relative to
the context root or relative to the current script The context root relative path is denoted with a
starting / So, if our calling script was located at http://localhost:8080/path/uriutils.gt, we would
get the URIs shown in Listing 11.2
Listing 11.2 Using the Java Relative URI API
URIUtils.getRelativeUri("/images/happy.jpg"); evaluates to
/images/happy.jpg
URIUtils.getRelativeUri("images/happy.jpg"); evaluates to
images/happy.jpg
The leading / signals all the relative URI methods if your intention is to generate a URI that
is relative to the context root The API used in the preceding examples automatically encodes the
URI It is a convenience method for a call to the method that takes in a true boolean value for the
encode parameter, as shown in Listing 11.3
Listing 11.3 Using the Java Relative URI API
URIUtils.getRelativeUri("/space images/happy.jpg", true);
evaluates to /space%20images/happy.jpg
If, for some reason, you want to suppress the encoding, simply set the encode boolean
parameter to false The other variants of the API enable you to add parameters or a particular
fragment to the URI They are exemplified in Listing 11.4
Trang 2Listing 11.4 Using the Java Relative URI API
HashMap params = new HashMap<String,String>();
params.put("key0","value 0");
params.put("key1","value 1");
URIUtils.getRelativeUri("images/happy.jpg", params);
evaluates to images/happy.jpg?key1=value+1&key0=value+0
URIUtils.getRelativeUri("images/happy.jpg", params, "fragment");
evaluates to images/happy.jpg?key1=value+1&key0=value+0#fragment
As you can see, the methods allow for the creation of many different URIs for use in your
application There are analogous APIs to create absolute URIs, shown in Listing 11.5
Listing 11.5 Java Absolute URI API
static java.lang.String getAbsoluteUri(java.lang.String path)
static java.lang.String getAbsoluteUri(java.lang.String path,
boolean encode)
static java.lang.String getAbsoluteUri(java.lang.String path,
java.util.Map<java.lang.String,java.lang.String> params)
static java.lang.String getAbsoluteUri(java.lang.String path,
java.util.Map<java.lang.String,java.lang.String> params,
java.lang.String fragment)
URIs generated with this set of APIs return a string in the form of the following:
schema://server-name:port/context-root/[path][?query-string][#fragment]
The same rules apply for absolute URIs as for relative URIs If a path starts with a /, it
indi-cates that the URI should start from the context root If not, it will be relative to the current script
path If we call a script at http://localhost:8080/path/uriutils.gt, the following code will return, as
shown in Listing 11.6
Listing 11.6 Using the Java Absolute URI API
HashMap params = new HashMap<String,String>();
params.put("key0","value 0");
params.put("key1","value 1");
Trang 3URIUtils.getAbsoluteUri("images/happy.jpg");
evaluates to http://localhost:8080/path/images/happy.jpg
URIUtils.getAbsoluteUri("/space images/happy.jpg");
evaluates to http://localhost:8080/space%20images/happy.jpg
URIUtils.getAbsoluteUri("space images/happy.jpg", true);
evaluates to http://localhost:8080/path/space%20images/happy.jpg
URIUtils.getAbsoluteUri("space images/happy.jpg", false);
evaluates to http://localhost:8080/path/space%20images/happy.jpg
URIUtils.getAbsoluteUri("images/happy.jpg", params);
evaluates to
http://localhost:8080/path/images/happy.jpg?key1=value+1&key0=value+0
URIUtils.getAbsoluteUri("images/happy.jpg", params, "fragment");
evaluates to
http://localhost:8080/path/images/happy.jpg?key1=value+1&key0=value+0#f
ragment
As you can see, the absolute path URIs return similar results as their relative path
ana-logues Finally, the URIUtils enable us to get the current URI with the following API:
static java.lang.String getRequestedUri(boolean
includeQueryString)
With this URI, you can retrieve the current URI with or without including the query string,
as shown in Listing 11.7
Listing 11.7 Using the Java Requested URI API
URIUtils.getRequestedUri(false);
URIUtils.getRequestedUri(true);
If this code was called in for an application located here,
http://localhost:8080/path/uriutils.gt?key=value
the following URIs would be returned, as shown in Listing 11.8
Listing 11.8 Results of Using the Java Requested URI API
http://localhost:8080/path/uriutils.gt
http://localhost:8080/path/uriutils.gt?key=value
Trang 4There is also a convenience method for retrieving the URI without the query string,
shown here:
static java.lang.String getRequestedUri()
This API is the same as calling the previous API with false as the parameter In other words
URIUtils.getRequestedUri();
and
URIUtils.getRequestedUri(false);
are the equivalent
Groovy APIs
Groovy provides a similar set of APIs that work in the same way They are automatically
imported, so they don’t require extra work on your part to use them in your script You need to
call them only directly, without the static class name For example, Listing 11.9 shows the
rela-tive URI version of the URIs shown previously in Listing 11.6
Listing 11.9 Using the Groovy Relative URI API
def params = ["key0":"value 0","key1":"value 1" ]
getRelativeUri("images/happy.jpg");
evaluates to images/happy.jpg
getRelativeUri("/space images/happy.jpg");
evaluates to space%20images/happy.jpg
getRelativeUri("space images/happy.jpg", true);
evaluates to space%20images/happy.jpg
getRelativeUri("space images/happy.jpg", false);
evaluates to space%20images/happy.jpg
getRelativeUri("images/happy.jpg", params);
evaluates to images/happy.jpg?key1=value+1&key0=value+0
getRelativeUri("images/happy.jpg", params, "fragment");
evaluates to images/happy.jpg?key1=value+1&key0=value+0#fragment
The resultant relative URIs are the same as the Java versions Likewise, similar APIs are
available for absolute URIs and the requested URI
Trang 5PHP APIs
Some of this functionality is also provided by PHP using a similar set of APIs However, to
enable this functionality, you must add the URIUtils extension to the php.ini file by adding the
following line:
extension = zero.php.URIUtilsExtension
This enables three functions that can be directly called from PHP, as shown in Listing 11.10
Listing 11.10 PHP URIUtils API
get_absolute_uri(path);
get_relative_uri(path);
get_requested_uri([boolean includeQueryString]);
The PHP API doesn’t have as many convenience methods, but it can still get the job done
Specifically, you’ll have to append your own parameter and fragments In Listing 11.11, you’ll
see how it works and what it returns
Listing 11.11 Using the PHP URIUtils API
get_relative_uri("images/happy.jpg");
evaluates to images/happy.jpg
get_relative_uri("/space images/happy.jpg");
evaluates to /space%20images/happy.jpg
get_absolute_uri("images/happy.jpg");
evaluates to http://localhost:8080/path/images/happy.jpg
get_absolute_uri("/space images/happy.jpg");
evaluates to http://localhost:8080/space%20images/happy.jpg
get_requested_uri();
evaluates to http://localhost:8080/path/uriutils.php
get_requested_uri(true);
evaluates to http://localhost:8080/path/uriutils.php?key=value
get_requested_uri(false);
evaluates to http://localhost:8080/path/uriutils.php
Trang 6Validators
Caching content in HTTP improves application performance and can offload content delivery to
intermediate devices HTTP uses entity tags (ETags) and last-modified dates to identify content
and determine content expiration An ETag is meant to be used as a unique identifier for content
from a particular site, and the last-modified date indicates the currency of the content
Intermedi-ate devices, such as caching proxy servers, can use ETags to return cached content instead of
ini-tiating content generation on the back-end HTTP server ETags in association with the
last-modified date can also be used to conditionally render new content WebSphere sMash
pro-vides support called validators for generating ETags and last-modified dates
The creation of ETags is supported by the ETag Java class that is part of the WebSphere
sMash core An ETag is created from the concatenation of all time-sensitive content that is to be
set to the client For example, if we were building a service that returned an RSS feed that was
updated only occasionally, perhaps the ETag would be computed based on the titles of the feed If
we were building a stock feed resource, perhaps the ETag computation would consist of a
con-catenation of the stock symbol and the date-time stamp of the last price update We could also use
the complete content to be returned and compute the ETag if that is apropos In Listing 11.12, we
see an example of how to create an ETag and set it in the HTTP header
Listing 11.12 Creating an ETag Validator
import zero.core.etags.Etag
def onList()
{
def stockSymbol = "ACME"
def currentPrice = "127.50"
def currentDateTimeStamp = "09/05/2009"
def content = stockSymbol + currentDateTimeStamp
def etag = Etag.computeHashedValue(content);
Etag.setEtagHeader(etag);
}
If the preceding code is placed into a resource, we can try it on our web browser or any
other tooling In Figure 11.1, we’ve used the Poster add-in for Firefox to show the ETag that’s
been set by this code
The other validator provided by WebSphere sMash is the ability to set the last-modified
date in the HTTP header To set the last-modified date, you need to use the classes provided by
Java and then use the WebSphere sMash classes to format the date properly for use in the
last-modified header For example, in Listing 11.13, we generate a last-last-modified date and set it in the
header
Trang 7Figure 11.1 ETag set for resource
Listing 11.13 Creating the Last-Modified Header
import java.text.DateFormat
import zero.core.etags.Etag
def onList()
{
def currentDateTimeStamp = "09/05/2009"
DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
Date date = df.parse(currentDateTimeStamp );
request.headers.out.’Last-Modified’ = date.toString();
}
In Figure 11.2, we use Poster again to take a look at the last-modified header we’ve set with
our resource
As you can see, we now have a last-modified header set for our resource Using these
tech-niques will help your application’s performance and take a load off your back-end server IBM
Trang 8Figure 11.2 Last-modified set in Poster
WebSphere sMash also provides APIs for checking validators when presented Take a look at the
product documentation for further information
Active Content Filtering
Active Content Filtering (ACF) filters potentially harmful content from being displayed on the
user’s screen This can be used to prevent cross-site scripting Cross-site scripting (XSS) is a type
of website security vulnerability that enables the injection of potentially malicious content into a
web page or application The simplest incarnation of a cross site is nạve parameter handling
This is when developers neglect to verify that parameters passed to an application are valid input
and not some form of script In computer security, the people who attack sites and attempt to
exploit security holes left by developers are sometimes called “black hats” (in reference to old
western movies in which the bad guys tended to wear black cowboy hats) Let’s take a look at an
example of XSS, shown in Listing 11.14
Listing 11.14 Nạve Parameter Handling
<html>
<head>
<title>Test ACF</title>
</head>
<body>
Hello <%= request.params.name[] %>
</body>
</html>
Usually a parameter such as this would come from a form submit A typical user would
have submitted his or her name and the URL; for example:
http://localhost:8080?name=Bob
Trang 9Figure 11.4 JavaScript injection
Figure 11.3 Results of a regular user
This would result, as expected, in what is shown in Figure 11.3
A black hat user might try to inject active content, such as JavaScript:
http://localhost:8080?name=<script>alert("Bob was here!")</script>
The result of this JavaScript injection is not simply printing all the text that was part of the
name parameter The JavaScript alert function is executed in the client, the results of which are
shown in Figure 11.4
This is a pretty innocuous “malicious” attack that affects only the user experience of the
person making the attack However, if the parameter had been placed in a database and later
recalled in product comments, reviews, and other such user-submitted content, you could
imag-ine how this would affect your site
Malicious users can inject more than just JavaScript Any HTML tag can be used Other
good examples are the image and iframe HTML tags Combined with JavaScript, you could
liter-ally rewrite an entire page by injecting the right JavaScript and HTML tags into a page:
http://localhost:8080/?name=<iframe
src="http://www.acme.com"></iframe>
This could be used to discredit your site or misinform your users Perhaps the most
insidi-ous of all is to use JavaScript to simply redirect users away from your site:
http://localhost:8080/?name=<script>location.href=
Trang 10Figure 11.5 Dependencies tab
In this example, the site that your users were redirected to could look exactly like the one
they are used to Maybe it’s their online bank They attempt to login, and the black hats are
col-lecting user IDs, passwords, bank account numbers, and so on, all for their own nefarious uses
In WebSphere sMash, this is a fairly easy attack to prevent You simply need to add the
zero.acf dependency to the project In the Application Builder, go to the Dependencies tab, as
shown in Figure 11.5
When you’re on the Dependencies tab, click the Add button and the Add Dependency
dia-log will appear, as shown in Figure 11.6
In Figure 11.6, the ACF module, zero:zero.acf, is already in our repository We select
the module and then click Add It then shows up in our dependency list for the project If it’s not
there, you’ll need to click the Manage Repository button to add the ACF module to your
reposi-tory, as shown in Figure 11.7
In the Manage Repository dialog, type zero into the organization text box and zero.acf into
the module text box Next, click Search The list returns with a number of different versions of the
module Select the version that matches your version of WebSphere sMash; then click the <<
but-ton to add the module to your local repository After the module downloads, close this dialog, and
you can now add the module to your project from the Add Dependency dialog, as shown
previ-ously in Figure 11.6 When the ACF module is added to your dependencies, all parameters
com-ing into your application will be scanned for active content before your application has access to
them This completely eliminates any chance of cross-site scripting or other active content
dis-rupting your application If we go back and try what we showed in Figure 11.4, we now get a
dif-ferent result Figure 11.8 displays that result