001: /* Https.java
002:
003: {{IS_NOTE
004: Purpose:
005: Description:
006: History:
007: 2001/11/29 13:53:05, Create, Tom M. Yeh.
008: }}IS_NOTE
009:
010: Copyright (C) 2001 Potix Corporation. All Rights Reserved.
011:
012: {{IS_RIGHT
013: This program is distributed under GPL Version 2.0 in the hope that
014: it will be useful, but WITHOUT ANY WARRANTY.
015: }}IS_RIGHT
016: */
017: package org.zkoss.web.servlet.http;
018:
019: import java.io.InputStream;
020: import java.io.ByteArrayOutputStream;
021: import java.util.zip.GZIPOutputStream;
022: import java.io.IOException;
023: import java.util.Date;
024: import java.util.Locale;
025: import java.util.Map;
026: import java.text.SimpleDateFormat;
027: import java.text.ParseException;
028:
029: import javax.servlet.ServletContext;
030: import javax.servlet.ServletRequest;
031: import javax.servlet.ServletResponse;
032: import javax.servlet.ServletException;
033: import javax.servlet.http.HttpServletRequest;
034: import javax.servlet.http.HttpServletResponse;
035: import javax.servlet.http.HttpSession;
036: import javax.servlet.http.Cookie;
037:
038: import org.zkoss.lang.D;
039: import org.zkoss.lang.SystemException;
040: import org.zkoss.util.logging.Log;
041: import org.zkoss.io.Files;
042:
043: import org.zkoss.web.Attributes;
044: import org.zkoss.web.servlet.Servlets;
045: import org.zkoss.web.util.resource.ExtendletContext;
046:
047: /**
048: * The Servlet-related utilities.
049: *
050: * @author tomyeh
051: */
052: public class Https extends Servlets {
053: private static final Log log = Log.lookup(Https.class);
054:
055: /** Compresses the content into an byte array, or null
056: * if the browser doesn't support the compression (accept-encoding).
057: *
058: * @param content1 the first part of the content to compress; null to ignore.
059: * If you have multiple input streams, use java.io.SequenceInputStream
060: * to concatenate them
061: * @param content2 the second part of the content to compress; null to ignore.
062: * @return the compressed result in an byte array,
063: * null if the browser doesn't support the compression.
064: * @since 2.4.1
065: */
066: public static final byte[] gzip(HttpServletRequest request,
067: HttpServletResponse response, InputStream content1,
068: byte[] content2) throws IOException {
069: //We check Content-Encoding first to avoid compressing twice
070: String ae = request.getHeader("accept-encoding");
071: if (ae != null && !response.containsHeader("Content-Encoding")) {
072: if (ae.indexOf("gzip") >= 0) {
073: response.addHeader("Content-Encoding", "gzip");
074: final ByteArrayOutputStream boas = new ByteArrayOutputStream(
075: 8192);
076: final GZIPOutputStream gzs = new GZIPOutputStream(boas);
077: if (content1 != null)
078: Files.copy(gzs, content1);
079: if (content2 != null)
080: gzs.write(content2);
081: gzs.finish();
082: return boas.toByteArray();
083: // } else if (ae.indexOf("deflate") >= 0) {
084: //Refer to http://www.gzip.org/zlib/zlib_faq.html#faq38
085: //It is not a good idea to zlib (i.e., deflate)
086: }
087: }
088: return null;
089: }
090:
091: /**
092: * Gets the complete server name, including protocol, server, and ports.
093: * Example, http://mysite.com:8080
094: */
095: public static final String getCompleteServerName(
096: HttpServletRequest hreq) {
097: final StringBuffer sb = hreq.getRequestURL();
098: final String ctx = hreq.getContextPath();
099: final int j = sb.indexOf(ctx);
100: if (j < 0)
101: throw new SystemException("Unknown request: url=" + sb
102: + ", ctx=" + ctx);
103: return sb.delete(j, sb.length()).toString();
104: }
105:
106: /**
107: * Gets the complete context path, including protocol, server, ports, and
108: * context.
109: * Example, http://mysite.com:8080/we
110: */
111: public static final String getCompleteContext(
112: HttpServletRequest hreq) {
113: final StringBuffer sb = hreq.getRequestURL();
114: final String ctx = hreq.getContextPath();
115: final int j = sb.indexOf(ctx);
116: if (j < 0)
117: throw new SystemException("Unknown request: url=" + sb
118: + ", ctx=" + ctx);
119: return sb.delete(j + ctx.length(), sb.length()).toString();
120: }
121:
122: /** Gets the value of the specified cookie, or null if not found.
123: * @param name the cookie's name
124: */
125: public static final String getCookieValue(
126: HttpServletRequest request, String name) {
127: final Cookie[] cookies = request.getCookies();
128: if (cookies != null) {
129: for (int j = cookies.length; --j >= 0;) {
130: if (cookies[j].getName().equals(name))
131: return cookies[j].getValue();
132: }
133: }
134: return null;
135: }
136:
137: /**
138: * Returns the servlet uri of the request.
139: * A servlet uri is getServletPath() + getPathInfo().
140: * In other words, a servlet uri is a request uri without the context path.
141: * <p>However, HttpServletRequest.getRequestURI returns in encoded format,
142: * while this method returns in decode format (i.e., %nn is converted).
143: */
144: public static final String getServletURI(HttpServletRequest request) {
145: final String sp = request.getServletPath();
146: final String pi = request.getPathInfo();
147: if (pi == null || pi.length() == 0)
148: return sp;
149: if (sp.length() == 0)
150: return pi;
151: return sp + pi;
152: }
153:
154: /**
155: * Gets the context path of this page.
156: * Unlike getContextPath, it detects whether the current page is included.
157: *
158: * @return "/" if request is not a http request
159: */
160: public static final String getThisContextPath(ServletRequest request) {
161: String path = (String) request
162: .getAttribute(Attributes.INCLUDE_CONTEXT_PATH);
163: return path != null ? path
164: : request instanceof HttpServletRequest ? ((HttpServletRequest) request)
165: .getContextPath()
166: : "";
167: }
168:
169: /**
170: * Gets the servlet path of this page.
171: * Unlike getServletPath, it detects whether the current page is included.
172: *
173: * @return "/" if request is not a http request
174: */
175: public static final String getThisServletPath(ServletRequest request) {
176: String path = (String) request
177: .getAttribute(Attributes.INCLUDE_SERVLET_PATH);
178: return path != null ? path
179: : request instanceof HttpServletRequest ? ((HttpServletRequest) request)
180: .getServletPath()
181: : "/";
182: }
183:
184: /**
185: * Gets the request URI of this page.
186: * Unlike getRequestURI, it detects whether the current page is included.
187: *
188: * @return "/" if request is not a http request
189: */
190: public static final String getThisRequestURI(ServletRequest request) {
191: String path = (String) request
192: .getAttribute(Attributes.INCLUDE_REQUEST_URI);
193: return path != null ? path
194: : request instanceof HttpServletRequest ? ((HttpServletRequest) request)
195: .getRequestURI()
196: : "/";
197: }
198:
199: /**
200: * Gets the query string of this page.
201: * Unlike getQueryString, it detects whether the current page is included.
202: *
203: * @return null if request is not a http request
204: */
205: public static final String getThisQueryString(ServletRequest request) {
206: String path = (String) request
207: .getAttribute(Attributes.INCLUDE_QUERY_STRING);
208: return path != null || isIncluded(request)
209: || !(request instanceof HttpServletRequest) ? path : //null is valid even included
210: ((HttpServletRequest) request).getQueryString();
211: }
212:
213: /**
214: * Gets the path info of this page.
215: * Unlike getPathInfo, it detects whether the current page is included.
216: *
217: * @return null if request is not a http request
218: */
219: public static final String getThisPathInfo(ServletRequest request) {
220: String path = (String) request
221: .getAttribute(Attributes.INCLUDE_PATH_INFO);
222: return path != null || isIncluded(request)
223: || !(request instanceof HttpServletRequest) ? path : //null is valid even included
224: ((HttpServletRequest) request).getPathInfo();
225: }
226:
227: /**
228: * Gets the original context path regardless of being forwarded or not.
229: * Unlike getContextPath, it won't be affected by forwarding.
230: */
231: public static final String getOriginContextPath(
232: ServletRequest request) {
233: String path = (String) request
234: .getAttribute(Attributes.FORWARD_CONTEXT_PATH);
235: return path != null ? path
236: : request instanceof HttpServletRequest ? ((HttpServletRequest) request)
237: .getContextPath()
238: : "";
239: }
240:
241: /**
242: * Gets the original servlet path regardless of being forwarded or not.
243: * Unlike getServletPath, it won't be affected by forwarding.
244: */
245: public static final String getOriginServletPath(
246: ServletRequest request) {
247: String path = (String) request
248: .getAttribute(Attributes.FORWARD_SERVLET_PATH);
249: return path != null ? path
250: : request instanceof HttpServletRequest ? ((HttpServletRequest) request)
251: .getServletPath()
252: : "/";
253: }
254:
255: /**
256: * Gets the request URI regardless of being forwarded or not.
257: * Unlike HttpServletRequest.getRequestURI,
258: * it won't be affected by forwarding.
259: */
260: public static final String getOriginRequestURI(
261: ServletRequest request) {
262: String path = (String) request
263: .getAttribute(Attributes.FORWARD_REQUEST_URI);
264: return path != null ? path
265: : request instanceof HttpServletRequest ? ((HttpServletRequest) request)
266: .getRequestURI()
267: : "/";
268: }
269:
270: /**
271: * Gets the path info regardless of being forwarded or not.
272: * Unlike getPathInfo, it won't be affected by forwarding.
273: */
274: public static final String getOriginPathInfo(ServletRequest request) {
275: String path = (String) request
276: .getAttribute(Attributes.FORWARD_QUERY_STRING);
277: return path != null ? path
278: : isForwarded(request) ? null : //null is valid even included
279: request instanceof HttpServletRequest ? ((HttpServletRequest) request)
280: .getQueryString()
281: : null;
282: }
283:
284: /**
285: * Gets the query string regardless of being forwarded or not.
286: * Unlike getQueryString, it won't be affected by forwarding.
287: */
288: public static final String getOriginQueryString(
289: ServletRequest request) {
290: String path = (String) request
291: .getAttribute(Attributes.FORWARD_PATH_INFO);
292: return path != null ? path
293: : isForwarded(request) ? null : //null is valid even included
294: request instanceof HttpServletRequest ? ((HttpServletRequest) request)
295: .getPathInfo()
296: : null;
297: }
298:
299: /** Returns the servlet path + path info + query string.
300: * Because the path info is decoded, the return string can be considered
301: * as decoded. On the other hand {@link #getOriginFullRequest} is in
302: * the encoded form.
303: * @see #getOriginFullRequest
304: */
305: public static final String getOriginFullServlet(
306: ServletRequest request) {
307: final String qstr = getOriginQueryString(request);
308: final String pi = getOriginPathInfo(request);
309: if (qstr == null && pi == null)
310: return getOriginServletPath(request);
311:
312: final StringBuffer sb = new StringBuffer(80)
313: .append(getOriginServletPath(request));
314: if (pi != null)
315: sb.append(pi);
316: if (qstr != null)
317: sb.append('?').append(qstr);
318: return sb.toString();
319: }
320:
321: /** Returns the request uri + query string.
322: * Unlik {@link #getOriginFullServlet}, this is in the encoded form
323: * (e.g., %nn still exists, if any).
324: * Note: request uri = context path + servlet path + path info.
325: */
326: public static final String getOriginFullRequest(
327: ServletRequest request) {
328: final String qstr = getOriginQueryString(request);
329: return qstr != null ? getOriginRequestURI(request) + '?' + qstr
330: : getOriginRequestURI(request);
331: }
332:
333: /**
334: * Redirects to another URL by prefixing the context path and
335: * encoding with encodeRedirectURL.
336: *
337: * <p>It encodes the URI automatically (encodeRedirectURL).
338: * Parameters are encoded by
339: * {@link Encodes#setToQueryString(StringBuffer,Map)}.
340: *
341: * <p>Like {@link Encodes#encodeURL}, the servlet context is
342: * prefixed if uri starts with "/". In other words, to redirect other
343: * application, the complete URL must be used, e.g., http://host/other.
344: *
345: * <p>Also, HttpServletResponse.encodeRedirectURL is called automatically.
346: *
347: * @param request the request; used only if params is not null
348: * @param response the response
349: * @param uri the redirect uri (not encoded; not including context-path),
350: * or null to denote {@link #getOriginFullServlet}
351: * It is OK to relevant (without leading '/').
352: * If starts with "/", the context path of request is assumed.
353: * To reference to foreign context, use "~ctx/" where ctx is the
354: * context path of the foreign context (without leading '/').
355: * @param params the attributes that will be set when the redirection
356: * is back; null to ignore; format: (String, Object)
357: * @param mode one of {@link #OVERWRITE_URI}, {@link #IGNORE_PARAM},
358: * and {@link #APPEND_PARAM}. It defines how to handle if both uri
359: * and params contains the same parameter.
360: */
361: public static final void sendRedirect(ServletContext ctx,
362: HttpServletRequest request, HttpServletResponse response,
363: String uri, Map params, int mode) throws IOException,
364: ServletException {
365: final String encodedUrl = encodeRedirectURL(ctx, request,
366: response, uri, params, mode);
367: if (D.ON && log.debugable())
368: log.debug("redirect to " + encodedUrl);
369: response.sendRedirect(encodedUrl);
370: }
371:
372: /** Encodes an URL such that it can be used with HttpServletResponse.sendRedirect.
373: */
374: public static final String encodeRedirectURL(ServletContext ctx,
375: HttpServletRequest request, HttpServletResponse response,
376: String uri, Map params, int mode) {
377: if (uri == null) {
378: uri = request.getContextPath()
379: + getOriginFullServlet(request);
380: } else {
381: final int len = uri.length();
382: if (len == 0 || uri.charAt(0) == '/') {
383: uri = request.getContextPath() + uri;
384: } else if (uri.charAt(0) == '~') {
385: final int j = uri.indexOf('/', 1);
386: final String ctxroot = j >= 0 ? "/"
387: + uri.substring(1, j) : "/" + uri.substring(1);
388: final ExtendletContext extctx = Servlets
389: .getExtendletContext(ctx, ctxroot.substring(1));
390: if (extctx != null) {
391: uri = j >= 0 ? uri.substring(j) : "/";
392: return extctx.encodeRedirectURL(request, response,
393: uri, params, mode);
394: } else {
395: uri = len >= 2 && uri.charAt(1) == '/' ? uri
396: .substring(1) : '/' + uri.substring(1);
397: }
398: }
399: }
400:
401: return response
402: .encodeRedirectURL(generateURI(uri, params, mode));
403: }
404:
405: /**
406: * Converts a date string to a Date instance.
407: * The format of the giving date string must be complaint
408: * to HTTP proptocol.
409: *
410: * @exception ParseException if the string is not valid
411: */
412: public static final Date toDate(String sdate) throws ParseException {
413: for (int j = 0;;) {
414: try {
415: synchronized (_dateFmts[j]) {
416: return _dateFmts[j].parse(sdate);
417: }
418: } catch (ParseException ex) {
419: if (++j == _dateFmts.length)
420: throw ex;
421: }
422: }
423: }
424:
425: /**
426: * Converts a data to a string complaint to HTTP protocol.
427: */
428: public static final String toString(Date date) {
429: synchronized (_dateFmts[0]) {
430: return _dateFmts[0].format(date);
431: }
432: }
433:
434: private static final SimpleDateFormat _dateFmts[] = {
435: new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz",
436: Locale.US),
437: new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz",
438: Locale.US),
439: new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
440: }
|