11848a29d323bd4d47581ae92b7551f4f236a3883dhanji/**
21848a29d323bd4d47581ae92b7551f4f236a3883dhanji * Copyright (C) 2010 Google Inc.
31848a29d323bd4d47581ae92b7551f4f236a3883dhanji *
41848a29d323bd4d47581ae92b7551f4f236a3883dhanji * Licensed under the Apache License, Version 2.0 (the "License");
51848a29d323bd4d47581ae92b7551f4f236a3883dhanji * you may not use this file except in compliance with the License.
61848a29d323bd4d47581ae92b7551f4f236a3883dhanji * You may obtain a copy of the License at
71848a29d323bd4d47581ae92b7551f4f236a3883dhanji *
81848a29d323bd4d47581ae92b7551f4f236a3883dhanji * http://www.apache.org/licenses/LICENSE-2.0
91848a29d323bd4d47581ae92b7551f4f236a3883dhanji *
101848a29d323bd4d47581ae92b7551f4f236a3883dhanji * Unless required by applicable law or agreed to in writing, software
111848a29d323bd4d47581ae92b7551f4f236a3883dhanji * distributed under the License is distributed on an "AS IS" BASIS,
121848a29d323bd4d47581ae92b7551f4f236a3883dhanji * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131848a29d323bd4d47581ae92b7551f4f236a3883dhanji * See the License for the specific language governing permissions and
141848a29d323bd4d47581ae92b7551f4f236a3883dhanji * limitations under the License.
151848a29d323bd4d47581ae92b7551f4f236a3883dhanji */
161848a29d323bd4d47581ae92b7551f4f236a3883dhanji
171848a29d323bd4d47581ae92b7551f4f236a3883dhanjipackage com.google.inject.servlet;
181848a29d323bd4d47581ae92b7551f4f236a3883dhanji
19d9c913acca55023ef5d76a32c3d4a51ee6b420cbsberlinimport com.google.common.collect.Maps;
20b7a02b02d81c830d148355c90bc309bcd66fb592sberlinimport com.google.inject.OutOfScopeException;
21b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
221848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport java.io.IOException;
231848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport java.util.Map;
24b7a02b02d81c830d148355c90bc309bcd66fb592sberlin
251848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport javax.servlet.ServletInputStream;
261848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport javax.servlet.http.Cookie;
271848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport javax.servlet.http.HttpServletRequest;
281848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport javax.servlet.http.HttpServletRequestWrapper;
291848a29d323bd4d47581ae92b7551f4f236a3883dhanjiimport javax.servlet.http.HttpSession;
301848a29d323bd4d47581ae92b7551f4f236a3883dhanji
311848a29d323bd4d47581ae92b7551f4f236a3883dhanji/**
321848a29d323bd4d47581ae92b7551f4f236a3883dhanji * A wrapper for requests that makes requests immutable, taking a snapshot
331848a29d323bd4d47581ae92b7551f4f236a3883dhanji * of the original request.
341848a29d323bd4d47581ae92b7551f4f236a3883dhanji *
351848a29d323bd4d47581ae92b7551f4f236a3883dhanji * @author dhanji@gmail.com (Dhanji R. Prasanna)
361848a29d323bd4d47581ae92b7551f4f236a3883dhanji */
371848a29d323bd4d47581ae92b7551f4f236a3883dhanjiclass ContinuingHttpServletRequest extends HttpServletRequestWrapper {
381848a29d323bd4d47581ae92b7551f4f236a3883dhanji
391848a29d323bd4d47581ae92b7551f4f236a3883dhanji  // We clear out the attributes as they are mutable and not thread-safe.
401848a29d323bd4d47581ae92b7551f4f236a3883dhanji  private final Map<String, Object> attributes = Maps.newHashMap();
413b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna  private final Cookie[] cookies;
421848a29d323bd4d47581ae92b7551f4f236a3883dhanji
431848a29d323bd4d47581ae92b7551f4f236a3883dhanji  public ContinuingHttpServletRequest(HttpServletRequest request) {
441848a29d323bd4d47581ae92b7551f4f236a3883dhanji    super(request);
453b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
463b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    Cookie[] originalCookies = request.getCookies();
473b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    if (originalCookies != null) {
483b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      int numberOfCookies = originalCookies.length;
493b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      cookies = new Cookie[numberOfCookies];
503b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      for (int i = 0; i < numberOfCookies; i++) {
513b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        Cookie originalCookie = originalCookies[i];
523b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
533b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        // Snapshot each cookie + freeze.
543b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        // No snapshot is required if this is a snapshot of a snapshot(!)
553b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        if (originalCookie instanceof ImmutableCookie) {
563b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna          cookies[i] = originalCookie;
573b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        } else {
583b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna          cookies[i] = new ImmutableCookie(originalCookie);
593b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        }
603b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      }
613b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    } else {
623b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      cookies = null;
633b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
641848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
651848a29d323bd4d47581ae92b7551f4f236a3883dhanji
661848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public HttpSession getSession() {
671848a29d323bd4d47581ae92b7551f4f236a3883dhanji    throw new OutOfScopeException("Cannot access the session in a continued request");
681848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
691848a29d323bd4d47581ae92b7551f4f236a3883dhanji
701848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public HttpSession getSession(boolean create) {
711848a29d323bd4d47581ae92b7551f4f236a3883dhanji    throw new UnsupportedOperationException("Cannot access the session in a continued request");
721848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
731848a29d323bd4d47581ae92b7551f4f236a3883dhanji
741848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public ServletInputStream getInputStream() throws IOException {
751848a29d323bd4d47581ae92b7551f4f236a3883dhanji    throw new UnsupportedOperationException("Cannot access raw request on a continued request");
761848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
771848a29d323bd4d47581ae92b7551f4f236a3883dhanji
781848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public void setAttribute(String name, Object o) {
791848a29d323bd4d47581ae92b7551f4f236a3883dhanji    attributes.put(name, o);
801848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
811848a29d323bd4d47581ae92b7551f4f236a3883dhanji
821848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public void removeAttribute(String name) {
831848a29d323bd4d47581ae92b7551f4f236a3883dhanji    attributes.remove(name);
841848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
851848a29d323bd4d47581ae92b7551f4f236a3883dhanji
861848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public Object getAttribute(String name) {
871848a29d323bd4d47581ae92b7551f4f236a3883dhanji    return attributes.get(name);
881848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
891848a29d323bd4d47581ae92b7551f4f236a3883dhanji
901848a29d323bd4d47581ae92b7551f4f236a3883dhanji  @Override public Cookie[] getCookies() {
913b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    // NOTE(dhanji): Cookies themselves are mutable. However a ContinuingHttpServletRequest
923b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    // snapshots the original set of cookies it received and imprisons them in immutable
933b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    // form. Unfortunately, the cookie array itself is mutable and there is no way for us
943b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    // to avoid this. At worst, however, mutation effects are restricted within the scope
953b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    // of a single request. Continued requests are not affected after snapshot time.
963b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    return cookies;
973b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna  }
983b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
993b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna  private static final class ImmutableCookie extends Cookie {
1003b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    public ImmutableCookie(Cookie original) {
1013b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super(original.getName(), original.getValue());
1023b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1033b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super.setMaxAge(original.getMaxAge());
1043b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super.setPath(original.getPath());
1053b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super.setComment(original.getComment());
1063b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super.setSecure(original.getSecure());
1073b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super.setValue(original.getValue());
1083b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      super.setVersion(original.getVersion());
1093b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1103b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      if (original.getDomain() != null) {
1113b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna        super.setDomain(original.getDomain());
1123b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      }
1133b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1143b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1153b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setComment(String purpose) {
1163b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
1173b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1183b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1193b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setDomain(String pattern) {
1203b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
1213b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1223b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1233b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setMaxAge(int expiry) {
1243b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
1253b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1263b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1273b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setPath(String uri) {
1283b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
1293b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1303b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1313b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setSecure(boolean flag) {
1323b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
1333b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1343b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1353b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setValue(String newValue) {
1363b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
1373b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    }
1383b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna
1393b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna    @Override public void setVersion(int v) {
1403b02622e856e845f9bc5353a494b5ccc75dec40cDhanji R. Prasanna      throw new UnsupportedOperationException("Cannot modify cookies on a continued request");
141882330dad166a44b2498c7c13dcab61d853cecddChristian Edward Gruber    }
1421848a29d323bd4d47581ae92b7551f4f236a3883dhanji  }
1431848a29d323bd4d47581ae92b7551f4f236a3883dhanji}
144