Skip to content
This repository has been archived by the owner on Feb 11, 2019. It is now read-only.

Commit

Permalink
Merge 747b067 into fd9deca
Browse files Browse the repository at this point in the history
  • Loading branch information
hedleyroos committed Feb 9, 2014
2 parents fd9deca + 747b067 commit 87ffe5a
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 14 deletions.
13 changes: 11 additions & 2 deletions devproxy/handlers/wurfl_handler/base.py
Expand Up @@ -24,6 +24,7 @@ def validate_config(self, config):
self.cache_prefix_delimiter = config.get('cache_prefix_delimiter', '#')
self.cache_lifetime = int(config.get('cache_lifetime', 0))
self.memcached_config = config.get('memcached', {})
self.default_ua_map = config.get('default_ua_map', 'web')

@inlineCallbacks
def setup_handler(self):
Expand Down Expand Up @@ -90,8 +91,10 @@ def get_cookies(self, request):

@inlineCallbacks
def handle_request_and_cache(self, cache_key, user_agent, request):
device = self.devices.select_ua(user_agent, search=self.algorithm)
headers = self.handle_device(request, device)
headers = self.handle_user_agent(user_agent)
if headers is None:
device = self.devices.select_ua(user_agent, search=self.algorithm)
headers = self.handle_device(request, device)
yield self.memcached.set(cache_key, json.dumps(headers),
expireTime=self.cache_lifetime)
returnValue(headers)
Expand All @@ -111,5 +114,11 @@ def get_debug_info(self, request):
device = self.devices.select_ua(user_agent, search=self.algorithm)
return flattenString(None, debug.DebugElement(device))

def handle_user_agent(self, user_agent):
"""User agents unknown to Wurfl may require special handling. Override
this method to provide it. Return None to indicate no special
handling."""
return None

def handle_device(self, request, device):
raise NotImplementedError("Subclasses should implement this")
25 changes: 20 additions & 5 deletions devproxy/handlers/wurfl_handler/scientia_mobile_cloud.py
Expand Up @@ -7,6 +7,10 @@
from twisted.web.client import getPage


class ScientiaMobileCloudHandlerConnectError(Exception):
pass


class ScientiaMobileCloudHandler(WurflHandler):

SMCLOUD_CONFIG = {
Expand Down Expand Up @@ -34,10 +38,18 @@ def setup_handler(self):

@inlineCallbacks
def handle_request_and_cache(self, cache_key, user_agent, request):
device = yield self.get_device_from_smcloud(user_agent)
headers = self.handle_device(request, device)
expireTime = self.cache_lifetime
headers = self.handle_user_agent(user_agent)
if headers is None:
try:
device = yield self.get_device_from_smcloud(user_agent)
except ScientiaMobileCloudHandlerConnectError:
# Set a short expiry time in case of network error
device = {}
expireTime = 60
headers = self.handle_device(request, device)
yield self.memcached.set(cache_key, json.dumps(headers),
expireTime=self.cache_lifetime)
expireTime=expireTime)
returnValue(headers)

@inlineCallbacks
Expand All @@ -52,8 +64,11 @@ def get_device_from_smcloud(self, user_agent):
'X-Cloud-Client': self.SMCLOUD_CONFIG['client_version'],
'Authorization': 'Basic %s' % b64
}
page = yield getPage(self.SMCLOUD_CONFIG['url'], headers=headers,
agent=user_agent)
try:
page = yield getPage(self.SMCLOUD_CONFIG['url'], headers=headers,
agent=user_agent, timeout=5)
except ConnectError, exc:
raise ScientiaMobileCloudHandlerConnectError(exc)
device = json.loads(page)
returnValue(device)

Expand Down
Expand Up @@ -3,9 +3,48 @@


class ScientiaMobileCloudResolutionHandler(ScientiaMobileCloudHandler):
"""The initial implementation. This remains as legacy. Use of
ScientiaMobileCloudResolutionTouchHandler is recommended."""

def handle_device(self, request, device):
if device['capabilities']['resolution_width'] > 240:
return [{self.header_name: 'high'}]
else:
return [{self.header_name: 'medium'}]


class ScientiaMobileCloudResolutionTestHandler(ScientiaMobileCloudResolutionHandler):
"""Handler used in tests. Do not use in production."""

def handle_user_agent(self, user_agent):
if user_agent == 'Some special bot':
return [{self.header_name: 'bot'}]
return None


class ScientiaMobileCloudResolutionTouchHandler(ScientiaMobileCloudHandler):

def handle_device(self, request, device):
result = {self.header_name: self.default_ua_map}

is_web_browser = False
is_smart_browser = False
is_basic_browser = False
try:
is_web_browser = device['capabilities']['ux_full_desktop'] \
or device['capabilities']['is_tablet']
is_smart_browser = \
(device['capabilities']['resolution_width'] >= 320) \
and (device['capabilities']['pointing_method'] == 'touchscreen')
is_basic_browser = not (is_web_browser or is_smart_browser)
except KeyError:
pass

if is_web_browser:
result[self.header_name] = 'web'
elif is_smart_browser:
result[self.header_name] = 'smart'
elif is_basic_browser:
result[self.header_name] = 'basic'

return [result]
9 changes: 9 additions & 0 deletions devproxy/handlers/wurfl_handler/simple.py
Expand Up @@ -8,3 +8,12 @@ def handle_device(self, request, device):
return [{self.header_name: 'medium'}]
else:
return [{self.header_name: 'high'}]


class SimpleWurflTestHandler(SimpleWurflHandler):
"""Handler used in tests. Do not use in production."""

def handle_user_agent(self, user_agent):
if user_agent == 'Some special bot':
return [{self.header_name: 'bot'}]
return None
17 changes: 14 additions & 3 deletions devproxy/tests/test_wurfl_handler.py
Expand Up @@ -2,7 +2,7 @@

from twisted.internet.defer import inlineCallbacks

from devproxy.handlers.wurfl_handler.simple import SimpleWurflHandler
from devproxy.handlers.wurfl_handler.simple import SimpleWurflTestHandler
from devproxy.utils import http
from devproxy.tests.utils import FakeMemcached, ProxyTestCase

Expand All @@ -13,10 +13,10 @@ class WurlfHandlerTestCase(ProxyTestCase):
def setUp(self):
yield super(WurlfHandlerTestCase, self).setUp()
self.fake_memcached = FakeMemcached()
self.patch(SimpleWurflHandler, 'connect_to_memcached',
self.patch(SimpleWurflTestHandler, 'connect_to_memcached',
self.patch_memcached)

self.wurfl_handlers = yield self.start_handlers([SimpleWurflHandler({
self.wurfl_handlers = yield self.start_handlers([SimpleWurflTestHandler({
'header_name': 'X-UA-header',
'cache_prefix': 'prefix',
'cache_prefix_delimiter': '_',
Expand Down Expand Up @@ -115,3 +115,14 @@ def test_debug_path(self):
'User-Agent': self.iphone_ua,
}, method='GET')
self.assertEqual(response.code, 200)

@inlineCallbacks
def test_handle_user_agent(self):
proxy, url = self.start_proxy(self.wurfl_handlers)
response = yield http.request(url, headers={
'User-Agent': 'Some special bot',
})
self.assertEqual(response.delivered_body, 'foo')
req = yield self.mocked_backend.queue.get()
self.assertEqual(req.requestHeaders.getRawHeaders('x-ua-header'),
['bot'])
19 changes: 15 additions & 4 deletions devproxy/tests/test_wurfl_scientia_mobile_cloud.py
Expand Up @@ -3,7 +3,7 @@
from twisted.internet.defer import inlineCallbacks, succeed

from devproxy.handlers.wurfl_handler.scientia_mobile_cloud_resolution \
import ScientiaMobileCloudResolutionHandler
import ScientiaMobileCloudResolutionTestHandler
from devproxy.utils import http
from devproxy.tests.utils import FakeMemcached, ProxyTestCase

Expand All @@ -15,14 +15,14 @@ def setUp(self):
yield super(WurlfHandlerTestCase, self).setUp()
self.fake_memcached = FakeMemcached()
self._mocked_devices = {}
self.patch(ScientiaMobileCloudResolutionHandler,
self.patch(ScientiaMobileCloudResolutionTestHandler,
'get_device_from_smcloud',
self.patch_get_device_from_smcloud)
self.patch(ScientiaMobileCloudResolutionHandler,
self.patch(ScientiaMobileCloudResolutionTestHandler,
'connect_to_memcached',
self.patch_memcached)
self.wurfl_handlers = yield self.start_handlers([
ScientiaMobileCloudResolutionHandler({
ScientiaMobileCloudResolutionTestHandler({
'header_name': 'X-UA-header',
'cache_prefix': 'prefix',
'cache_prefix_delimiter': '_',
Expand Down Expand Up @@ -132,3 +132,14 @@ def test_cache_lifetime(self):
self.assertEqual(response.delivered_body, 'foo')
cache_key = handler.get_cache_key(self.iphone_ua)
self.assertEqual(self.fake_memcached.key_lifetime(cache_key), 100)

@inlineCallbacks
def test_handle_user_agent(self):
proxy, url = self.start_proxy(self.wurfl_handlers)
response = yield http.request(url, headers={
'User-Agent': 'Some special bot',
})
self.assertEqual(response.delivered_body, 'foo')
req = yield self.mocked_backend.queue.get()
self.assertEqual(req.requestHeaders.getRawHeaders('x-ua-header'),
['bot'])

0 comments on commit 87ffe5a

Please sign in to comment.