From: Christoph Z. <ci...@on...> - 2007-03-24 19:15:07
|
One thing I always disliked about Webware is the static 404 error page. First, the name '404Text.txt' is hard coded and misleading because it is a complete HTML page (maybe it has only been the body part in older versions, as it is still wrongly documented), so it should better be called something like '404page.html'. Second, you usually define a custom layout and CSS in your base servlet class. If you don't want your 404 page to look completely different, you are forced to insert (duplicate) the layout manually in the 404Text.txt file. Therefore I'd like to be able to forward to an arbitrary servlet in case of a 404 error, or generally, any http error. This servlet could then simply use the same base class as the other servlets, and everything will look neatly. While you can install a customized error handler for exceptions that occurred in the servlets using the Application._exceptionHandlerClass, it does not seem to be possible to invoke a custom servlet on an HTTPException. (Or am I overlooking something obvious?) So I have just implemented such a feature, considering that I really would like to have that before Webware 1.0. I introduced a new Application.config setting "HTTPErrorPage". (If you have a better name, let me know. I do not want to call it "ErrorPage" because there are already many "Error" settings which all refer to servlet exceptions, not HTTPExceptions.) For example: HTTPErrorPage = { 'NotFound': '/Error404' 'SessionExpired': '/Expired', 'default': '/Error' } Webware will then forward to the URL '/Error404' if an HTTPNotFound exception is raised. Integer error codes are also allowed as keys (e.g. 401: '/Expired'), but the names of the exceptions are more readable and allow for finer granularity. E.g. 401 is also used for a more general "authentication required" error. In the case that you only have one page to be used as the default, I will allow the shorter notation: HTTPErrorPage = '/Error' If HTTPErrorPage is set to None, or you hit an HTTPException that is not in HTTPErrorPage and there is no default key, then Webware will behave exactly as before. The error servlet could look like that: ------------- Error404.py ---------------- from MyPage import MyPage class Error404(MyPage ): def title(self): return "This page does not exist!" def writeContent(self): self.write(""" <h4>You were not here:</h4> <h3>%s</h3> <h5>Let's never mention it again.</h5> """ % self.htmlEncode(self.request().uri())) -------------------------------------------- I have this already working. The error page will of course come with its associated status code in the http header, automatically. Let me know whether you think this all makes sense before I will check it in ;-) -- Chris |
From: Chuck E. <chu...@gm...> - 2007-03-25 07:43:26
|
On 3/24/07, Christoph Zwerschke <ci...@on...> wrote: > One thing I always disliked about Webware is the static 404 error page. ... Your proposal sounds good to me. I just hope Webware is uber stable when we call it 1.0. G'night, -Chuck |
From: Christoph Z. <ci...@on...> - 2007-03-25 11:54:14
|
Chuck Esterbrook wrote: > I just hope Webware is uber stable when we call it 1.0. Right, actually I did not want to make larger changes before 1.0. But in this case, I had to make bigger changes in the mechanisms for forwarding and catching errors anyway, in order to fix the problems reported by Andrew Butash last month. I think I understand the details now very clearly and implemented it in a much cleaner way that does not leave any servlet in limbo state, so it should have be more stable already. Of course we still need to test 0.9.3 very thoroughly and fix any remaining or new bugs before 1.0. -- Chris |
From:
<jf....@la...> - 2007-03-25 08:21:51
|
Christoph Zwerschke wrote: [snip] > > Let me know whether you think this all makes sense before I will check > it in ;-) > Very good idea, allowing declaration of a default error page will be very useful. May be it would be also interesting to allow the declaration of HPPTErrorPage for application raised exceptions. For example: HTTPErrorPage = { 'NotFound': '/Error404' 'SessionExpired': '/Expired', 'OneAppException': '/OneAppError', 'OnotherAppException': '/AnotherAppError', 'default': '/Error' } Cheers, JF |
From: Christoph Z. <ci...@on...> - 2007-03-25 11:37:45
|
Jean-François Piéronne wrote: > Very good idea, allowing declaration of a default error page will be > very useful. > May be it would be also interesting to allow the declaration of > HPPTErrorPage for application raised exceptions. For example: > > HTTPErrorPage = { > 'NotFound': '/Error404' > 'SessionExpired': '/Expired', > 'OneAppException': '/OneAppError', > 'OnotherAppException': '/AnotherAppError', > 'default': '/Error' > } Makes sense to me. But in this case, we sould use another notation: ErrorPage = { 'HTTPNotFound': '/Error404' 'HTTPSessionExpired': '/Expired', 'OneAppException': '/OneAppError', 'OnotherAppException': '/AnotherAppError', 'HTTPException': '/HttpError', 'Exception': '/Error' } 'HTTPException' would be a catch-all for HTTP errors, 'Exception' for all other exceptions. The exception instance is stored in an "_error" attribute of the transaction so the servlet can examine it. There is already a Boolean attribute "_errorOccurred" which is actually only used for the activity log. We could replace that by def errorOccured(self): self._error is not None. One question is whether we want to set errorOccurred also for HTTP exceptions. So far it is only set for other exceptions. Should we change that? If not, we need to def errorOccured(self): self._error is not None and not self._error.isinstance(HTTPException). -- Chris |
From: Christoph Z. <ci...@on...> - 2007-03-25 17:36:45
|
I have now implemented and documented it that way in the trunk. If ErrorPage is set to None or does not contain the raised exception, or if the response has already been commited, then it behaves as before. -- Chris |
From: Ben P. <be...@pa...> - 2007-03-25 19:54:49
|
Hi - It would be really nice to have the session store class and session classes fully configurable from the Application.config file. Currently Webware is limited to the included Memory/File/Dynamic setting which is translated into ("Session%sStore" % setting) and used to import the store. Then the session class is hard-coded as Session in the Application. What do you think of having config settings for importing custom session stores and session classes for use by the app? I built a custom store for one application that happens to use MySQL as the back-end, coupled with a custom Session object, and I have to jump through some hoops to get the app to use them. It could be as simple as four new config settings: SessionStoreModule SessionStoreClass SessionModule SessionClass The Application object could do the same process it does now to import SessionXxxStore. Something like this (rough, untested): CURRENT: # For session store: sessionStore = 'Session%sStore' % self.setting('SessionStore') exec 'from %s import %s' % (sessionStore, sessionStore) klass = locals()[sessionStore] assert isinstance(klass, ClassType) or issubclass(klass, Object) self._sessions = klass(self) NEW: # For session store: exec 'from %s import %s' % (self.setting('SessionStoreModule'), self.setting('SessionStoreClass')) klass = locals()[self.setting('SessionStoreClass')] assert isinstance(klass, ClassType) or issubclass(klass, Object) self._sessions = klass(self) # For session class: exec 'from %s import %s' % (self.setting('SessionModule'), self.setting('SessionClass')) klass = locals()[self.setting('SessionClass')] self._session = klass If there is interest in this, I can whip up a patch. I can include support for the current "SessionStore" param as well, rather than force a change to config files. Thanks - Ben |
From: Christoph Z. <ci...@on...> - 2007-04-05 15:50:55
|
Hi Ben, I'm going to implement your patch, but I'd like to cut down the number of additional config settings. The number of parameters is already scaring enough ;-) What do you think about: 1) Assuming that the class name is always the same as the module name (this is also backward compatible and reduces confusion). 2) If the setting contains no dot, then try "Session%sStore" % setting, if this fails or the name contains a dot, then use the name as is. This way we can get on only with the old 'SessionStore' setting in a backward compatible way, plus one additional setting for the session module (and class). Would this be ok for you? -- Chris Ben Parker wrote: > Hi - It would be really nice to have the session store class and session > classes fully configurable from the Application.config file. Currently > Webware is limited to the included Memory/File/Dynamic setting which is > translated into ("Session%sStore" % setting) and used to import the > store. Then the session class is hard-coded as Session in the Application. > > What do you think of having config settings for importing custom session > stores and session classes for use by the app? I built a custom store > for one application that happens to use MySQL as the back-end, coupled > with a custom Session object, and I have to jump through some hoops to > get the app to use them. > > It could be as simple as four new config settings: > > SessionStoreModule > SessionStoreClass > SessionModule > SessionClass > > The Application object could do the same process it does now to import > SessionXxxStore. Something like this (rough, untested): > > CURRENT: > # For session store: > sessionStore = 'Session%sStore' % self.setting('SessionStore') > exec 'from %s import %s' % (sessionStore, sessionStore) > klass = locals()[sessionStore] > assert isinstance(klass, ClassType) or issubclass(klass, Object) > self._sessions = klass(self) > > NEW: > # For session store: > exec 'from %s import %s' % (self.setting('SessionStoreModule'), > self.setting('SessionStoreClass')) > klass = locals()[self.setting('SessionStoreClass')] > assert isinstance(klass, ClassType) or issubclass(klass, Object) > self._sessions = klass(self) > # For session class: > exec 'from %s import %s' % (self.setting('SessionModule'), > self.setting('SessionClass')) > klass = locals()[self.setting('SessionClass')] > self._session = klass > > If there is interest in this, I can whip up a patch. I can include > support for the current "SessionStore" param as well, rather than force > a change to config files. > > Thanks - Ben |
From: Ben P. <be...@pa...> - 2007-04-05 16:12:17
|
Yes that would work fine for our app. Agreed about too many config settings - I thought about having the Session / SessionStore set through some kind of runtime configuration. Allow each context to set its own session/store combo perhaps? but that is a larger effort, and I didn't need that full solution. :) Thanks for considering the patch, and thank you very much for your work on the Webware releases! Regards - Ben Christoph Zwerschke wrote on 4/5/07 8:50 AM: > Hi Ben, > > I'm going to implement your patch, but I'd like to cut down the number > of additional config settings. The number of parameters is already > scaring enough ;-) What do you think about: > > 1) Assuming that the class name is always the same as the module name > (this is also backward compatible and reduces confusion). > > 2) If the setting contains no dot, then try "Session%sStore" % setting, > if this fails or the name contains a dot, then use the name as is. > > This way we can get on only with the old 'SessionStore' setting in a > backward compatible way, plus one additional setting for the session > module (and class). > > Would this be ok for you? > > -- Chris > > Ben Parker wrote: > >> Hi - It would be really nice to have the session store class and session >> classes fully configurable from the Application.config file. Currently >> Webware is limited to the included Memory/File/Dynamic setting which is >> translated into ("Session%sStore" % setting) and used to import the >> store. Then the session class is hard-coded as Session in the Application. >> >> What do you think of having config settings for importing custom session >> stores and session classes for use by the app? I built a custom store >> for one application that happens to use MySQL as the back-end, coupled >> with a custom Session object, and I have to jump through some hoops to >> get the app to use them. >> >> It could be as simple as four new config settings: >> >> SessionStoreModule >> SessionStoreClass >> SessionModule >> SessionClass >> >> The Application object could do the same process it does now to import >> SessionXxxStore. Something like this (rough, untested): >> >> CURRENT: >> # For session store: >> sessionStore = 'Session%sStore' % self.setting('SessionStore') >> exec 'from %s import %s' % (sessionStore, sessionStore) >> klass = locals()[sessionStore] >> assert isinstance(klass, ClassType) or issubclass(klass, Object) >> self._sessions = klass(self) >> >> NEW: >> # For session store: >> exec 'from %s import %s' % (self.setting('SessionStoreModule'), >> self.setting('SessionStoreClass')) >> klass = locals()[self.setting('SessionStoreClass')] >> assert isinstance(klass, ClassType) or issubclass(klass, Object) >> self._sessions = klass(self) >> # For session class: >> exec 'from %s import %s' % (self.setting('SessionModule'), >> self.setting('SessionClass')) >> klass = locals()[self.setting('SessionClass')] >> self._session = klass >> >> If there is interest in this, I can whip up a patch. I can include >> support for the current "SessionStore" param as well, rather than force >> a change to config files. >> >> Thanks - Ben >> > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys-and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Webware-devel mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webware-devel > > > |
From: Christoph Z. <ci...@on...> - 2007-04-05 22:41:17
|
Ok, this is now in the trunk if you want to check it out. Ben Parker wrote: > Agreed about too many config settings - I thought about having the > Session / SessionStore set through some kind of runtime configuration. > Allow each context to set its own session/store combo perhaps? but that > is a larger effort, and I didn't need that full solution. :) |
From: Ben P. <be...@pa...> - 2007-04-06 01:29:53
|
Thanks, Chris. For purposes of these comments, I'm browsing svn rev 6414. http://svn.w4py.org/Webware/trunk/WebKit/Application.py The SessionStore initialization seems a bit more complicated than it needs to be. Rather than the for loop, and the prefix/suffix check, you can check if the setting is 'Memory', 'File', or 'Dynamic'. Otherwise everyone with a custom SessionStore needs to follow the SessionXxxxStore naming convention needlessly. Here's the snippet from rev 6414 Application.py's initSessions(), updated to remove the for loop: sessionStore = self.setting('SessionStore') if sessionStore in ('Memory', 'File', 'Dynamic'): moduleName = className = 'Session' + sessionStore + 'Store' else: moduleName = sessionStore className = sessionStore.split('.')[-1] try: exec 'from %s%s import %s' % (moduleName, className) except ImportError: self._sessions = None else: try: klass = locals()[className] if not isinstance(klass, ClassType) \ and not issubclass(klass, Object): raise KeyError self._sessions = klass(self) except KeyError: print "ERROR: ", moduleName, " module" \ " does not contain class", className self._sessions = None if self._sessions is None: print "ERROR: Session store not found!" Regards - Ben Christoph Zwerschke wrote on 4/5/07 3:41 PM: > Ok, this is now in the trunk if you want to check it out. > > Ben Parker wrote: > >> Agreed about too many config settings - I thought about having the >> Session / SessionStore set through some kind of runtime configuration. >> Allow each context to set its own session/store combo perhaps? but that >> is a larger effort, and I didn't need that full solution. :) >> > > ------------------------------------------------------------------------- > Take Surveys. Earn Cash. Influence the Future of IT > Join SourceForge.net's Techsay panel and you'll get the chance to share your > opinions on IT & business topics through brief surveys-and earn cash > http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV > _______________________________________________ > Webware-devel mailing list > Web...@li... > https://lists.sourceforge.net/lists/listinfo/webware-devel > > > |
From: Christoph Z. <ci...@on...> - 2007-04-06 09:11:53
|
Ben Parker wrote: > The SessionStore initialization seems a bit more complicated than it > needs to be. Rather than the for loop, and the prefix/suffix check, you > can check if the setting is 'Memory', 'File', or 'Dynamic'. Otherwise > everyone with a custom SessionStore needs to follow the SessionXxxxStore > naming convention needlessly. That's why I had the loop, it checked first for SessionNameStore and then for Name only, so you could either follow the convention or use your own name. But you're right - I have reimplemented it as suggested for better compliance with the KISS principle. Looks much better now. -- Chris |