tag:blogger.com,1999:blog-60640957635809902024-03-13T12:17:40.926-06:00Perimeter SweepSoftware Development: Tips and How-to'sGary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.comBlogger84125tag:blogger.com,1999:blog-6064095763580990.post-16118620212084510572013-02-13T20:27:00.000-07:002013-02-13T20:27:09.397-07:00A View on Premature OptimizationSlow learner that I am - it took me some time to realize my own perspective on so-called "premature optimization":<br />
<br />
<i>Deciding against doing something because you're certain it won't help is just as premature an optimization as choosing to <b>do</b> something because you're certain it will help.</i><br />
<i><br /></i>
That came recently in the context of a discussion with colleagues around the tradeoffs in an HTTP caching design - in particular, does the latency you lose with validation-based caching responses (i.e. all the additional round trips, albeit with zero content length) rule out its use? One could speculate that yes, it does; but I would claim to not know without first measuring - and measuring within the parameters of the particular application in question.<br />
<br />
And I guess that's my whole point. Assuming you've already optimized before testing/measuring with a well-known scalability strategy (one that balances round-trip latency cost with up-to-date staleness benefit) is a premature conclusion.<br />
<br />
Measure first.Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-46021677455413407612011-11-16T09:55:00.005-07:002011-11-16T10:06:15.634-07:00HTTP Caching 101<span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 17px;">This captures a basic learning curve around HTTP Caching, actually just a selected subset of a rather large topic. Another post driven by laziness - written in terse talking-point style, with most information either paraphrased or copied explicitly from the resources listed at end - with a touch of editorializing on my part. My thanks to those authors upfront.</span><br />
<div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"></div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-Overview"></a>Overview</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Benefits</b>: save bandwidth, reduce latency, lighten server load</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Types</b> of caches (server's responses can be cached by these)</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">gateway cache (shared): middle-man, facade in front of a server (for any client). This caches responses from one server for many clients.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">browser cache (private): for BACK button, images, etc. This caches responses from many servers for one particular client.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">proxy cache (shared): forward-facing towards web, client-side. This caches responses from many servers for many clients.</li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Here's some decent <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.slideshare.net/rtomayko/https-bestkept-secret-caching" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">slideware</a></span> with boxes and lines illustrating the above, and with some sequence diagrams illustrating the protocols discussed below.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Mechanisms</b></div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Expiration, Validation and Invalidation</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">note that caching is applied only to GET and HEAD</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">...this is yet another reason not to tunnel operations thru GET, etc abuse - requests won't make it to server w/proxy cache in play</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">and, another reason to use all verbs as intended: POST, PUT and DELETE <em>should</em> not ever be cached</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">in fact, POST, PUT and DELETE <em>should</em> result in cached content being <em>invalidated</em></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Pragma</b>: no-cache - don't bother; from <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://palisade.plynt.com/issues/2008Jul/cache-control-attributes/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://palisade.plynt.com/issues/2008Jul/cache-control-attributes/</a></span>:</div><div class="panel" style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: rgb(187, 187, 187); border-bottom-left-radius: 5px 5px; border-bottom-right-radius: 5px 5px; border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(187, 187, 187); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(187, 187, 187); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(187, 187, 187); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-top-style: solid; border-top-width: 1px; color: black; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; overflow-x: hidden; overflow-y: hidden; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><div class="panelContent" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 0.95em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 10px; padding-right: 10px; padding-top: 0px; text-align: left;"><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left;">“pragma: no-cache” is linked to requests, and not responses. The RFC did not specify the behavior of this directive for responses. Hence, this directive does NOT instruct the browser not to cache a page. We often see this tag being misused when a page is served to the browser. Developers mistakenly set this directive expecting that the page will not be cached on the browser.</div></div></div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span class="Apple-style-span" style="color: #333333; font-size: 10pt; font-weight: normal; line-height: 17px;">The sections of the HTTP 1.1 spec (<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.w3.org/Protocols/rfc2616/rfc2616.html" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.w3.org/Protocols/rfc2616/rfc2616.html</a></span>) that discuss caches include 13, 14.9, 14.19, 14.21, and 14.24-29.</span></h4><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-TargetProtocols"></a>Cache Control</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Here's a subset of the cache-control mechanism to be discussed here:</div><div class="code panel" style="background-attachment: initial; background-clip: initial; background-color: white; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: rgb(187, 187, 187); border-bottom-left-radius: 5px 5px; border-bottom-right-radius: 5px 5px; border-bottom-style: dashed; border-bottom-width: 1px; border-left-color: rgb(187, 187, 187); border-left-style: dashed; border-left-width: 1px; border-right-color: rgb(187, 187, 187); border-right-style: dashed; border-right-width: 1px; border-top-color: rgb(187, 187, 187); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-top-style: dashed; border-top-width: 1px; color: black; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; overflow-x: auto; overflow-y: auto; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><div class="codeContent panelContent" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 0.95em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 10px; padding-right: 10px; padding-top: 0px; text-align: left;"><div><div class="syntaxhighlighter nogutter java" id="highlighter_264513" style="background-color: white !important; font-size: 1em !important; margin-bottom: 1em !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 1em !important; overflow-x: auto !important; overflow-y: auto !important; position: relative !important; width: 923px;"><table border="0" cellpadding="0" cellspacing="0" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; clear: left; color: #333333; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: 923px;"><tbody style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">
<tr style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: #333333; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;"><td class="code" style="background-attachment: initial !important; background-clip: initial !important; background-color: white; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-style: dashed; border-bottom-width: 0px !important; border-color: initial !important; border-left-style: dashed; border-left-width: 0px !important; border-right-style: dashed; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-style: dashed; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: #333333; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: 923px;"><div class="container" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 0px !important; padding-top: 0px !important; position: relative !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;" title="Hint: double-click to select code"><div class="line number1 index0 alt2" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">non-cacheable:</code></div><div class="line number2 index1 alt1" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">HTTP/</code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">1.1</code> <code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">200</code> <code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">OK</code></div><div class="line number3 index2 alt2" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">Cache-Control: no-cache,no-store</code></div><div class="line number4 index3 alt1" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"></div><div class="line number5 index4 alt2" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">user-specific </code><code class="java keyword" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(127, 0, 85) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: bold !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">private</code><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">:</code></div><div class="line number6 index5 alt1" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">HTTP/</code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">1.1</code> <code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">200</code> <code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">OK</code></div><div class="line number7 index6 alt2" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">Cache-Control: </code><code class="java keyword" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(127, 0, 85) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: bold !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">private</code><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">,no-cache,no-store</code></div><div class="line number8 index7 alt1" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"></div><div class="line number9 index8 alt2" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">cacheable:</code></div><div class="line number10 index9 alt1" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">HTTP/</code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">1.1</code> <code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">200</code> <code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">OK</code></div><div class="line number11 index10 alt2" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">Cache-Control: max-age=</code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">3600</code><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">,must-revalidate</code></div><div class="line number12 index11 alt1" style="background-attachment: initial !important; background-clip: initial !important; background-color: white !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0em !important; padding-right: 1em !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; white-space: pre-wrap !important; width: auto !important;"><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">Date: Sun </code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">16</code> <code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">Oct </code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">2011</code> <code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">15</code><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">:</code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">30</code><code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">:</code><code class="java value" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: rgb(0, 153, 0) !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">00</code> <code class="java plain" style="background-attachment: initial !important; background-clip: initial !important; background-color: initial !important; background-image: none !important; background-origin: initial !important; background-position: initial initial !important; background-repeat: initial initial !important; border-bottom-left-radius: 0px 0px !important; border-bottom-right-radius: 0px 0px !important; border-bottom-width: 0px !important; border-color: initial !important; border-left-width: 0px !important; border-right-width: 0px !important; border-style: initial !important; border-top-left-radius: 0px 0px !important; border-top-right-radius: 0px 0px !important; border-top-width: 0px !important; bottom: auto !important; box-sizing: content-box !important; color: black !important; float: none !important; font-family: Consolas, 'Bitstream Vera Sans Mono', 'Courier New', Courier, monospace !important; font-size: 1em !important; font-style: normal !important; font-weight: normal !important; height: auto !important; left: auto !important; line-height: 1.2em !important; margin-bottom: 0px !important; margin-left: 0px !important; margin-right: 0px !important; margin-top: 0px !important; min-height: inherit !important; outline-color: initial !important; outline-style: initial !important; outline-width: 0px !important; overflow-x: visible !important; overflow-y: visible !important; padding-bottom: 0px !important; padding-left: 0px !important; padding-right: 0px !important; padding-top: 0px !important; position: static !important; right: auto !important; text-align: left !important; top: auto !important; vertical-align: baseline !important; width: auto !important;">GMT</code></div></div></td></tr>
</tbody></table></div></div></div></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Here's a summary on the semantics of the header values listed above ( the first explanation section of each directive comes from <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.mnot.net/cache_docs/#CACHE-CONTROL" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.mnot.net/cache_docs/#CACHE-CONTROL</a></span>, with subsequent text coming from section 14.9 of the HTTP 1.1 spec):</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>no-cache</b> — forces caches to submit the request to the origin server for validation before releasing a cached copy, every time. This is useful to assure that authentication is respected (in combination with public), or to maintain rigid freshness, without sacrificing all of the benefits of caching. From the spec: This allows an origin server to prevent caching even by caches that have been configured to return stale responses to client requests. (Note that it's possible to specify field-names for this header that can apply more fine-grained meaning to the intended behavior; see section 14.9.1 for details.). However, a point of interest from <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://palisade.plynt.com/issues/2008Jul/cache-control-attributes" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">this article</a></span>:</div><div class="panel" style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: rgb(187, 187, 187); border-bottom-left-radius: 5px 5px; border-bottom-right-radius: 5px 5px; border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(187, 187, 187); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(187, 187, 187); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(187, 187, 187); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-top-style: solid; border-top-width: 1px; color: black; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; overflow-x: hidden; overflow-y: hidden; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><div class="panelContent" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 0.95em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 10px; padding-right: 10px; padding-top: 0px; text-align: left;"><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left;">“no-cache” directive, according to the RFC, tells the browser that it should revalidate with the server before serving the page from the cache..."no-store" tells the browser not only not to cache the page, but also not to even store the page in its cache folder. Whenever you’re serving a sensitive page, this is the cache control directive to use. Notice that of late, “cache-control: no-cache” has also started behaving like the “no-store” directive. To be on the safer side, we recommend that you use both “no-cache” and “no-store” when serving sensitive pages.</div></div></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>no-store</b> — instructs caches not to keep a copy of the representation under any conditions.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>private</b> — allows caches that are specific to one user (e.g., in a browser) to store the response; shared caches (e.g., in a proxy) may not.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>max-age=</b><b><seconds></seconds></b> --- specifies the maximum amount of time that a representation will be considered fresh. Similar to Expires, this directive is relative to the time of the request, rather than absolute. <seconds> is the number of seconds from the time of the request you wish the representation to be fresh for. From the spec: implies that the response is cacheable (i.e., "public") unless some other, more restrictive cache directive is also present. If a response includes both an Expires header and a max-age directive, the max-age directive overrides the Expires header, even if the Expires header is more restrictive. (Note that max-age can also be specified in a request from the client; the meaning here is, from section 14.9.3, that the client is willing to accept a response whose age is no greater than the specified time in seconds. There are also max-stale and max-fresh directives that further refine the user-agent's intentions; see section 14.9.3 for details.). Note that setting max-age to zero ensures that a page is never served from cache, but is always re-validated against the server.</seconds></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>must-revalidate</b> — tells caches that they must obey any freshness information you give them about a representation. HTTP allows caches to serve stale representations under special conditions; by specifying this header, you’re telling the cache that you want it to strictly follow your rules.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">What follows here is a general discussion of the Expiration and Validation models.</div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-Expiration"></a>Expiration</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">With expiration, you tell the cache how long should a response be considered "fresh", i.e. on expiration it becomes "stale". This is more efficient than validation since cache need not go back to origin server until staleness.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Expires</b></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">This is useful for long-lived static images, and things that change on regular schedule. It's not without its problems: </div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">server/client clocks must be in sync</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">times are in one-second resolution</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">you might forget to update date after expiration</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">spec prohibits Expires date more than one year in future</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">it's not useful for dynamic content</li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Cache-Control</b> (i.e. max-age, s-max-age (shared caches only))</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">to address limitations of Expires</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">relative vs absolute time frames</li>
</ul><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-Validation"></a>Validation</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">With the validation model, the cache asks the origin server on each request if its cached response is still valid. This is probably the best option for dynamic content.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>ETag/If-None-Match</em></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">You can think of ETag as a hash, fingerprint, etc. unique ID for a given page, resource, etc. Use this when it's inconvenient to store modification dates, or when the 1-second resolution of HTTP expiration model is not good enough, etc. </div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">An ETag can be <em>strong</em> or <em>weak</em> - in a nutshell, strong means the response can be used to compose a larger response, i.e. it's valid as a partial piece of content; whereas weak means you should expect to use the response to reliably compose larger pages (etc.). If a request contains an If-None-Match header with a value equal to the ETag for the given resource, the response simply contains a 304-Not Modified response status with an empty body; this is useful for bandwidth savings. If any intermediary cache must go back to the origin server for validation, a useful implementation to consider on that origin server involves saving the ETag (in database, key-value store, in-memory hashmap, etc.) on a per-URL (etc.) basis, to additionally save on CPU (i.e. the ETag need not be recomputed on each request).</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Note that there is a fair amount more to the ETag-based validation model than discussed here. Please consult the RFC for more details.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>Last-Modified/If-Modified-Since</em></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">A date-based approach to validation can be done with the Last-Modified/If-Modified-Since protocol. Similar to ETag, the server might save the modification dates for a given resource (URL, etc.) and compare that with any request header value for If-Modified-Since, again returning 304-Not Modified if the resource has not been modified since that given date. Again, savings in bandwidth can be gained here.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>Combining ETag with Last-Modified</em></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">There's a fair amount of ambiguity in blogs and web articles around what the behavior should be when requests send both types of validation headers and the server side supports both. To make things worse, the RFC 2616 is not the easiest specification to understand (in fact, there's an effort underway to improve that with a <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://tools.ietf.org/wg/httpbis/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">rewrite</a></span>). I'm basing my interpretation on my own careful read of RFC 2616; you are invited to correct me if you believe I've got it wrong - note in the following that "server must execute the method" is similar to saying there was a "cache miss":</div><div class="panel" style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: rgb(187, 187, 187); border-bottom-left-radius: 5px 5px; border-bottom-right-radius: 5px 5px; border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(187, 187, 187); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(187, 187, 187); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(187, 187, 187); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-top-style: solid; border-top-width: 1px; color: black; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; overflow-x: hidden; overflow-y: hidden; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><div class="panelContent" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 0.95em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 10px; padding-right: 10px; padding-top: 0px; text-align: left;"><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left;">- etag matches, date is fresh: return status 304<br />
- etag matches, but date is stale: origin server must execute the method and return that response<br />
- etag does not match: origin server must execute the method and return that response, <em>regardless</em> of any date-based validation information in request<br />
- etag matches, and there is no date-based header: return status 304<br />
- no etag in request; date is fresh: return status 304<br />
- no etag in request; date is stale: origin server must execute the method and return that response</div></div></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;">For reference,</span> <span style="color: #333333;"><span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.3.4" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">here</a></span></span> <span style="color: #333333;"><span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.25" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">are</a></span></span> <span style="color: #333333;">the</span> <span style="color: #333333;"><span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.26" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">sections</a></span></span> <span style="color: #333333;">of the RFC that I used to determine the above recipe.</span></div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-Invalidation"></a>Invalidation</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">The third mechanism supporting caching (beyond Expiration and Validation) is <em>invalidation</em>. However, here you shouldn't need to do anything special with your web application -- it should be handled implicitly by any gateway or proxy cache that is in place. What you <em>should</em> do is return ETag and Last-Modified information in any response for a given resource (including GET, POST, PUT, DELETE) - such that any intermediary cache can not only cache as needed (for GETs), but also evict/update/otherwise-deal-with URLs that have been changed (via POST, PUT and DELETE).</div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-DesignDiscussion"></a>Design Discussion</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Checking for ETag alone is not as effective a caching solution as might be accomplished with use of If-Modified-Since. This is because the cache must validate the value of the ETag before returning a 304. In the case of a dynamic system where state changes frequently or unpredictably, however, ETag might be the best approach. In other cases where it is known e.g. that state won't change until a given time, use of If-Modified-Since is likely to be the most scalable solution, since the application can offload requests to reverse proxies.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Use of the Expires header can also be used in systems where it is known that state will change at precise times; however, this calls for client and server clocks to be sync, and requires explicit updates to the Expires header value when expiration occurs (which, if forgotten, leads to permanent staleness and zero benefit from a cache).</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Note that date-based validation is limited to one-second precision. So it's feasible that a client could fetch a resource, saving the last-modified date in the response, then change the resource (or some other client could change it) and subsequently request it again immediately, but receive a 304 response since all of this took place within the same second. As such, I'd endorse use of the ETag as the preferred caching protocol if your service expects anything resembling high concurrency and requires strict correctness.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;">If proxy/reverse caches are expected to be part of the ecosystem and you want to control their behavior independently, consider using these headers (see RFC 2616, section 14.9.3 for details):</span></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;"><b>s-maxage=</b></span><span style="color: #333333;"><b><seconds></seconds></b></span><span style="color: #333333;"><seconds> - similar to max-age, except that it only applies to shared caches.</seconds></span><br />
<span style="color: #333333;"><b>proxy-revalidate</b></span><span style="color: #333333;"> - similar to must-revalidate, except that it only applies to proxy caches. From</span> <span style="color: #333333;"><span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://palisade.plynt.com/issues/2008Jul/cache-control-attributes" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">this article</a></span></span><span style="color: #333333;">:</span></div><div class="panel" style="background-attachment: initial; background-clip: initial; background-color: #f0f0f0; background-image: initial; background-origin: initial; background-position: initial initial; background-repeat: initial initial; border-bottom-color: rgb(187, 187, 187); border-bottom-left-radius: 5px 5px; border-bottom-right-radius: 5px 5px; border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(187, 187, 187); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(187, 187, 187); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(187, 187, 187); border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; border-top-style: solid; border-top-width: 1px; color: black; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 0px; overflow-x: hidden; overflow-y: hidden; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><div class="panelContent" style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 0.95em; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 10px; padding-right: 10px; padding-top: 0px; text-align: left;"><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px; text-align: left;"><span style="color: #333333;">...useful when an authenticated page is being cached in the browser. You don’t want the proxy to cache and serve the page, whereas it’s fine for your browser to cache and serve the page.</span></div></div></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;">From my understanding of the protocol so far, I'd also suggest adding the</span> <span style="color: #333333;"><em>public</em></span> <span style="color: #333333;">header value to responses intended to be cacheable if HTTP authentication is involved:</span></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;"><b>public</b></span><span style="color: #333333;"> --- marks authenticated responses as cacheable; normally, if HTTP authentication is required, responses are automatically private. From HTTP 1.1 spec: Indicates that the response MAY be cached by any cache, even if it would normally be non-cacheable or cacheable only within a non- shared cache.</span></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;">Here's additional information from HTTP 1.1. spec, section 14.8:</span></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span style="color: #333333;">A user agent that wishes to authenticate itself with a server – usually, but not necessarily, after receiving a 401 response – does so by including an Authorization request-header field with the request. When a shared cache (see section 13.7) receives a request containing an Authorization field, it MUST NOT return the corresponding response as a reply to any other request, except that it MAY use the response in a subsequent request if s-maxage, must-revalidate or public headers are included in the response (see section 13.7 for details).</span></div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-Other"></a>Other</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Here are some things you can do to make your website more <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.mnot.net/cache_docs/#TIPS" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;"><span class="Apple-style-span" style="color: #006daf;"><span class="Apple-style-span" style="outline-color: initial; outline-width: initial;">cache-friendly</span></span></a></span> and <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.mnot.net/cache_docs/#SCRIPT" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">cache-aware</a></span>. Not all of these will necessarily apply to your context, especially when dealing with dynamic content.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Note that one assumption made in this writeup is that there is only one representation for any given URL. This may not be the case, however; representations may vary as per JSON vs XML encoding, use of compression or not, special markup for a given browser (or other user agent), and etc. This is where the Vary header comes into play; here's a nice <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://symfony.com/doc/2.0/book/http_cache.html#varying-the-response" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">explanation</a></span> of this pattern.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">There are many open source/commercial proxy and reverse-proxy caches available, notably <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.squid-cache.org/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">Squid</a></span> and <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="https://www.varnish-cache.org/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">Varnish</a></span> (let alone <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://httpd.apache.org/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">Apache</a></span>, <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://wiki.nginx.org/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">Nginx</a></span>, ... etc.). </div><h4 style="color: black; font-size: 1.2em; font-weight: bold; line-height: normal; margin-bottom: 0.3em; margin-left: 0px; margin-right: 0px; margin-top: 1.2em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="http://www.blogger.com/post-create.g?blogID=6064095763580990" name="HTTPCaching-Resources"></a>Resources</h4><hr style="border-bottom-color: rgb(204, 204, 204); border-bottom-style: solid; border-bottom-width: 1px; border-left-color: rgb(204, 204, 204); border-left-style: solid; border-left-width: 1px; border-right-color: rgb(204, 204, 204); border-right-style: solid; border-right-width: 1px; border-top-color: rgb(204, 204, 204); border-top-style: solid; border-top-width: 1px; color: #cccccc; height: 0px;" /><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://en.wikipedia.org/wiki/Web_cache" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://en.wikipedia.org/wiki/Web_cache</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.peej.co.uk/articles/http-caching.html" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.peej.co.uk/articles/http-caching.html</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://tomayko.com/writings/things-caches-do" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://tomayko.com/writings/things-caches-do</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.web-caching.com/welcome.html" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.web-caching.com/welcome.html</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.mnot.net/cache_docs/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.mnot.net/cache_docs/</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.visolve.com/squid/whitepapers/ViSolve_Web_Caching.pdf" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.visolve.com/squid/whitepapers/ViSolve_Web_Caching.pdf</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://stackoverflow.com/questions/4360283/http-cache-control" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://stackoverflow.com/questions/4360283/http-cache-control</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.w3.org/Protocols/rfc2616/rfc2616.html</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://wiki.squid-cache.org/" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://wiki.squid-cache.org</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://symfony.com/doc/2.0/book/http_cache.html" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://symfony.com/doc/2.0/book/http_cache.html</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://hc.apache.org/user-docs.html" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://hc.apache.org/user-docs.html</a></span><br />
<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.slideshare.net/rtomayko/https-bestkept-secret-caching" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.slideshare.net/rtomayko/https-bestkept-secret-caching</a></span></div>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-37539940869921404942011-11-16T09:44:00.000-07:002011-11-16T09:44:37.753-07:00RESTful Design - Benefits, Patterns<span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 17px;">This captures odds-n-ends around RESTful design - why bother, what are the benefits, what are some patterns, etc. This is written in a terse "talking points" style, with most content either paraphrased or explicitly copied from the footnoted links at end of post; I've added some of my thoughts here and there.</span><span class="Apple-style-span" style="color: #333333; font-family: Arial, Helvetica, FreeSans, sans-serif; font-size: 13px; line-height: 17px;"></span><br />
<div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">An opening thought around what might be the benefit to understanding and leveraging aspects of RESTful design: since REST describes the way the web works, and the web is the single most scalable application ever known, we might do well to understand and embrace aspects of RESTful style.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">REST describes a <b>Resource-Oriented Architecture (ROA):</b> <em>the web is based on resource exchange, not on sending commands</em>.</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Selected excerpts from Roy Fielding's thesis</b>[1]:</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>REST provides a set of architectural constraints that, when applied as a whole, emphasizes scalability of component interactions, generality of interfaces, independent deployment of components, and intermediary components to reduce interaction latency, enforce security, and encapsulate legacy systems.</em></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>The central feature that distinguishes the REST architectural style from other network-based styles is its emphasis on a uniform interface between components. By applying the software engineering principle of generality to the component interface, the overall system architecture is simplified and the visibility of interactions is improved.</em></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>What makes HTTP significantly different from RPC is that the requests are directed to resources using a generic interface with standard semantics that can be interpreted by intermediaries almost as well as by the machines that originate services. The result is an application that allows for layers of transformation and indirection that are independent of the information origin, which is very useful for an Internet-scale, multi-organization, anarchically scalable information system. RPC mechanisms, in contrast, are defined in terms of language APIs, not network-based applications.</em></div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>HTTP is not designed to be a transport protocol. It is a transfer protocol in which the messages reflect the semantics of the Web architecture by performing actions on resources through the transfer and manipulation of representations of those resources. It is possible to achieve a wide range of functionality using this very simple interface, but following the interface is required in order for HTTP semantics to remain visible to intermediaries.</em></div><h5 style="color: black; font-size: 1.1em; font-weight: bold; line-height: normal; margin-bottom: 0.1em; margin-left: 0px; margin-right: 0px; margin-top: 1em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="" name="RESTfulDesign-Benefits%2CPatterns-%7B%7D%7B%7DPrinciples%7B%7D%7B%7D"></a><b><em><ins>Principles</ins></em></b></h5><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>as per Tilkov</em>[2]:</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Everything has its own URI as an identifier</b></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Link things together</b></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Use a set of standard methods (in the manner they're intended)</b></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Resources have multiple representations</b></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Assume stateless</b> <b><em>communication</em></b></li>
</ul><h6 style="color: black; font-size: 1em; font-weight: bold; line-height: normal; margin-bottom: 0.1em; margin-left: 0px; margin-right: 0px; margin-top: 1em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="" name="RESTfulDesign-Benefits%2CPatterns-BenefitsfromPrinciples"></a><em>Benefits from Principles</em></h6><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Identifiers: </b></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>flexibility, extensibility</em>: bookmarkable, pass between different apps, facilitate new mashups; support versioning (version # is part of URI)<br />
<em>lowered dev costs, extensibility</em>: familiar programming model (ala browser); apply web-centric security constraints; leverage HTTP redirects; apply different rules to different URIs for logging, statistics, auditing, etc.<br />
<em>ease of evolution</em>: retrofit things like auditing, diagnostics, recovery, undo operations, ...</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Linking:</b></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>scalability</em>: paging via links in the face of many results<br />
<em>lowered dev costs</em>: symmetric, consistent, understandable, maintainable, extensible codebase; familiar programming model (as browser). Clients can "discover" the entire information space dynamically, no need to hardwire drill-down URLs that will later break.<br />
<em>lowered dev costs, extensibility</em>: guide "next valid transitions"; encapsulate URI details via rel (relations) attribute, no need for out-of-band document (WADL, WSDL)<br />
<em>ease of evolution</em>: self-describing server can evolve without breaking clients</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Standard Verbs ("Uniform Interface"):</b></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>scalability</em>: can leverage (and not get burned by) existing web infrastructure (proxies, gateways, etc...crawlers, etc.)<br />
<em>reliability</em>: GET and HEAD are safe; PUT and DELETE are idempotent - thus clients can resend requests as needed (except for POST - but see patterns below for workarounds). Cache intermediaries can "determine the cacheability of a response because the interface is generic rather than specific to each resource. By default, the response to a retrieval request is cacheable and the responses to other requests are non-cacheable." (Fielding, sec. 5.2.2)<br />
<em>lowered dev costs</em>: no need to invent a new protocol for every application (ala WS).<br />
<em>extensibility</em>: re-use of testing tools/techniques, interoperability between new apps and existing clients, etc.<br />
<em>value-add</em>: facilitate intranet with searchable resources (i.e. crawlers can index GETs without deleting your database...).</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Multiple Representations:</b></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>ease of evolution</em>: support versioning for backwards compatibility (e.g. application-custom MIME types)<br />
<em>flexibility</em>: client references are not coupled to a particular representation</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>Stateless:</b></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><em>scalability</em>: facilitates load balancing, distributed caching, clustering, parallel processing and pipelining<br />
<em>reliability</em>: failover<br />
<em>flexibility, extensibility</em>: decoupled from clients<br />
<em>visibility</em>: diagnostics are transparent since each request is self-contained</div><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>All of above used together</b></li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">easier to combine different services (interop)<br />
more consistent coding patterns, better redundancy, faster training/learning curves, faster evolution<br />
symmetric, understandable, maintainable codebase<br />
From Fielding, section 5.3.1: "<em>(RESTful constraints) allow intermediaries - proxies, gateways, and firewalls - to be introduced at various points in the communication without changing the interfaces between (client and server), thus allowing them to assist in communication translation or improve performance via large-scale, shared caching. REST enables intermediate processing by constraining messages to be self-descriptive: interaction is stateless between requests, standard methods and media types are used to indicate semantics and exchange information, and responses explicitly indicate cacheability</em>."</div><h3 style="color: black; font-size: 1.4em; font-weight: bold; line-height: normal; margin-bottom: 0.5em; margin-left: 0px; margin-right: 0px; margin-top: 1.5em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="" name="RESTfulDesign-Benefits%2CPatterns-Patterns"></a><ins>Patterns</ins></h3><h5 style="color: black; font-size: 1.1em; font-weight: bold; line-height: normal; margin-bottom: 0.1em; margin-left: 0px; margin-right: 0px; margin-top: 1em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="" name="RESTfulDesign-Benefits%2CPatterns-Scalability"></a><em>Scalability</em></h5><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Caching - leverage validation, expiration, etc so response transfers data only when it's changed; server-side caching to minimize repeating expensive computations and/or to handle increased demand from multiple clients</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Cache control - server specifies which responses are cacheable; client has option to re-use the cacheable data</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Response code 409 - to leverage optimistic locking patterns</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Asynch request pattern - POST a query that is costly on server side; client receives a "future" in Location header, later does a GET to that URI (404 means not done yet...)</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Header information - specify what encoding is acceptable, server can compress e.g. into gzip to save bandwidth</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Instead of sessions (impacts scalability), make the shopping cart a <i>resource</i></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Provide "collection" resources - coarse-grained interactions</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Provide paging of large results - e.g. 20 at a time - with links on NEXT and PREVIOUS, etc.<ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">provide this link in a header to enable linking from non-text media types, e.g. an image[7]</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">use this "header link" pattern for other linking needs, e.g. providing the "next valid state transitions" (i.e. what valid things can client do from here)</li>
</ul></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Transactional behavior<ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">make the txn a resource. GET txn, do stuff to it, finally PUT it at the very end</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">use BASE and compensating txns (PUT, DELETE, POST) as needed</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">server provides links that facilitate compensating actions</li>
</ul></li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Conditional GET: response has ETag and/or Last-Modified set; client later requests same resource with header including Etag and/or Last-Modified value as value for If-None-Match and/or If-Modified-Since, respectively; then server decides if resend is needed ("validation"). If not, response code is 304.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">If you must use cookies, store all app state on client side (i.e. don't use a session ID pointing to data on server) - else, you'll sacrifice scalability</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Leverage intermediaries - using HTTP as intended in a RESTful style facilitates interoperation with network components that provide load balancing, caching, security policies, etc. As per Fielding: <em>Within REST, intermediary components can actively transform the content of messages because the messages are self-descriptive and their semantics are visible to intermediaries.</em></li>
</ul><h5 style="color: black; font-size: 1.1em; font-weight: bold; line-height: normal; margin-bottom: 0.1em; margin-left: 0px; margin-right: 0px; margin-top: 1em; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><a href="" name="RESTfulDesign-Benefits%2CPatterns-Design%2FCoding"></a><em>Design/Coding</em></h5><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">New URIs are created by server, returned to server via the Location header after a POST creates it</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Version the service with URI - /v1/service/resource, or even as part of the host - v1.myservice.twc.com, v2.myservice.twc.com, etc.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Keep in mind that HTML5 will support PUT/DELETE. But not all firewalls allow these through...so, tunnel the method using header or hidden form field, or just use XHR</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Provide canonical representations (text/plain, HTML) - supports easier debugging, scraping</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Get around idempotence of POST:<ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">instead of retry when uncertain about success, do a PUT</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Post-Once-Exactly: to get around non-repeatable POSTs - GET returns a server-side link representing a resource not yet created, then client POSTs to that URL to create new resource; subsequent POSTs to the same resource URL return 405 (not allowed).</li>
</ul></li>
</ul><ul style="font-size: 10pt; line-height: 13pt; list-style-type: disc;"><li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">"Conditional PUT (POST)": before submitting a large amount of information to server that might not be able to handle it at the moment - PUT without resource but include Content-Length and Expect headers. If response has same code as Expect value, client proceeds, else it does not.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Use POST to support large queries, to get around length limits imposed by servers, clients and proxies. However this results in loss of cacheability if response is sent synchronously; instead, use the async request pattern from above - server returns new resource with 201 response code, client then GETs the answer to the request.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Content negotiation - client uses accept, accept-encoding, accept-language headers; vary and/or location headers in response. This supports "late binding" in determining content representation as function of request.</li>
<li style="font-size: 10pt; line-height: 13pt; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">Evaluate extensibility vs visibility if considering "code on demand" (applets, javascript) - while this simplifies clients (extensible at runtime), it reduces visibility (maintenance, understandability, diagnostics, ...)</li>
</ul><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"><b>References</b>:</div><div style="background-attachment: initial; background-clip: initial; background-color: initial; background-image: none; background-origin: initial; background-position: initial initial; background-repeat: initial initial; color: #333333; font-size: 10pt; font-weight: normal; line-height: 13pt; margin-bottom: 10px; margin-left: 0px; margin-right: 0px; margin-top: 10px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;">[1] Fielding, Roy Thomas. Architectural Styles and the Design of Network-based Software Architectures. Doctoral dissertation, University of California, Irvine, 2000:<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm<sup><img align="absmiddle" alt="" border="0" class="rendericon" height="7" src="http://mystropedia.corp.mystrotv.com/images/icons/linkext7.gif" style="border-bottom-style: none; border-color: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial;" width="7" /></sup></a></span><br />
[2] Stefan Tilkov presentation (video): <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://www.parleys.com/#st=5&id=1397" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://www.parleys.com/#st=5&id=1397<sup><img align="absmiddle" alt="" border="0" class="rendericon" height="7" src="http://mystropedia.corp.mystrotv.com/images/icons/linkext7.gif" style="border-bottom-style: none; border-color: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial;" width="7" /></sup></a></span><br />
[3] Richardson, L. & Ruby, S. (2007) <em>RESTful Web Services</em>. Sebastopol, CA:O'Reilly Media, Inc.<br />
[4] Allamaraju, S. (2010) <em>RESTful Web Services Cookbook</em>. Sebastopol, CA:O'Reilly Media, Inc.<br />
[5] HATEOAS, the scary acronym<span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://css.dzone.com/articles/hateoas-scary-acronym" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">: http://css.dzone.com/articles/hateoas-scary-acronym<sup><img align="absmiddle" alt="" border="0" class="rendericon" height="7" src="http://mystropedia.corp.mystrotv.com/images/icons/linkext7.gif" style="border-bottom-style: none; border-color: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial;" width="7" /></sup></a></span><br />
[6] RESTful Web Services: <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://imyousuf-tech.blogs.smartitengineering.com/2011/02/restful-web-services.html" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://imyousuf-tech.blogs.smartitengineering.com/2011/02/restful-web-services.html<sup><img align="absmiddle" alt="" border="0" class="rendericon" height="7" src="http://mystropedia.corp.mystrotv.com/images/icons/linkext7.gif" style="border-bottom-style: none; border-color: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial;" width="7" /></sup></a></span><br />
[7] IETF RFC 5988 - Web Linking: <span class="nobr" style="white-space: nowrap;"><a class="external-link" href="http://tools.ietf.org/html/rfc5988" rel="nofollow" style="color: #006daf; outline-color: initial; outline-style: none; outline-width: initial; text-decoration: none;">http://tools.ietf.org/html/rfc5988<sup><img align="absmiddle" alt="" border="0" class="rendericon" height="7" src="http://mystropedia.corp.mystrotv.com/images/icons/linkext7.gif" style="border-bottom-style: none; border-color: initial; border-left-style: none; border-right-style: none; border-top-style: none; border-width: initial;" width="7" /></sup></a></span></div>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-4301509908452229442011-10-27T15:37:00.004-06:002011-10-28T10:04:09.330-06:00Create and Detect Thread DeadlocksJust the code:<br />
<pre class="brush:java">import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;
import java.util.Date;
import java.util.Scanner;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Example of how a deadlock might be created, and how to detect it. Two threads
* are launched, each acquiring the same two resources but in a different order.
* A delay is introduced in the first thread before acquiring the second
* resource to set up a race condition such that a deadlock *may* be introduced.
* The deadlock is not guaranteed to occur; it depends on the length of the
* delay, which is controlled by the user executing the program. Empirically, on
* my desktop, I've found that values of 100 sometimes are adequate, while
* values of 1000+ become increasingly reliable.
*
* Note that looking for deadlocks with the JMX mechanism used here (ThreadMXBean) is
* described in the javadocs as an operation that "might be expensive". As such,
* unless you're confident that the cost is not high...I'd recommend not putting
* this into operation, rather using it in dev/test environment when trying to
* reproduce a situation observed in production where a deadlock occurred. Note
* that in production, issuing SIGQUIT (ctl-backslash) will provoke a thread
* dump (without killing the process), in which information on deadlocked
* threads will also appear.
*/
public class DeadlockedThreadFinder
{
// done becomes true when either thread completes; note that if one thread
// completes, then the other one will also
public boolean done;
/**
* Launch two threads, each acquiring a lock on two different resources in a
* different order. The first thread pauses some time T as a function of the
* given delay.
*
* @param delay is the given delay
*/
public void createDeadlock(final int delay)
{
System.out.println("First thread will pause for time T as function of " +
delay);
// the resources in contention - if threads use the synchronized keyword,
// you could use something like the two Object declared (and commented
// out) here; else, use the ReentrantLock if in java.util.concurrent
// land.
// final Object resource1 = new Object();
// final Object resource2 = new Object();
final Lock lock1 = new ReentrantLock();
final Lock lock2 = new ReentrantLock();
// first thread
Thread t1 = new Thread()
{
public void run()
{
long id = this.getId();
lock1.lock(); // alternately use synchronized (resource1) without
// the try-finally block
try
{
System.out.println(id + ": obtained first lock");
// instead of using Thread.sleep(), just create a whole bunch
// of expensive objects
for (int i = 0; i < delay; i++)
{
new Date();
}
System.out.println(id + " waiting for 2nd lock...");
lock2.lock(); // or use synchronized (resource2)
try
{
System.out.println(id + ": obtained 2nd lock");
}
finally
{
lock2.unlock();
}
System.out.println(id + " is done!");
done = true;
}
finally
{
lock1.unlock();
}
}
};
// second thread
Thread t2 = new Thread()
{
public void run()
{
long id = this.getId();
lock2.lock(); // alternately use synchronized (resource2) without
// the try-finally block
try
{
System.out.println(id + ": obtained 2nd lock");
System.out.println(id + " waiting for first lock...");
lock1.lock(); // or use synchronized (resource1)
try
{
System.out.println(id + ": obtained first lock");
}
finally
{
lock1.unlock();
}
System.out.println(id + " is done!");
done = true;
}
finally
{
lock2.unlock();
}
}
};
t1.start();
t2.start();
}
/**
* User must enter an integer that specifies the delay. Values of 10000+ are
* likely to cause a deadlock. The larger the value entered, the more likely
* the program will loop a few times detecting no deadlock, and then, once
* the first thread has satisfied the delay, the program will detect a
* deadlock until the end of time or user termination of program, whichever
* comes first.
*/
public static void main(String[] args) throws Exception
{
// the JMX deadlock finder
ThreadMXBean mxbean = ManagementFactory.getThreadMXBean();
// user specifies the delay
System.out.print("Enter delay: ");
Scanner sc = new Scanner(System.in);
// launch the threads
DeadlockedThreadFinder finder = new DeadlockedThreadFinder();
finder.createDeadlock(sc.nextInt());
System.out.println("Waiting for either thread to be done...");
do
{
// the JMX deadlock finder will return null if no deadlock detected.
// Note that if the threads are using traditional synchronization (i.e.
// using the synchronized keyword), then you could also use the
// findMonitorDeadlockedThreads method here; but since the threads
// might uplevel to use java.util.concurrent, it's advised to instead
// always use findDeadlockedThreads, which will work for either situation.
long[] deadlocked = mxbean.findDeadlockedThreads();
if (deadlocked != null)
{
System.out.print("Deadlocked threads: ");
String comma = "";
for (long l : deadlocked)
{
System.out.print(comma + l);
comma = ",";
}
System.out.println();
}
else
{
System.out.println("No deadlock detected");
}
Thread.sleep(1000);
}
while (!finder.done);
// uh, done
System.out.println("Done");
}
}
</pre>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-14350021385481255322011-03-08T15:16:00.001-07:002011-03-08T15:21:35.061-07:00Create and Initialize a Utility Class with Spring<p>Let's say we want to encapsulate a collection of read-only configuration parameters into a class (so, we want immutability). There are numerous parameters in the configuration, perhaps dozens - so we don't want to provide some ugly multi-parameter constructor or factory method. In fact, we want to provide clients with the convenience of static getters, so we know this will be a utility class (i.e. no instances needed or desired). While we could initialize a list of static fields with their configuration values to facilitate this, we would rather factor these value out into some external file.</p><p>We'd like to use Spring - but Spring works on instances, and we don't have a constructor for Spring to use, nor do we want or need an instance anyway, nor do we want to provide setters on this class (since we would like to stay immutable). So, how to use Spring?</p><p>One solution is to use a variation on the <a href="http://blog.temposwc.com/2010/12/notes-on-builder-pattern.html">Builder pattern</a> - the recipe goes like this:</p><ol><li>create the utilty class with static fields for each configuration parameter</li><li>give it a private constructor</li><li>provide static getters for each parameter</li><li>add a static inner class with the same fields, although these will be instance fields (not static)</li><li>this inner class also has a private constructor</li><li>provide setters for each field - although here we deviate from the standard Builder pattern: these are true setters, returning void</li><li>the utility class now provides a static "init" method that accepts an instance of the inner class as an argument - and this behaves just like the regular Builder pattern, where the top-level class initializes its fields from the correspond fields in the argument object</li><li>the inner class provides its own "init" method which calls the utility class init method with itself</li></ol><p>Spring wires all of this together like this:</p><pre class="brush:java"><br /> <bean id="builder-variant" class="com.mybiz.MyUtilityClass$MyInnerClass"<br /> init-method="initUtilityClass"><br /> <property name="foo" value="bar"/><br /> <property name="bar" value="foo"/><br /> </bean><br /></pre><p>Using this, Spring will create an instance of the inner class, setting its properties as given, and then call the inner class' initializer. As mentioned in the above recipe, that initializer will then call the utility class' initializer with itself as the argument. That facilitates initializing the utility class properties, and we're done.</p>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com3tag:blogger.com,1999:blog-6064095763580990.post-79774393523025348782011-02-17T13:39:00.000-07:002011-02-21T07:39:21.905-07:00Integrate MyBatis 3.x with Spring 3.x<p>Since last I wrote about <a href="http://blog.temposwc.com/2009/07/spring-30-cheatsheet-integration-with_09.html">integrating Spring with iBatis</a>, and about using the very useful <a href="http://blog.temposwc.com/2009/09/spring-test-framework-cheatsheet.html">auto-rollback in Spring Test Framework</a>, things have changed. The iBatis project has shifted to Google and is now called <a href="http://www.mybatis.org/">MyBatis</a>, and includes numerous API changes. But, this was done after Spring 3.0 was released - so full integration with Spring was left undone at that time. However, a <a href="http://mybatis.googlecode.com/files/mybatis-spring-1.0.0-reference.pdf">Spring-MyBatis integration component</a> is now available, and here I'll write up how to use it to very simply use MyBatis, preserving the auto-rollback feature.<br></p><a href="http://blog.temposwc.com/2011/02/integrate-mybatis-3x-with-spring-3x.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-80031396123564687772011-02-09T14:44:00.001-07:002011-02-09T14:44:15.944-07:00Get a Random Value Within a Given Range<p>Just the code:</p><pre class="brush:java"><br /> public int getRandomValue(long min, long max) {<br /> return (int) Math.max(min, (int) (Math.random() * max) + 1);<br /> }<br /></pre><p>Use this to (obviously) generate an integer value between (inclusively) the given minimum and maximum - which is useful also to fetch random elements e.g. from a List.</p>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com2tag:blogger.com,1999:blog-6064095763580990.post-91622981463438934792011-02-08T12:30:00.002-07:002011-02-21T08:10:18.049-07:00Getting Around the Double-Checked Locking Problem<p>This is just a summary of alternatives to the <a href="http://en.wikipedia.org/wiki/Double-checked_locking">double-checked locking pattern</a>, which has been shown to have potential problems. The alternatives are taken from <a href="https://www.securecoding.cert.org/confluence/display/java/LCK10-J.+Do+not+use+incorrect+forms+of+the+double-checked+locking+idiom">a CERT wiki article</a>. The motivations for the pattern come from three concerns:</p><ol><li>avoid constructing an object that is expensive to construct, unless-until it is needed</li><li>avoid more than one instantiation of that object, and</li><li>avoid the overhead of synchronization for the more common case of fetching the object.</li></ol><p></p><a href="http://blog.temposwc.com/2011/02/getting-around-double-checked-locking_08.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-48775488617892901252011-02-08T12:30:00.001-07:002011-02-21T08:10:32.388-07:00Getting Around the Double-Checked Locking Problem<p>This is just a summary of alternatives to the <a href="http://en.wikipedia.org/wiki/Double-checked_locking">double-checked locking pattern</a>, which has been shown to have potential problems. The alternatives are taken from <a href="https://www.securecoding.cert.org/confluence/display/java/LCK10-J.+Do+not+use+incorrect+forms+of+the+double-checked+locking+idiom">a CERT wiki article</a>. The motivations for the pattern come from three concerns:</p><ol><li>avoid constructing an object that is expensive to construct, unless-until it is needed</li><li>avoid more than one instantiation of that object, and</li><li>avoid the overhead of synchronization for the more common case of fetching the object.</li></ol><p></p><a href="http://blog.temposwc.com/2011/02/getting-around-double-checked-locking.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-46569171439067855392011-02-08T10:27:00.001-07:002011-02-21T08:10:52.754-07:00Thread-Safe Singleton Using ThreadLocal<p>Let's say a given component in your application has these constraints:</p><ol><li>it needs a reference to an object that is expensive to construct</li><li>the expensive object state can be set just once, i.e. it never changes</li><li>it executes in a multi-threaded context</li><li>maximum throughput is required</li></ol><p>Constraint #1 seems to call for an instance variable - i.e. you don't want to use a method-local field since the object construction is expensive, as such you don't want to do it each time the object is needed. Constraint #2 implies that a singleton will serve our needs. However, constraint #3 means the singleton must be used in a thread-safe manner - and constraint #4 tells us that we want to avoid synchronization if possible.<br></p><a href="http://blog.temposwc.com/2011/02/thread-safe-singleton-using-threadlocal.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com1tag:blogger.com,1999:blog-6064095763580990.post-84008049815448945592011-02-02T17:42:00.000-07:002011-02-21T08:11:31.247-07:00Get Notified When Your Periodic Task Throws an Exception<p>I've written up a how-to on a <a href="http://blog.temposwc.com/2011/01/periodic-task-and-watchdog-reusable-and.html">periodic task with a watchdog</a>; now I want to handle exceptions and notify interested observers when exceptions occur. The watchdog is in place in case exceptions don't get handled at all, in which case subsequent executions of the scheduled thread <a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html#scheduleAtFixedRate(java.lang.Runnable, long, long, java.util.concurrent.TimeUnit)">will be suppressed</a>. in this case, the watchdog knows that some problem occurred - but it doesn't know just what that was. As an alternative (or in addition) to the watchdog, we simply catch exceptions in the Runnable passed to our <a href="http://download.oracle.com/javase/6/docs/api/java/util/concurrent/Executor.html">Executor</a>, handling it by both logging the information and notifying interested listeners. This helps pass along exception information from a different stack of execution, since the problem occurs in a different thread:</p><a href="http://blog.temposwc.com/2011/02/get-notified-when-your-periodic-task.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-32846885082305492372011-02-02T17:18:00.000-07:002011-02-21T08:12:00.203-07:00Use Spring to Wire Up Varargs<p>This describes a technique to provide N objects to a constructor using Spring. Nothing real new or innovative here; just an idiom I wanted to save for future reference. Let's say we have a constructor that uses <a href="http://download.oracle.com/javase/1.5.0/docs/guide/language/varargs.html">varargs</a>:</p><pre class="brush:java"><br> public MockDao(SummaryData...summaries) {<br> // save the summary data for downstream use...<br> }<br></pre><p>And, we want to use Spring to provide test summary data to our mocked-out DAO. </p><a href="http://blog.temposwc.com/2011/02/use-spring-to-wire-up-varargs.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-57436423474860521202011-02-02T13:27:00.001-07:002011-02-21T08:12:45.898-07:00Encapsulate SSL TrustStore Configuration<p>Here I'll present the steps of a recent exercise I completed, around configuring SSL on the client side, encapsulating the configuration for transparency. For some background on SSL and the topics discussed in this article, here are some resources:</p><p><a href="http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/JSSERefGuide.html#SSLOverview">SSL Protocol Overview</a><br><a href="http://www.tldp.org/HOWTO/SSL-Certificates-HOWTO">SSL Certificates HOWTO</a><br><a href="http://en.wikipedia.org/wiki/Secure_Sockets_Layer">Transport Layer Security</a></p><p>The <a href="http://www.grc.com/securitynow.htm">Security Now podcast series</a> also has some excellent deep-dives into SSL and many other security-related topics.<br></p><a href="http://blog.temposwc.com/2011/02/encapsulate-ssl-truststore.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-75887951872085152712011-02-02T10:18:00.000-07:002011-02-02T10:18:02.426-07:00Enable Assertions with JUnit Tests in IDEA<p>My test cases have recently been converted from <a href="http://testng.org/">TestNG</a> to <a href="http://junit.org/">JUnit4</a>, and to my surprise every single test I wrote from that point forward passed without a problem - if I ran the tests in my <a href="http://www.jetbrains.com/idea/">Intellij IDEA</a> 9.0.4 IDE. Mysteriously, executing them via <a href="http://maven.apache.org/plugins/maven-surefire-plugin/">Maven</a> did not have that same result (whether from command line or from IDEA). As it turns out - apparently <a href="http://download.oracle.com/javase/1.4.2/docs/guide/lang/assert.html">JDK assertions</a> are enabled by default when I use TestNG in IDEA, but not so much when using JUnit.</p><p>Fix this problem by setting the <a href="http://download.oracle.com/javase/1.4.2/docs/guide/lang/assert.html#enable-disable">-ea VM argument</a> for all existing tests, and setting that as a default for JUnit tests created from this point forward.</p><p>Arrrggghhhh.</p>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-68874584088268158072011-01-28T11:41:00.000-07:002011-02-21T08:13:07.280-07:00Basic Authentication with Apache HttpClient<p>This is the general idiom used for <a href="http://hc.apache.org/httpclient-legacy/authentication.html">BASIC authentication with Apache's HttpClient</a>, version 3.1. </p><a href="http://blog.temposwc.com/2011/01/basic-authentication-with-apache.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com1tag:blogger.com,1999:blog-6064095763580990.post-71531958785651926902011-01-27T13:31:00.000-07:002011-02-21T08:13:15.298-07:00Periodic Task and Watchdog - Reusable and Testable Versions<p>In my <a href="http://blog.temposwc.com/2011/01/schedule-periodic-task-with-watchdog.html">previous post</a>, I presented a simple utility for a periodically executing task and a watchdog to make sure it runs forever. Now I'll refactor that prototype code to make things generic and reusable.<br></p><a href="http://blog.temposwc.com/2011/01/periodic-task-and-watchdog-reusable-and.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-79098780257983221322011-01-27T11:36:00.000-07:002011-02-21T08:13:49.851-07:00Schedule a Periodic Task with a Watchdog<p>This demonstrates a simple mechanism to start up a thread that executes some task periodically, with a watchdog to ensure it keeps running. It is assumed that the periodic task involves some kind of I/O or remote communication that can result in an exception. The watchdog is needed because the <span style="font-family: 'courier new', courier;"><a title="java.util.concurrent javadoc" href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html">java.util.concurrent</a></span> <a title="ScheduledExecutorService javadoc" href="http://download.oracle.com/javase/7/docs/api/java/util/concurrent/ScheduledExecutorService.html">class used for the task</a> will not proceed with subsequent executions after one of its executions encounters an exception. </p><a href="http://blog.temposwc.com/2011/01/schedule-periodic-task-with-watchdog.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com2tag:blogger.com,1999:blog-6064095763580990.post-76637845504582697062011-01-14T15:14:00.000-07:002011-02-21T08:13:57.465-07:00Test Your CXF REST Service by Examining Application Object State<p>While I've previously described using <a href="http://cxf.apache.org/">CXF</a> to <a href="http://blog.temposwc.com/2011/01/unit-test-your-rest-service.html">unit test a REST service</a>, it's a limited technique since the object returned from the HTTP request is a response string - and any assertions you could make against that string are going to be brittle, since it relies on the decisions around how the encoding (XML or JSON) is done. What we really want is a more object-oriented mechanism for testing against application object state...which means you need a REST client that calls the service and can then look at the returned application object, as opposed to a Response object.<br></p><a href="http://blog.temposwc.com/2011/01/test-your-cxf-rest-service-by-examining.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-30823169746346221652011-01-10T09:31:00.002-07:002011-02-21T08:14:22.179-07:00Portfolio Entry #1: Massage Business in Erie, Colorado<p>Tempo Software and Consulting (my LLC) happily announces the publishing of its first website, for my client running a massage therapy business in Erie, Colorado. Please have a look - comments and feedback are invited.</p><p>And if in fact you live in the Boulder County area, Aimee is a very gifted therapist who has taken care of my aches and pains for many years. Should you be looking for a massage therapist, I would very sincerely recommend her.</p><p>Full disclosure: Aimee is my wife, but I submit that my endorsement remains objective - since she was my massage therapist of choice for many years before we even started dating. And, yes, I billed her at a discounted rate.</p><p>Her business is <a href="http://www.handsonharmonymassage.com/">Hands On Harmony Massage</a>. Enjoy.</p><p><span class="post-author vcard"> </span></p>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-33170567388451302252011-01-06T17:01:00.000-07:002011-02-21T08:14:28.854-07:00Versioning XML and JSON Models in a CXF REST Service<p>Following up on my <a href="http://blog.temposwc.com/2011/01/add-json-support-to-your-rest-service.html">previous post</a> around how simple it was to add JSON support to my CXF-based REST service...now I'll add versioning support to my XML-annotated model and see what happens.<br></p><a href="http://blog.temposwc.com/2011/01/versioning-xml-and-json-models-in-cxf.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-27564311217254124542011-01-04T15:47:00.000-07:002011-02-21T08:14:42.875-07:00Add JSON Support to your REST Service<p>Continuing from my previous post about <a href="http://blog.temposwc.com/2011/01/unit-test-your-rest-service.html">a standalone unit-test mechanism for your RESTful service</a>, now I'll add JSON support to that service, which already gives you XML. This turns out to be a pretty simple thing - all we need is:</p><ol><li>Tell the RESTful service to produce both XML and JSON</li><li>Add the runtime dependency you'll need </li><li>Add some tests to confirm things</li></ol><p></p><a href="http://blog.temposwc.com/2011/01/add-json-support-to-your-rest-service.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-85991838471461279372011-01-04T15:19:00.001-07:002011-02-21T08:15:00.915-07:00Unit Test Your REST Service<p>Here's an approach for unit-testing your RESTful service. </p><a href="http://blog.temposwc.com/2011/01/unit-test-your-rest-service.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-77073617241570832392010-12-16T10:33:00.001-07:002011-02-21T08:15:07.640-07:00Populate Immutable Objects with iBatis Mapping<p>In a <a href="http://blog.temposwc.com/2010/08/ibatis-mapping-for-one-to-many.html">previous post</a>, I provided iBatis configuration and mapping that supported populating Java objects on a per-property basis, i.e. the classes in use had to provide setters for this approach. Here I describe another iBatis pattern that populates <i>immutable</i> objects with more than a few properties.<br></p><a href="http://blog.temposwc.com/2010/12/populate-immutable-objects-with-ibatis.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-48313748488078867812010-12-16T09:49:00.000-07:002011-02-21T08:15:18.802-07:00Notes on the Builder Pattern<p>This post simply describes the <a href="http://en.wikipedia.org/wiki/Builder_pattern">Builder Pattern</a>, for my own future reference. This pattern is useful in constructing immutable objects that have numerous properties, some required and some optional, without using numerous constructors to support various permutations. And, of course, since the object is immutable, there are no setters or non-private fields to support post-construction alterations. With the Builder pattern, one can ensure objects are not only immutable, but have completed state initialization before use.<br></p><a href="http://blog.temposwc.com/2010/12/notes-on-builder-pattern.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0tag:blogger.com,1999:blog-6064095763580990.post-71236390254790953492010-11-17T14:40:00.003-07:002011-02-21T08:15:24.674-07:00Running an Effective Agile Retrospective<p>This is a summary of a presentation given by Brad Swanson of <a href="http://properosolutions.com/">Propero Solutions </a>on November 9, 2010, with permission from Brad. The topic was around effectively leading an <a href="http://www.agilegamedevelopment.com/2008/06/when-we-talk-about-agile-we-use-phrase.html">agile retrospective meeting</a>.<br></p><a href="http://blog.temposwc.com/2010/11/running-effective-agile-retrospective.html#more">Read more »</a>Gary Hortonhttp://www.blogger.com/profile/00737811225322795002noreply@blogger.com0