001: /*
002: * The Apache Software License, Version 1.1
003: *
004: * Copyright (c) 2001-2004 Caucho Technology, Inc. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution, if
019: * any, must include the following acknowlegement:
020: * "This product includes software developed by the
021: * Caucho Technology (http://www.caucho.com/)."
022: * Alternately, this acknowlegement may appear in the software itself,
023: * if and wherever such third-party acknowlegements normally appear.
024: *
025: * 4. The names "Hessian", "Resin", and "Caucho" must not be used to
026: * endorse or promote products derived from this software without prior
027: * written permission. For written permission, please contact
028: * info@caucho.com.
029: *
030: * 5. Products derived from this software may not be called "Resin"
031: * nor may "Resin" appear in their names without prior written
032: * permission of Caucho Technology.
033: *
034: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
035: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
036: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
037: * DISCLAIMED. IN NO EVENT SHALL CAUCHO TECHNOLOGY OR ITS CONTRIBUTORS
038: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
039: * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
040: * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
041: * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
042: * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
043: * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
044: * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
045: *
046: * @author Sam
047: */
048:
049: package com.caucho.portal.generic;
050:
051: import javax.portlet.PortletContext;
052: import javax.portlet.PortletRequest;
053: import javax.portlet.PortletSecurityException;
054: import javax.portlet.PortletSession;
055: import javax.servlet.http.HttpServletRequest;
056: import javax.servlet.http.HttpServletResponse;
057: import javax.servlet.http.HttpSession;
058: import java.io.BufferedReader;
059: import java.io.IOException;
060: import java.io.InputStream;
061: import java.io.OutputStream;
062: import java.io.PrintWriter;
063: import java.io.UnsupportedEncodingException;
064: import java.security.Principal;
065: import java.util.Enumeration;
066: import java.util.LinkedHashSet;
067: import java.util.Locale;
068: import java.util.Set;
069:
070: /**
071: * A connection to an HttpServletRequest and HttpServletResponse.
072: */
073: public class HttpPortletConnection extends PortletConnection {
074: /**
075: * request attribute for the HttpServletRequest
076: */
077: final static public String HTTP_SERVLET_REQUEST = HttpPortletRequestDispatcher.HTTP_SERVLET_REQUEST;
078:
079: /**
080: * request attribute for the HttpServletResponse
081: */
082: final static public String HTTP_SERVLET_RESPONSE = HttpPortletRequestDispatcher.HTTP_SERVLET_RESPONSE;
083:
084: public static HttpServletRequest getHttpRequest(
085: PortletRequest request) {
086: return (HttpServletRequest) request
087: .getAttribute(HTTP_SERVLET_REQUEST);
088: }
089:
090: public static HttpServletResponse getHttpResponse(
091: PortletRequest request) {
092: return (HttpServletResponse) request
093: .getAttribute(HTTP_SERVLET_RESPONSE);
094: }
095:
096: private PortletContext _portletContext;
097: private HttpServletRequest _httpRequest;
098: private HttpServletResponse _httpResponse;
099:
100: private Object _oldHttpRequest;
101: private Object _oldHttpResponse;
102:
103: private String _servletUrl;
104:
105: private MapBasedInvocationFactory _createdInvocationFactory;
106:
107: private HttpPortletSession _portletSession;
108:
109: private Set<Locale> _clientLocales;
110: private Set<String> _clientCharacterEncodings;
111: private Set<String> _clientContentTypes;
112:
113: private boolean _isLocaleEstablished;
114: private boolean _isContentTypeEstablished;
115:
116: public HttpPortletConnection() {
117: }
118:
119: public void start(Portal portal, PortletContext portletContext,
120: HttpServletRequest httpRequest,
121: HttpServletResponse httpResponse, boolean useParameters) {
122: if (_createdInvocationFactory != null)
123: throw new IllegalStateException("missing finish?");
124:
125: _createdInvocationFactory = new MapBasedInvocationFactory();
126:
127: if (useParameters)
128: _createdInvocationFactory.start(httpRequest
129: .getParameterMap());
130: else
131: _createdInvocationFactory.start(null);
132:
133: start(portal, portletContext, httpRequest, httpResponse,
134: _createdInvocationFactory);
135: }
136:
137: public void start(Portal portal, PortletContext portletContext,
138: HttpServletRequest httpRequest,
139: HttpServletResponse httpResponse,
140: InvocationFactory invocationFactory) {
141: super .start(portal, invocationFactory);
142:
143: _portletContext = portletContext;
144: _httpRequest = httpRequest;
145: _httpResponse = httpResponse;
146:
147: _oldHttpRequest = _httpRequest
148: .getAttribute(HTTP_SERVLET_REQUEST);
149:
150: if (_oldHttpRequest != null)
151: _oldHttpResponse = _httpRequest
152: .getAttribute(HTTP_SERVLET_RESPONSE);
153:
154: _httpRequest.setAttribute(HTTP_SERVLET_REQUEST, _httpRequest);
155: _httpRequest.setAttribute(HTTP_SERVLET_RESPONSE, _httpResponse);
156:
157: _servletUrl = makeServletUrl(_httpRequest);
158: }
159:
160: protected String makeServletUrl(HttpServletRequest request) {
161: String scheme = request.getScheme();
162: String serverName = request.getServerName();
163: int port = request.getServerPort();
164:
165: if (port == 80 && scheme.equals("http"))
166: port = -1;
167:
168: if (port == 443 && scheme.equals("https"))
169: port = -1;
170:
171: String contextPath = (String) request
172: .getAttribute("javax.servlet.include.context_path");
173:
174: String servletPath;
175:
176: if (contextPath == null) {
177: contextPath = request.getContextPath();
178: servletPath = request.getServletPath();
179: } else {
180: servletPath = (String) request
181: .getAttribute("javax.servlet.include.servlet_path");
182: }
183:
184: StringBuffer buf = new StringBuffer(256);
185:
186: buf.append(scheme);
187: buf.append("://");
188: buf.append(serverName);
189: if (port > 0) {
190: buf.append(':');
191: buf.append(port);
192: }
193: buf.append(contextPath);
194: buf.append(servletPath);
195:
196: return buf.toString();
197: }
198:
199: public void finish() {
200: int expirationCache = getExpirationCache();
201:
202: if (expirationCache == 0) {
203: _httpResponse.setHeader("Cache-Control",
204: "no-cache,post-check=0,pre-check=0");
205:
206: _httpResponse.setHeader("Pragma", "no-cache");
207: _httpResponse.setHeader("Expires",
208: "Thu,01Dec199416:00:00GMT");
209: } else {
210: if (isPrivate()) {
211: _httpResponse.setHeader("Cache-Control",
212: "private,max-age=" + expirationCache);
213: } else {
214: _httpResponse.setHeader("Cache-Control", "max-age="
215: + expirationCache);
216: }
217: }
218:
219: _isLocaleEstablished = false;
220: _isContentTypeEstablished = false;
221:
222: _clientLocales = null;
223: _clientCharacterEncodings = null;
224: _clientContentTypes = null;
225:
226: PortletContext portletContext = _portletContext;
227: MapBasedInvocationFactory createdInvocationFactory = _createdInvocationFactory;
228: HttpServletRequest httpRequest = _httpRequest;
229: Object oldHttpRequest = _oldHttpRequest;
230: HttpServletResponse httpResponse = _httpResponse;
231: Object oldHttpResponse = _oldHttpResponse;
232: HttpPortletSession portletSession = _portletSession;
233:
234: _servletUrl = null;
235:
236: _portletContext = null;
237: _portletSession = null;
238: _oldHttpRequest = null;
239: _oldHttpResponse = null;
240: _createdInvocationFactory = null;
241: _httpRequest = null;
242: _httpResponse = null;
243:
244: httpRequest
245: .setAttribute(HTTP_SERVLET_RESPONSE, oldHttpResponse);
246: httpRequest.setAttribute(HTTP_SERVLET_REQUEST, oldHttpRequest);
247:
248: super .finish();
249:
250: if (portletSession != null)
251: portletSession.finish();
252:
253: if (createdInvocationFactory != null)
254: createdInvocationFactory.finish();
255: }
256:
257: public HttpServletRequest getHttpRequest() {
258: return _httpRequest;
259: }
260:
261: public HttpServletResponse getHttpResponse() {
262: return _httpResponse;
263: }
264:
265: /**
266: * Get the content types acceptable to the client. The returned Set
267: * is ordered, the most preferrable content types appear before the least
268: * preferred.
269: *
270: * This implementation returns the content types that appear in the
271: * String returned by getProperty("Accept") in the order
272: * they appear in the string.
273: *
274: * @return the Set, null if client content types cannot be determined
275: */
276: public Set<String> getClientContentTypes() {
277: if (_clientContentTypes != null)
278: return _clientContentTypes;
279:
280: _clientContentTypes = HttpUtil
281: .getHeaderElements(getProperty("Accept"));
282:
283: return _clientContentTypes;
284: }
285:
286: /**
287: * Get the locales acceptable to the client. The returned Set is ordered,
288: * the most preferrable locale appears before the least preferred. If the
289: * client supports all locales, then a Locale("","","") will be present in
290: * the returned Set.
291: *
292: * This implementation returns the locales that appear in the String returned
293: * by getProperty("Accept-Language") in the order they appear in the
294: * string. If the "*" element is present in the header, then a new
295: * Locale("","","") is present in the set.
296: *
297: * @return the Set, null if client locales cannot be determined
298: */
299: public Set<Locale> getClientLocales() {
300: if (_clientLocales != null)
301: return _clientLocales;
302:
303: _clientLocales = new LinkedHashSet<Locale>();
304: _clientLocales.add(_httpRequest.getLocale());
305:
306: Enumeration en = _httpRequest.getLocales();
307:
308: while (en.hasMoreElements()) {
309: _clientLocales.add((Locale) en.nextElement());
310: }
311:
312: return _clientLocales;
313: }
314:
315: /**
316: * Get the character encodings acceptable to the client. The returned Set is
317: * order, the most preferrable character encoding appears before the least
318: * preferred.
319: *
320: * This implementation returns the character encodings that appear in the
321: * String returned by getProperty("Accept-Charset") in the order
322: * they appear in the string.
323: *
324: * @return the Set, null if client character encodings cannot be determined
325: */
326: public Set<String> getClientCharacterEncodings() {
327: if (_clientCharacterEncodings != null)
328: return _clientCharacterEncodings;
329:
330: _clientCharacterEncodings = HttpUtil
331: .getHeaderElements(getProperty("Accept-Charset"));
332:
333: return _clientCharacterEncodings;
334: }
335:
336: public String resolveURL(String url) {
337: StringBuffer buf = new StringBuffer(256);
338: appendUrlPrefix(_httpRequest, buf);
339: buf.append(url);
340: return buf.toString();
341: }
342:
343: /**
344: * Resolve the url with the given security level and encode it.
345: *
346: * This implementation calls resolveURL(String) if <i>secure</i>
347: * is <code>false</code>.
348: *
349: * If <i>secure</i> is <code>true</code>, the prefix set with
350: * setSecureUrlPrefix() is prepended.
351: *
352: * @throws PortletSecurityException if secure is true but the url
353: * cannot be made secure because setSecureUrlPrefix() has not been called.
354: */
355: public String resolveURL(String url, boolean secure)
356: throws PortletSecurityException {
357: if (secure == false)
358: return resolveURL(url);
359: else {
360: StringBuffer buf = new StringBuffer(256);
361:
362: appendSecureUrlPrefix(_httpRequest, buf);
363: buf.append(url);
364: return buf.toString();
365: }
366: }
367:
368: private String appendUrlPrefix(HttpServletRequest request,
369: StringBuffer buf) {
370: buf.append(_servletUrl);
371: return buf.toString();
372: }
373:
374: private String appendSecureUrlPrefix(HttpServletRequest request,
375: StringBuffer buf) throws PortletSecurityException {
376: // XXX:
377:
378: if (request.isSecure())
379: return appendUrlPrefix(request, buf);
380: else
381: throw new PortletSecurityException("cannot make url secure");
382: }
383:
384: public boolean handleConstraintFailure(Constraint constraint,
385: int failureCode) throws IOException {
386: if (failureCode == Constraint.SC_FORBIDDEN) {
387: _httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
388: } else {
389: _httpResponse
390: .sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE);
391: }
392:
393: return true;
394: }
395:
396: public boolean handleException(Exception exception) {
397: return false;
398: }
399:
400: /**
401: * Return true if the connection can guarantee integrity
402: * (preventing data tampering in the communication process).
403: */
404: public boolean canGuaranteeIntegrity() {
405: return isSecure();
406: }
407:
408: /**
409: * Return true if the connection can guarantee confidentiality (preventing
410: * reading while in transit).
411: */
412: public boolean canGuaranteeConfidentiality() {
413: return isSecure();
414: }
415:
416: /**
417: * Attributes for the connection are HttpServletRequest attributes.
418: */
419: public Object getAttribute(String name) {
420: return _httpRequest.getAttribute(name);
421: }
422:
423: /**
424: * Attributes for the connection are HttpServletRequest attributes.
425: */
426: public void setAttribute(String name, Object o) {
427: _httpRequest.setAttribute(name, o);
428: }
429:
430: /**
431: * Attributes for the connection are HttpServletRequest attributes.
432: */
433: public void removeAttribute(String name) {
434: _httpRequest.removeAttribute(name);
435: }
436:
437: /**
438: * Attributes for the connection are HttpServletRequest attributes.
439: */
440: public Enumeration getAttributeNames() {
441: return _httpRequest.getAttributeNames();
442: }
443:
444: public PortletSession getPortletSession(boolean create) {
445: if (_portletSession != null)
446: return _portletSession;
447:
448: HttpSession httpSession = _httpRequest.getSession(create);
449:
450: if (httpSession != null) {
451: // XXX: pool these
452: _portletSession = new HttpPortletSession();
453: _portletSession.start(_portletContext, httpSession);
454: }
455:
456: return _portletSession;
457: }
458:
459: public String getScheme() {
460: return _httpRequest.getScheme();
461: }
462:
463: public String getServerName() {
464: return _httpRequest.getServerName();
465: }
466:
467: public int getServerPort() {
468: return _httpRequest.getServerPort();
469: }
470:
471: public String getContextPath() {
472: return _httpRequest.getContextPath();
473: }
474:
475: public String getAuthType() {
476: String authType = _httpRequest.getAuthType();
477:
478: if (authType == null)
479: return null;
480: else if (authType == HttpServletRequest.BASIC_AUTH)
481: return PortletRequest.BASIC_AUTH;
482: /** XXX: bug in caucho impl of jsdk
483: else if (authType == HttpServletRequest.CLIENT_CERT_AUTH)
484: return PortletRequest.CLIENT_CERT_AUTH;
485: */
486: else if (authType == HttpServletRequest.DIGEST_AUTH)
487: return PortletRequest.DIGEST_AUTH;
488: else if (authType == HttpServletRequest.FORM_AUTH)
489: return PortletRequest.FORM_AUTH;
490: else if (authType.equals(HttpServletRequest.BASIC_AUTH))
491: return PortletRequest.BASIC_AUTH;
492: else if (authType.equals("CLIENT_CERT")) // XXX: bug in caucho impl of jsdk
493: return PortletRequest.CLIENT_CERT_AUTH;
494: else if (authType.equals(HttpServletRequest.DIGEST_AUTH))
495: return PortletRequest.DIGEST_AUTH;
496: else if (authType.equals(HttpServletRequest.FORM_AUTH))
497: return PortletRequest.FORM_AUTH;
498: else
499: return authType;
500: }
501:
502: public boolean isSecure() {
503: return _httpRequest.isSecure();
504: }
505:
506: public String getRequestedSessionId() {
507: return _httpRequest.getRequestedSessionId();
508: }
509:
510: public boolean isRequestedSessionIdValid() {
511: return _httpRequest.isRequestedSessionIdValid();
512: }
513:
514: public String getRemoteUser() {
515: return _httpRequest.getRemoteUser();
516: }
517:
518: public Principal getUserPrincipal() {
519: return _httpRequest.getUserPrincipal();
520: }
521:
522: public boolean isUserInRole(String role) {
523: return _httpRequest.isUserInRole(role);
524: }
525:
526: public String getProperty(String propertyName) {
527: return _httpRequest.getHeader(propertyName);
528: }
529:
530: public Enumeration getProperties(String propertyName) {
531: return _httpRequest.getHeaders(propertyName);
532: }
533:
534: public Enumeration getPropertyNames() {
535: return _httpRequest.getHeaderNames();
536: }
537:
538: public String getSubmitContentType() {
539: return _httpRequest.getContentType();
540: }
541:
542: public int getSubmitContentLength() {
543: return _httpRequest.getContentLength();
544: }
545:
546: public InputStream getSubmitInputStream() throws IOException {
547: return _httpRequest.getInputStream();
548: }
549:
550: public void setSubmitCharacterEncoding(String enc)
551: throws UnsupportedEncodingException, IllegalStateException {
552: _httpRequest.setCharacterEncoding(enc);
553: }
554:
555: public String getSubmitCharacterEncoding() {
556: return _httpRequest.getCharacterEncoding();
557: }
558:
559: public BufferedReader getSubmitReader()
560: throws UnsupportedEncodingException, IOException {
561: return _httpRequest.getReader();
562: }
563:
564: /**
565: * A path with a schem is encoded only.
566: *
567: * A relative location (does not start with slash) is resolved relative to
568: * the servlet path and then encoded.
569: *
570: * An absolute url (begins with slash) is resolved relative to
571: * the context path and then encoded.
572: */
573: public String encodeURL(String location) {
574: int slash = location.indexOf('/');
575: int colon = location.indexOf(':');
576:
577: if (colon == -1 || slash < colon) {
578:
579: String scheme = _httpRequest.getScheme();
580: String serverName = _httpRequest.getServerName();
581: int port = _httpRequest.getServerPort();
582:
583: if (port == 80 && scheme.equals("http"))
584: port = -1;
585:
586: if (port == 443 && scheme.equals("https"))
587: port = -1;
588:
589: String contextPath = (String) _httpRequest
590: .getAttribute("javax.servlet.include.context_path");
591: String servletPath = null;
592:
593: if (contextPath == null) {
594: contextPath = _httpRequest.getContextPath();
595: servletPath = _httpRequest.getServletPath();
596: }
597:
598: StringBuffer buf = new StringBuffer();
599:
600: buf.append(scheme);
601: buf.append("://");
602: buf.append(serverName);
603:
604: if (port > 0) {
605: buf.append(':');
606: buf.append(port);
607: }
608:
609: buf.append(contextPath);
610:
611: if (slash != 0) {
612:
613: if (servletPath == null)
614: servletPath = (String) _httpRequest
615: .getAttribute("javax.servlet.include.servlet_path");
616:
617: buf.append(servletPath);
618:
619: buf.append('/');
620:
621: buf.append(location);
622: } else {
623: buf.append(location);
624: }
625:
626: location = buf.toString();
627: }
628:
629: return _httpResponse.encodeURL(location);
630: }
631:
632: public void sendRedirect(String location) throws IOException {
633: String url = _httpResponse.encodeRedirectURL(location);
634:
635: _httpResponse.sendRedirect(url);
636: }
637:
638: public void setProperty(String name, String value) {
639: _httpResponse.setHeader(name, value);
640: }
641:
642: public void addProperty(String name, String value) {
643: _httpResponse.addHeader(name, value);
644: }
645:
646: public void setContentType(String contentType) {
647: _isContentTypeEstablished = true;
648: _httpResponse.setContentType(contentType);
649: }
650:
651: /**
652: * Return the content type established with setContentType(), or null if
653: * setContentType() has not been called.
654: */
655: public String getContentType() {
656: if (_isContentTypeEstablished)
657: return _httpResponse.getContentType();
658: else
659: return null;
660: }
661:
662: public void setLocale(Locale locale) {
663: _isLocaleEstablished = true;
664: _httpResponse.setLocale(locale);
665: }
666:
667: /**
668: * Return the Locale established with setLocale(), or null if setLocale()
669: * has not been called.
670: */
671: public Locale getLocale() {
672: if (_isLocaleEstablished)
673: return _httpResponse.getLocale();
674: else
675: return null;
676: }
677:
678: public void setBufferSize(int size) {
679: _httpResponse.setBufferSize(size);
680: }
681:
682: public int getBufferSize() {
683: return _httpResponse.getBufferSize();
684: }
685:
686: public void flushBuffer() throws IOException {
687: _httpResponse.flushBuffer();
688: }
689:
690: public void resetBuffer() {
691: _httpResponse.resetBuffer();
692: }
693:
694: public void reset() {
695: _httpResponse.reset();
696: }
697:
698: public boolean isCommitted() {
699: return _httpResponse.isCommitted();
700: }
701:
702: public OutputStream getOutputStream() throws IOException {
703: return _httpResponse.getOutputStream();
704: }
705:
706: public String getCharacterEncoding() {
707: return _httpResponse.getCharacterEncoding();
708: }
709:
710: public void setCharacterEncoding(String enc)
711: throws UnsupportedEncodingException {
712: _httpResponse.setCharacterEncoding(enc);
713: }
714:
715: public PrintWriter getWriter() throws IOException {
716: return _httpResponse.getWriter();
717: }
718:
719: }
|