ptg 252 Chapter 11 Framework Components All 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. Download from www.wowebook.com ptg URIUtils 253 Listing 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"); Download from www.wowebook.com ptg 254 Chapter 11 Framework Components URIUtils.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 Download from www.wowebook.com ptg URIUtils 255 There 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. Download from www.wowebook.com ptg 256 Chapter 11 Framework Components PHP 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 As you can see, these methods work exactly as the analogous methods in Groovy and Java. Download from www.wowebook.com ptg Validators 257 Validators 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-modified date and set it in the header. Download from www.wowebook.com ptg 258 Chapter 11 Framework Components Figure 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 Download from www.wowebook.com ptg Active Content Filtering 259 Figure 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 naï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 Naï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 Download from www.wowebook.com ptg 260 Chapter 11 Framework Components Figure 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= "http://www.acme.com"</script> Download from www.wowebook.com ptg Active Content Filtering 261 Figure 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. Download from www.wowebook.com . 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",. 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 space%20images/happy.jpg getRelativeUri("space images/happy.jpg", false); evaluates to space%20images/happy.jpg getRelativeUri("images/happy.jpg", params); evaluates