diff --git a/product/CMFActivity/ActivityTool.py b/product/CMFActivity/ActivityTool.py
index d005395e5f68594c63f023a3f07f4a464fbea241..7cd0a3648e00eb813612d8dba976afa4aa18c3fc 100644
--- a/product/CMFActivity/ActivityTool.py
+++ b/product/CMFActivity/ActivityTool.py
@@ -134,7 +134,13 @@ class Message:
     self.traceback = None
     self.processing = None
     self.user_name = str(_getAuthenticatedUser(self))
-    # Store REQUEST Info ?
+    # Store REQUEST Info
+    request = getattr(obj, 'REQUEST', None)
+    if request is not None:
+      self.request_info = dict(
+        SERVER_URL=request.other['SERVER_URL'],
+        VirtualRootPhysicalPath=request.other.get('VirtualRootPhysicalPath'),
+        _script=list(request._script))
 
   def getObject(self, activity_tool):
     """return the object referenced in this message."""
@@ -805,7 +811,18 @@ class ActivityTool (Folder, UniqueObject):
         if parents is None:
           warn('CMFActivity.ActivityTool.invoke: PARENTS is not defined in REQUEST. It should only happen in unit tests.')
           request['PARENTS'] = self.aq_chain[:]
-        new_request_container = request_container.__class__(REQUEST=request.clone())
+        
+        # restore request information
+        new_request = request.clone()
+        request_info = getattr(message, 'request_info', None)
+        if request_info is not None:
+          new_request.other['SERVER_URL'] = request_info['SERVER_URL']
+          virtual_root_path = request_info.get('VirtualRootPhysicalPath')
+          if virtual_root_path:
+            new_request.other['VirtualRootPhysicalPath'] = virtual_root_path
+          new_request._script = request_info['_script']
+
+        new_request_container = request_container.__class__(REQUEST=new_request)
         # Recreate acquisition chain.
         my_self = new_request_container
         base_chain.reverse()
diff --git a/product/CMFActivity/tests/testCMFActivity.py b/product/CMFActivity/tests/testCMFActivity.py
index 150a5be08733a534844adfdccb484c06749c39a2..d0b9bd10613b378ae88c68c6c8a0bbc104a2aacd 100644
--- a/product/CMFActivity/tests/testCMFActivity.py
+++ b/product/CMFActivity/tests/testCMFActivity.py
@@ -2798,6 +2798,45 @@ class TestCMFActivity(ERP5TypeTestCase):
       LOG('Testing... ',0,message)
     self.CheckSerializationTag('SQLQueue')
 
+  def test_108_testAbsoluteUrl(self):
+    # Tests that absolute_url works in activities. The URL generation is based
+    # on REQUEST information when the method was activated.
+    request = self.portal.REQUEST
+
+    request.setServerURL('http', 'test.erp5.org', '9080')
+    request.other['PARENTS'] = [self.portal.organisation_module]
+    request.setVirtualRoot('virtual_root')
+
+    calls = []
+    def checkAbsoluteUrl(self):
+      calls.append(self.absolute_url())
+    Organisation.checkAbsoluteUrl = checkAbsoluteUrl
+
+    try:
+      o = self.portal.organisation_module.newContent(
+                    portal_type='Organisation', id='test_obj')
+      self.assertEquals(o.absolute_url(),
+          'http://test.erp5.org:9080/virtual_root/test_obj')
+      o.activate().checkAbsoluteUrl()
+      
+      # Reset server URL and virtual root before executing messages.
+      # This simulates the case of activities beeing executed with different
+      # REQUEST, such as TimerServer.
+      request.setServerURL('https', 'anotherhost.erp5.org', '443')
+      request.other['PARENTS'] = [self.app]
+      request.setVirtualRoot('')
+      # obviously, the object url is different
+      self.assertEquals(o.absolute_url(),
+          'https://anotherhost.erp5.org/%s/organisation_module/test_obj'
+           % self.portal.getId())
+
+      # but activities are executed using the previous request information
+      self.flushAllActivities(loop_size=1000)
+      self.assertEquals(calls, ['http://test.erp5.org:9080/virtual_root/test_obj'])
+    finally:
+      delattr(Organisation, 'checkAbsoluteUrl')
+
+
 def test_suite():
   suite = unittest.TestSuite()
   suite.addTest(unittest.makeSuite(TestCMFActivity))