1 /** 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.servlet; 18 19 import com.google.common.collect.Maps; 20 import com.google.inject.OutOfScopeException; 21 22 import java.io.IOException; 23 import java.util.Map; 24 25 import javax.servlet.ServletInputStream; 26 import javax.servlet.http.Cookie; 27 import javax.servlet.http.HttpServletRequest; 28 import javax.servlet.http.HttpServletRequestWrapper; 29 import javax.servlet.http.HttpSession; 30 31 /** 32 * A wrapper for requests that makes requests immutable, taking a snapshot 33 * of the original request. 34 * 35 * @author dhanji@gmail.com (Dhanji R. Prasanna) 36 */ 37 class ContinuingHttpServletRequest extends HttpServletRequestWrapper { 38 39 // We clear out the attributes as they are mutable and not thread-safe. 40 private final Map<String, Object> attributes = Maps.newHashMap(); 41 private final Cookie[] cookies; 42 ContinuingHttpServletRequest(HttpServletRequest request)43 public ContinuingHttpServletRequest(HttpServletRequest request) { 44 super(request); 45 46 Cookie[] originalCookies = request.getCookies(); 47 if (originalCookies != null) { 48 int numberOfCookies = originalCookies.length; 49 cookies = new Cookie[numberOfCookies]; 50 for (int i = 0; i < numberOfCookies; i++) { 51 Cookie originalCookie = originalCookies[i]; 52 53 // Snapshot each cookie + freeze. 54 // No snapshot is required if this is a snapshot of a snapshot(!) 55 if (originalCookie instanceof ImmutableCookie) { 56 cookies[i] = originalCookie; 57 } else { 58 cookies[i] = new ImmutableCookie(originalCookie); 59 } 60 } 61 } else { 62 cookies = null; 63 } 64 } 65 getSession()66 @Override public HttpSession getSession() { 67 throw new OutOfScopeException("Cannot access the session in a continued request"); 68 } 69 getSession(boolean create)70 @Override public HttpSession getSession(boolean create) { 71 throw new UnsupportedOperationException("Cannot access the session in a continued request"); 72 } 73 getInputStream()74 @Override public ServletInputStream getInputStream() throws IOException { 75 throw new UnsupportedOperationException("Cannot access raw request on a continued request"); 76 } 77 setAttribute(String name, Object o)78 @Override public void setAttribute(String name, Object o) { 79 attributes.put(name, o); 80 } 81 removeAttribute(String name)82 @Override public void removeAttribute(String name) { 83 attributes.remove(name); 84 } 85 getAttribute(String name)86 @Override public Object getAttribute(String name) { 87 return attributes.get(name); 88 } 89 getCookies()90 @Override public Cookie[] getCookies() { 91 // NOTE(dhanji): Cookies themselves are mutable. However a ContinuingHttpServletRequest 92 // snapshots the original set of cookies it received and imprisons them in immutable 93 // form. Unfortunately, the cookie array itself is mutable and there is no way for us 94 // to avoid this. At worst, however, mutation effects are restricted within the scope 95 // of a single request. Continued requests are not affected after snapshot time. 96 return cookies; 97 } 98 99 private static final class ImmutableCookie extends Cookie { ImmutableCookie(Cookie original)100 public ImmutableCookie(Cookie original) { 101 super(original.getName(), original.getValue()); 102 103 super.setMaxAge(original.getMaxAge()); 104 super.setPath(original.getPath()); 105 super.setComment(original.getComment()); 106 super.setSecure(original.getSecure()); 107 super.setValue(original.getValue()); 108 super.setVersion(original.getVersion()); 109 110 if (original.getDomain() != null) { 111 super.setDomain(original.getDomain()); 112 } 113 } 114 setComment(String purpose)115 @Override public void setComment(String purpose) { 116 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 117 } 118 setDomain(String pattern)119 @Override public void setDomain(String pattern) { 120 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 121 } 122 setMaxAge(int expiry)123 @Override public void setMaxAge(int expiry) { 124 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 125 } 126 setPath(String uri)127 @Override public void setPath(String uri) { 128 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 129 } 130 setSecure(boolean flag)131 @Override public void setSecure(boolean flag) { 132 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 133 } 134 setValue(String newValue)135 @Override public void setValue(String newValue) { 136 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 137 } 138 setVersion(int v)139 @Override public void setVersion(int v) { 140 throw new UnsupportedOperationException("Cannot modify cookies on a continued request"); 141 } 142 } 143 } 144