|
View:
New views
17 Messages
—
Rating Filter:
Alert me
|
|
|
Share session cookie across subdomainsI'm working on a site that has a single web app in Tomcat that handles
lots of subdomains via wildcard DNS: - site.com - www.site.com - sub1.site.com - sub2.site.com - etc. Basically, the site content gets customized based on the subdomain in the request, if any. However I ran into a problem where Tomcat would use separate JSESSIONID session cookies on each different domain which causes problems as the user would have multiple sessions if they switched subdomains. I found an examle Valve at http://www.esus.be/blog/?p=3 but it ultimately did not result in a cross-subdomain session cookie (at least in the Tomcat 6.0.14 I'm using). I'm posting the Valve that did actually seem to solve the problem for me below in hopes that it will help someone else with the same problem in the future. Basically you end up with a single session cookie with its domain set to .site.com so the client will send it back in the request for any subdomain. Usage: - compile CrossSubdomainSessionValve & put it in a .jar file - put that .jar file in $CATALINA_HOME/lib directory - include a <Valve className="org.three3s.valves.CrossSubdomainSessionValve"/> in $CATALINA_HOME/conf/server.xml If you see/experience any problems please let me know! Thanks, Zach package org.three3s.valves; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.catalina.*; import org.apache.catalina.connector.*; import org.apache.catalina.valves.*; import org.apache.tomcat.util.buf.*; import org.apache.tomcat.util.http.*; /** <p>Replaces the domain of the session cookie generated by Tomcat with a domain that allows that * session cookie to be shared across subdomains. This valve digs down into the response headers * and replaces the Set-Cookie header for the session cookie, instead of futilely trying to * modify an existing Cookie object like the example at http://www.esus.be/blog/?p=3. That * approach does not work (at least as of Tomcat 6.0.14) because the * <code>org.apache.catalina.connector.Response.addCookieInternal</code> method renders the * cookie into the Set-Cookie response header immediately, making any subsequent modifying calls * on the Cookie object ultimately pointless.</p> * * <p>This results in a single, cross-subdomain session cookie on the client that allows the * session to be shared across all subdomains. However, see the {@link getCookieDomain(Request)} * method for limits on the subdomains.</p> * * <p>Note though, that this approach will fail if the response has already been committed. Thus, * this valve forces Tomcat to generate the session cookie and then replaces it before invoking * the next valve in the chain. Hopefully this is early enough in the valve-processing chain * that the response will not have already been committed. You are advised to define this * valve as early as possible in server.xml to ensure that the response has not already been * committed when this valve is invoked.</p> * * <p>We recommend that you define this valve in server.xml immediately after the Catalina Engine * as follows: * <pre> * <Engine name="Catalina"...> * <Valve className="org.three3s.valves.CrossSubdomainSessionValve"/> * </pre> * </p> */ public class CrossSubdomainSessionValve extends ValveBase { public CrossSubdomainSessionValve() { super(); info = "org.three3s.valves.CrossSubdomainSessionValve/1.0"; } @Override public void invoke(Request request, Response response) throws IOException, ServletException { //this will cause Request.doGetSession to create the session cookie if necessary request.getSession(true); //replace any Tomcat-generated session cookies with our own Cookie[] cookies = response.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; containerLog.debug("CrossSubdomainSessionValve: Cookie name is " + cookie.getName()); if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) replaceCookie(request, response, cookie); } } //process the next valve getNext().invoke(request, response); } /** Replaces the value of the response header used to set the specified cookie to a value * with the cookie's domain set to the value returned by <code>getCookieDomain(request)</code> * * @param request * @param response * @param cookie cookie to be replaced. */ @SuppressWarnings("unchecked") protected void replaceCookie(Request request, Response response, Cookie cookie) { //copy the existing session cookie, but use a different domain Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue()); if (cookie.getPath() != null) newCookie.setPath(cookie.getPath()); newCookie.setDomain(getCookieDomain(request)); newCookie.setMaxAge(cookie.getMaxAge()); newCookie.setVersion(cookie.getVersion()); if (cookie.getComment() != null) newCookie.setComment(cookie.getComment()); newCookie.setSecure(cookie.getSecure()); //if the response has already been committed, our replacement strategy will have no effect if (response.isCommitted()) containerLog.error("CrossSubdomainSessionValve: response was already committed!"); //find the Set-Cookie header for the existing cookie and replace its value with new cookie MimeHeaders headers = response.getCoyoteResponse().getMimeHeaders(); for (int i = 0, size = headers.size(); i < size; i++) { if (headers.getName(i).equals("Set-Cookie")) { MessageBytes value = headers.getValue(i); if (value.indexOf(cookie.getName()) >= 0) { StringBuffer buffer = new StringBuffer(); ServerCookie.appendCookieValue(buffer, newCookie.getVersion(), newCookie .getName(), newCookie.getValue(), newCookie.getPath(), newCookie .getDomain(), newCookie.getComment(), newCookie.getMaxAge(), newCookie .getSecure()); containerLog.debug("CrossSubdomainSessionValve: old Set-Cookie value: " + value.toString()); containerLog.debug("CrossSubdomainSessionValve: new Set-Cookie value: " + buffer); value.setString(buffer.toString()); } } } } /** Returns the last two parts of the specified request's server name preceded by a dot. * Using this as the session cookie's domain allows the session to be shared across subdomains. * Note that this implies the session can only be used with domains consisting of two or * three parts, according to the domain-matching rules specified in RFC 2109 and RFC 2965. * * <p>Examples:</p> * <ul> * <li>foo.com => .foo.com</li> * <li>www.foo.com => .foo.com</li> * <li>bar.foo.com => .foo.com</li> * <li>abc.bar.foo.com => .foo.com - this means cookie won't work on abc.bar.foo.com!</li> * </ul> * * @param request provides the server name used to create cookie domain. * @return the last two parts of the specified request's server name preceded by a dot. */ protected String getCookieDomain(Request request) { String cookieDomain = request.getServerName(); String[] parts = cookieDomain.split("\\."); if (parts.length >= 2) cookieDomain = parts[parts.length - 2] + "." + parts[parts.length - 1]; return "." + cookieDomain; } public String toString() { return ("CrossSubdomainSessionValve[container=" + container.getName() + ']'); } } --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Share session cookie across subdomainshow about adding either, a property that allows you to specify the
number of domain parts (accounting for domain.co.uk for example), or the actual domain? p Zach Cox wrote: > I'm working on a site that has a single web app in Tomcat that handles > lots of subdomains via wildcard DNS: > - site.com > - www.site.com > - sub1.site.com > - sub2.site.com > - etc. > > Basically, the site content gets customized based on the subdomain in > the request, if any. However I ran into a problem where Tomcat would > use separate JSESSIONID session cookies on each different domain which > causes problems as the user would have multiple sessions if they > switched subdomains. > > I found an examle Valve at http://www.esus.be/blog/?p=3 but it > ultimately did not result in a cross-subdomain session cookie (at > least in the Tomcat 6.0.14 I'm using). I'm posting the Valve that did > actually seem to solve the problem for me below in hopes that it will > help someone else with the same problem in the future. > > Basically you end up with a single session cookie with its domain set > to .site.com so the client will send it back in the request for any > subdomain. > > Usage: > - compile CrossSubdomainSessionValve & put it in a .jar file > - put that .jar file in $CATALINA_HOME/lib directory > - include a <Valve > className="org.three3s.valves.CrossSubdomainSessionValve"/> in > $CATALINA_HOME/conf/server.xml > > If you see/experience any problems please let me know! > > Thanks, > Zach > > > package org.three3s.valves; > > import java.io.*; > > import javax.servlet.*; > import javax.servlet.http.*; > > import org.apache.catalina.*; > import org.apache.catalina.connector.*; > import org.apache.catalina.valves.*; > import org.apache.tomcat.util.buf.*; > import org.apache.tomcat.util.http.*; > > /** <p>Replaces the domain of the session cookie generated by Tomcat > with a domain that allows that > * session cookie to be shared across subdomains. This valve digs > down into the response headers > * and replaces the Set-Cookie header for the session cookie, instead > of futilely trying to > * modify an existing Cookie object like the example at > http://www.esus.be/blog/?p=3. That > * approach does not work (at least as of Tomcat 6.0.14) because the > * <code>org.apache.catalina.connector.Response.addCookieInternal</code> > method renders the > * cookie into the Set-Cookie response header immediately, making any > subsequent modifying calls > * on the Cookie object ultimately pointless.</p> > * > * <p>This results in a single, cross-subdomain session cookie on the > client that allows the > * session to be shared across all subdomains. However, see the > {@link getCookieDomain(Request)} > * method for limits on the subdomains.</p> > * > * <p>Note though, that this approach will fail if the response has > already been committed. Thus, > * this valve forces Tomcat to generate the session cookie and then > replaces it before invoking > * the next valve in the chain. Hopefully this is early enough in the > valve-processing chain > * that the response will not have already been committed. You are > advised to define this > * valve as early as possible in server.xml to ensure that the > response has not already been > * committed when this valve is invoked.</p> > * > * <p>We recommend that you define this valve in server.xml > immediately after the Catalina Engine > * as follows: > * <pre> > * <Engine name="Catalina"...> > * <Valve className="org.three3s.valves.CrossSubdomainSessionValve"/> > * </pre> > * </p> > */ > public class CrossSubdomainSessionValve extends ValveBase > { > public CrossSubdomainSessionValve() > { > super(); > info = "org.three3s.valves.CrossSubdomainSessionValve/1.0"; > } > > @Override > public void invoke(Request request, Response response) throws > IOException, ServletException > { > //this will cause Request.doGetSession to create the session > cookie if necessary > request.getSession(true); > > //replace any Tomcat-generated session cookies with our own > Cookie[] cookies = response.getCookies(); > if (cookies != null) > { > for (int i = 0; i < cookies.length; i++) > { > Cookie cookie = cookies[i]; > containerLog.debug("CrossSubdomainSessionValve: Cookie > name is " + cookie.getName()); > if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) > replaceCookie(request, response, cookie); > } > } > > //process the next valve > getNext().invoke(request, response); > } > > /** Replaces the value of the response header used to set the > specified cookie to a value > * with the cookie's domain set to the value returned by > <code>getCookieDomain(request)</code> > * > * @param request > * @param response > * @param cookie cookie to be replaced. > */ > @SuppressWarnings("unchecked") > protected void replaceCookie(Request request, Response response, > Cookie cookie) > { > //copy the existing session cookie, but use a different domain > Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue()); > if (cookie.getPath() != null) > newCookie.setPath(cookie.getPath()); > newCookie.setDomain(getCookieDomain(request)); > newCookie.setMaxAge(cookie.getMaxAge()); > newCookie.setVersion(cookie.getVersion()); > if (cookie.getComment() != null) > newCookie.setComment(cookie.getComment()); > newCookie.setSecure(cookie.getSecure()); > > //if the response has already been committed, our replacement > strategy will have no effect > if (response.isCommitted()) > containerLog.error("CrossSubdomainSessionValve: response > was already committed!"); > > //find the Set-Cookie header for the existing cookie and > replace its value with new cookie > MimeHeaders headers = response.getCoyoteResponse().getMimeHeaders(); > for (int i = 0, size = headers.size(); i < size; i++) > { > if (headers.getName(i).equals("Set-Cookie")) > { > MessageBytes value = headers.getValue(i); > if (value.indexOf(cookie.getName()) >= 0) > { > StringBuffer buffer = new StringBuffer(); > ServerCookie.appendCookieValue(buffer, > newCookie.getVersion(), newCookie > .getName(), newCookie.getValue(), > newCookie.getPath(), newCookie > .getDomain(), newCookie.getComment(), > newCookie.getMaxAge(), newCookie > .getSecure()); > containerLog.debug("CrossSubdomainSessionValve: > old Set-Cookie value: " > + value.toString()); > containerLog.debug("CrossSubdomainSessionValve: > new Set-Cookie value: " + buffer); > value.setString(buffer.toString()); > } > } > } > } > > /** Returns the last two parts of the specified request's server > name preceded by a dot. > * Using this as the session cookie's domain allows the session to > be shared across subdomains. > * Note that this implies the session can only be used with > domains consisting of two or > * three parts, according to the domain-matching rules specified > in RFC 2109 and RFC 2965. > * > * <p>Examples:</p> > * <ul> > * <li>foo.com => .foo.com</li> > * <li>www.foo.com => .foo.com</li> > * <li>bar.foo.com => .foo.com</li> > * <li>abc.bar.foo.com => .foo.com - this means cookie won't work > on abc.bar.foo.com!</li> > * </ul> > * > * @param request provides the server name used to create cookie domain. > * @return the last two parts of the specified request's server > name preceded by a dot. > */ > protected String getCookieDomain(Request request) > { > String cookieDomain = request.getServerName(); > String[] parts = cookieDomain.split("\\."); > if (parts.length >= 2) > cookieDomain = parts[parts.length - 2] + "." + > parts[parts.length - 1]; > return "." + cookieDomain; > } > > public String toString() > { > return ("CrossSubdomainSessionValve[container=" + > container.getName() + ']'); > } > } > > --------------------------------------------------------------------- > To start a new topic, e-mail: users@... > To unsubscribe, e-mail: users-unsubscribe@... > For additional commands, e-mail: users-help@... > > --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Share session cookie across subdomainsThat's a really good idea and could definitely be done by modifying the getCookieDomain method. I whipped that method up pretty quickly for my own purposes - and you're correct, this currently won't work with two-part TLDs like .co.uk. If I get some spare time (already used 2 days of this project creating the existing valve) I'll add that. But I think there should be 3 use cases in server.xml:
1) Default - just assume 2 parts in cookie domain to extract from server name, like .domain.com: <Valve class="className="org.three3s.valves.CrossSubdomainSessionValve" /> 2) Specify number of parts in cookie domain to support .domain.co.uk: <Valve class="className="org.three3s.valves.CrossSubdomainSessionValve" partCount="3" /> #2 could also be used to support multi-level subdomains like a.b.domain.com. RFCs 2109 & 2965 say that a cookie with domain .domain.com will not be sent in a request to a.b.domain.com; instead it would need to be .b.domain.com. I haven't tested that so I don't know if that's accurate in practice or not. You'd need to be careful though if your app supports subdomains with different levels, like a.b.domain.com and c.domain.com etc. You may end up with session cookies for .b.domain.com and .domain.com and I haven't thought enough about if there would be confusion in a request for c.domain.com or b.comain.com. 3) Specify the actual cookie domain to use: <Valve class="className="org.three3s.valves.CrossSubdomainSessionValve" cookieDomain=".domain.com" /> So to support #2 and #3 CrossSubdomainSessionValve would need partCount and cookieDomain fields with get/set methods and would then use those, if specified, in the getCookieDomain method. Until I have time to implement & test I will leave this as an exercise to the reader. ;) |
|
|
RE: Share session cookie across subdomainsWith your implementation, the valve will have the effect that a session
is created upon first access to a server, not only when required by the application. (see also discussion on http://www.nabble.com/Cookie-less-session-tracking---whats-are-the-downs ides-tp16738472p16738472.html ) Thus, the valve is only suitable if this behavior is acceptable. (e.g. if you can be sure that your site is not accessed by search engine robots, if you have a rather short session timeout and can live with the overhead of creating many unnecessary session objects, ...) -- Matthias -----Original Message----- From: Zach Cox [mailto:zcox522@...] Sent: Saturday, April 19, 2008 10:26 PM To: users@... Subject: Share session cookie across subdomains I'm working on a site that has a single web app in Tomcat that handles lots of subdomains via wildcard DNS: - site.com - www.site.com - sub1.site.com - sub2.site.com - etc. Basically, the site content gets customized based on the subdomain in the request, if any. However I ran into a problem where Tomcat would use separate JSESSIONID session cookies on each different domain which causes problems as the user would have multiple sessions if they switched subdomains. I found an examle Valve at http://www.esus.be/blog/?p=3 but it ultimately did not result in a cross-subdomain session cookie (at least in the Tomcat 6.0.14 I'm using). I'm posting the Valve that did actually seem to solve the problem for me below in hopes that it will help someone else with the same problem in the future. Basically you end up with a single session cookie with its domain set to .site.com so the client will send it back in the request for any subdomain. Usage: - compile CrossSubdomainSessionValve & put it in a .jar file - put that .jar file in $CATALINA_HOME/lib directory - include a <Valve className="org.three3s.valves.CrossSubdomainSessionValve"/> in $CATALINA_HOME/conf/server.xml If you see/experience any problems please let me know! Thanks, Zach package org.three3s.valves; import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import org.apache.catalina.*; import org.apache.catalina.connector.*; import org.apache.catalina.valves.*; import org.apache.tomcat.util.buf.*; import org.apache.tomcat.util.http.*; /** <p>Replaces the domain of the session cookie generated by Tomcat with a domain that allows that * session cookie to be shared across subdomains. This valve digs down into the response headers * and replaces the Set-Cookie header for the session cookie, instead of futilely trying to * modify an existing Cookie object like the example at http://www.esus.be/blog/?p=3. That * approach does not work (at least as of Tomcat 6.0.14) because the * <code>org.apache.catalina.connector.Response.addCookieInternal</code> method renders the * cookie into the Set-Cookie response header immediately, making any subsequent modifying calls * on the Cookie object ultimately pointless.</p> * * <p>This results in a single, cross-subdomain session cookie on the client that allows the * session to be shared across all subdomains. However, see the {@link getCookieDomain(Request)} * method for limits on the subdomains.</p> * * <p>Note though, that this approach will fail if the response has already been committed. Thus, * this valve forces Tomcat to generate the session cookie and then replaces it before invoking * the next valve in the chain. Hopefully this is early enough in the valve-processing chain * that the response will not have already been committed. You are advised to define this * valve as early as possible in server.xml to ensure that the response has not already been * committed when this valve is invoked.</p> * * <p>We recommend that you define this valve in server.xml immediately after the Catalina Engine * as follows: * <pre> * <Engine name="Catalina"...> * <Valve className="org.three3s.valves.CrossSubdomainSessionValve"/> * </pre> * </p> */ public class CrossSubdomainSessionValve extends ValveBase { public CrossSubdomainSessionValve() { super(); info = "org.three3s.valves.CrossSubdomainSessionValve/1.0"; } @Override public void invoke(Request request, Response response) throws IOException, ServletException { //this will cause Request.doGetSession to create the session cookie if necessary request.getSession(true); //replace any Tomcat-generated session cookies with our own Cookie[] cookies = response.getCookies(); if (cookies != null) { for (int i = 0; i < cookies.length; i++) { Cookie cookie = cookies[i]; containerLog.debug("CrossSubdomainSessionValve: Cookie name is " + cookie.getName()); if (Globals.SESSION_COOKIE_NAME.equals(cookie.getName())) replaceCookie(request, response, cookie); } } //process the next valve getNext().invoke(request, response); } /** Replaces the value of the response header used to set the specified cookie to a value * with the cookie's domain set to the value returned by <code>getCookieDomain(request)</code> * * @param request * @param response * @param cookie cookie to be replaced. */ @SuppressWarnings("unchecked") protected void replaceCookie(Request request, Response response, Cookie cookie) { //copy the existing session cookie, but use a different domain Cookie newCookie = new Cookie(cookie.getName(), cookie.getValue()); if (cookie.getPath() != null) newCookie.setPath(cookie.getPath()); newCookie.setDomain(getCookieDomain(request)); newCookie.setMaxAge(cookie.getMaxAge()); newCookie.setVersion(cookie.getVersion()); if (cookie.getComment() != null) newCookie.setComment(cookie.getComment()); newCookie.setSecure(cookie.getSecure()); //if the response has already been committed, our replacement strategy will have no effect if (response.isCommitted()) containerLog.error("CrossSubdomainSessionValve: response was already committed!"); //find the Set-Cookie header for the existing cookie and replace its value with new cookie MimeHeaders headers = response.getCoyoteResponse().getMimeHeaders(); for (int i = 0, size = headers.size(); i < size; i++) { if (headers.getName(i).equals("Set-Cookie")) { MessageBytes value = headers.getValue(i); if (value.indexOf(cookie.getName()) >= 0) { StringBuffer buffer = new StringBuffer(); ServerCookie.appendCookieValue(buffer, newCookie.getVersion(), newCookie .getName(), newCookie.getValue(), newCookie.getPath(), newCookie .getDomain(), newCookie.getComment(), newCookie.getMaxAge(), newCookie .getSecure()); containerLog.debug("CrossSubdomainSessionValve: old Set-Cookie value: " + value.toString()); containerLog.debug("CrossSubdomainSessionValve: new Set-Cookie value: " + buffer); value.setString(buffer.toString()); } } } } /** Returns the last two parts of the specified request's server name preceded by a dot. * Using this as the session cookie's domain allows the session to be shared across subdomains. * Note that this implies the session can only be used with domains consisting of two or * three parts, according to the domain-matching rules specified in RFC 2109 and RFC 2965. * * <p>Examples:</p> * <ul> * <li>foo.com => .foo.com</li> * <li>www.foo.com => .foo.com</li> * <li>bar.foo.com => .foo.com</li> * <li>abc.bar.foo.com => .foo.com - this means cookie won't work on abc.bar.foo.com!</li> * </ul> * * @param request provides the server name used to create cookie domain. * @return the last two parts of the specified request's server name preceded by a dot. */ protected String getCookieDomain(Request request) { String cookieDomain = request.getServerName(); String[] parts = cookieDomain.split("\\."); if (parts.length >= 2) cookieDomain = parts[parts.length - 2] + "." + parts[parts.length - 1]; return "." + cookieDomain; } public String toString() { return ("CrossSubdomainSessionValve[container=" + container.getName() + ']'); } } --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
RE: Share session cookie across subdomainsThat's a good point Matthias - in my case sessions are always created so it's acceptable. Can you think of a good way to only replace the session cookie when it would be naturally created by the app for those cases where always creating it is not acceptable?
Note that this entire issue would be made much more simple if there was an easy way to override the org.apache.catalina.connector.Request.configureSessionCookie method. I have not found an easy way to do that. Thanks, Zach
|
|
|
Re: Share session cookie across subdomains-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1 Zach, Zach Cox wrote: | Note that this entire issue would be made much more simple if there was an | easy way to override the | org.apache.catalina.connector.Request.configureSessionCookie method. I have | not found an easy way to do that. Have your Valve wrap the Request object with your own class that overrides that method. Then just move your existing cookie checking/replacing code into the configureSessionCookie method. - -chris -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkgMmnsACgkQ9CaO5/Lv0PA/WACeK9Rcw1ltSqoVC/pFXUZFtob3 JYUAnRxnQV+FEtkxqruWMfA0U2p/Qg9O =ScpV -----END PGP SIGNATURE----- --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Share session cookie across subdomainsHi Chris - I thought about doing that, but that existing Request object could have state that my newly created Request will not have - Request does not have a copy constructor and does not wrap another Request object. Is it OK to just create a fresh, new, un-initialized Request object & pass it to the next valve in the chain?
Thanks, Zach
|
|
|
Re: Share session cookie across subdomains-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1 Zach, Zach Cox wrote: | Hi Chris - I thought about doing that, but that existing Request | object could have state that my newly created Request will not have - | Request does not have a copy constructor and does not wrap another | Request object. That's why you have to write your own Request class that extends the existing Request class, includes a constructor that takes the "wrapped" Request, and delegates nearly all operations to this wrapped object. | Is it OK to just create a fresh, new, un-initialized Request object & | pass it to the next valve in the chain? No, you have to do what I have described above. - -chris -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkgNCmQACgkQ9CaO5/Lv0PARGACgrCxjxUQfVFqxfjilm/wFeQuk RkIAoJEM7Jp45BpuBTuR1+M/N2x8mHIh =Dork -----END PGP SIGNATURE----- --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Share session cookie across subdomainsThat's what I was afraid of - that Request class is huge (2600+ lines) and has lots of fields (50+) some of which are private. So if I create a Request subclass that accepts another Request in the constructor, there are 2 options:
1) initialize as many of the superclass's fields of the new instance as possible using values from the passed-in Request 2) wrap the passed-in Request & delegate method calls to it (100+ methods) #1 is very error-prone, as many of the set methods in Request do things other than just setting the instance variable to a new value and in a future release when Request inevitably changes it will be broken. #2 is also not a good idea: my new Request subclass is not a true wrapper/adapter since I'm overriding one of the methods to get my desired behavior (configureSessionCookie). That method is not called directly, rather is a protected method called by a public method so I have to pick-and-choose which methods get delegated and which don't, which results in state split across two Request objects which gets very confusing and is also very error-prone. Overall, I'm going to call the Request API unsuitable for extension and in particular, I'm going to say overriding configureCookieSession in a Request subclass is not a viable solution to the cross-subdomain session cookie problem. To make Request suitable for extension I can see 2 possible solutions: 1) Provide a way to specify the fully-qualified name of my Request subclass in server.xml so Tomcat instantiates that instead of org.apache.catalina.connector.Request 2) Provide a copy constructor in org.apache.catalina.connector.Request that initializes its state based on the state of the passed-in Request If I'm missing something, please correct me. Thanks, Zach
|
|
|
Re: Share session cookie across subdomains-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1 Zach, Zach Cox wrote: | That's what I was afraid of - that Request class is huge (2600+ lines) and | has lots of fields (50+) some of which are private. So if I create a | Request subclass that accepts another Request in the constructor, there are | 2 options: | 1) initialize as many of the superclass's fields of the new instance as | possible using values from the passed-in Request | 2) wrap the passed-in Request & delegate method calls to it (100+ methods) #2 is what you want to do. The constructor should look like this: public Request(Request wrapped) { ~ this.wrapped = wrapped; } That's it. Every other method should look like this: public whatever doWhatever(args) { ~ super.doWhatever(args); } | #2 is also not a good idea: my new Request subclass is not a true | wrapper/adapter since I'm overriding one of the methods to get my desired | behavior (configureSessionCookie). That method is not called directly, | rather is a protected method called by a public method so I have to | pick-and-choose which methods get delegated and which don't, which results | in state split across two Request objects which gets very confusing and is | also very error-prone. Just override the protected method. Protected methods were made to be overridden. You are doing the exact same thing that is encouraged by the Servlet API itself (see javax.servlet.http.HttpServletRequestWrapper). | Overall, I'm going to call the Request API unsuitable for extension and in | particular, I'm going to say overriding configureCookieSession in a Request | subclass is not a viable solution to the cross-subdomain session cookie | problem. Okay, happy coding. | To make Request suitable for extension I can see 2 possible solutions: | 1) Provide a way to specify the fully-qualified name of my Request subclass | in server.xml so Tomcat instantiates that instead of | org.apache.catalina.connector.Request You won't have to do this if you modify Request.java directly, which is what you'll have to do in order to... | 2) Provide a copy constructor in org.apache.catalina.connector.Request that | initializes its state based on the state of the passed-in Request I'd be careful with this. You might not be able to get some of the internal state this way. If I were you, I'd start by submitting a bugzilla enhancement and patch to achieve #1 above (a way to specify the class name for the request class). Right now, each connector has "new Request()" hard-coded into its constructor. This won't be an easy task, as you will have to either modify the arguments to the connector's constructor (yuck), add a static class field to specify the Request class to use (and break convention within the Tomcat code), and in either case you'll have to modify every connector implementation (or, at least the ones you are currently using) /and/ any code that interacts with the connectors (because of the new constructor args, new static field, whatever). Trust me. Use a Valve even if you don't want to use a wrapper as I suggest. Otherwise, you have to modify Tomcat code for each release, which is horribly unmaintainable. - -chris -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.9 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkgN6rkACgkQ9CaO5/Lv0PCV6wCfV9Yh/wcd9aksuk1KXEUN1G9z O2AAnj6c8dkK1x/APNSyCrmLYcPoe1Ef =Px/z -----END PGP SIGNATURE----- --------------------------------------------------------------------- To start a new topic, e-mail: users@... To unsubscribe, e-mail: users-unsubscribe@... For additional commands, e-mail: users-help@... |
|
|
Re: Share session cookie across subdomains |