wurfl_cloud_client_light 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/FOSS_THIRD_PARTY_LICENSES.txt +23 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +40 -0
- data/LICENSE.txt +75 -0
- data/Rakefile +14 -0
- data/lib/wurfl_cloud/cache/cookie.rb +36 -0
- data/lib/wurfl_cloud/cache/local_memory.rb +36 -0
- data/lib/wurfl_cloud/cache/null.rb +34 -0
- data/lib/wurfl_cloud/client.rb +98 -0
- data/lib/wurfl_cloud/configuration.rb +81 -0
- data/lib/wurfl_cloud/device_capabilities.rb +71 -0
- data/lib/wurfl_cloud/environment.rb +41 -0
- data/lib/wurfl_cloud/errors.rb +16 -0
- data/lib/wurfl_cloud/helper.rb +14 -0
- data/lib/wurfl_cloud/rack/cache_manager.rb +47 -0
- data/lib/wurfl_cloud/rails.rb +27 -0
- data/lib/wurfl_cloud/version.rb +7 -0
- data/lib/wurfl_cloud.rb +42 -0
- data/spec/files/generic.json +1 -0
- data/spec/files/generic_filtered.json +1 -0
- data/spec/files/lumia.json +1 -0
- data/spec/files/lumia_filtered.json +1 -0
- data/spec/files/strange_values.json +1 -0
- data/spec/spec_helper.rb +20 -0
- data/spec/support/rack_helpers.rb +79 -0
- data/spec/support/string_extensions.rb +26 -0
- data/spec/wurfl_cloud/client_spec.rb +200 -0
- data/spec/wurfl_cloud/configuration_spec.rb +111 -0
- data/spec/wurfl_cloud/cookie_cache_spec.rb +44 -0
- data/spec/wurfl_cloud/device_capabilities_spec.rb +136 -0
- data/spec/wurfl_cloud/environment_spec.rb +86 -0
- data/spec/wurfl_cloud/helper_spec.rb +28 -0
- data/spec/wurfl_cloud/null_cache_spec.rb +30 -0
- data/spec/wurfl_cloud/rack_cache_manager_spec.rb +69 -0
- data/spec/wurfl_cloud/server_request_spec.rb +38 -0
- data/wurfl_cloud_client_light.gemspec +31 -0
- metadata +161 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
require 'wurfl_cloud/errors'
|
|
6
|
+
require 'json'
|
|
7
|
+
|
|
8
|
+
module WurflCloud
|
|
9
|
+
class DeviceCapabilities
|
|
10
|
+
attr_accessor :mtime, :id, :user_agent
|
|
11
|
+
|
|
12
|
+
def initialize(ua = nil)
|
|
13
|
+
@capabilities = {}
|
|
14
|
+
@mtime = Time.at(0)
|
|
15
|
+
@id = nil
|
|
16
|
+
@user_agent = ua
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def [](key)
|
|
20
|
+
@capabilities[key]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def []=(key, value)
|
|
24
|
+
@capabilities[key] = value
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def merge(newvalues)
|
|
28
|
+
@capabilities.merge!(newvalues)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def empty?
|
|
32
|
+
@capabilities.empty?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def has_key?(key)
|
|
36
|
+
@capabilities.has_key?(key)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_hash
|
|
40
|
+
@capabilities.clone
|
|
41
|
+
end
|
|
42
|
+
class << self
|
|
43
|
+
def parse(json)
|
|
44
|
+
object = JSON.parse(json)
|
|
45
|
+
new.tap do |device_capabilities|
|
|
46
|
+
object["capabilities"].each do |key,value|
|
|
47
|
+
device_capabilities[key] = cast_value(value)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
device_capabilities.id = object["id"]
|
|
51
|
+
device_capabilities["id"] = object["id"]
|
|
52
|
+
device_capabilities.mtime = Time.at(object["mtime"].to_i)
|
|
53
|
+
end
|
|
54
|
+
rescue
|
|
55
|
+
raise WurflCloud::Errors::MalformedResponseError.new
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
private
|
|
59
|
+
|
|
60
|
+
def cast_value(value)
|
|
61
|
+
case value.to_s
|
|
62
|
+
when "true" then true ;
|
|
63
|
+
when "false" then false ;
|
|
64
|
+
when /^[1-9][0-9]*$/ then value.to_s.to_i ;
|
|
65
|
+
when /^[1-9][0-9]*\.[0-9]+$/ then value.to_s.to_f ;
|
|
66
|
+
else value
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
require 'wurfl_cloud/errors'
|
|
6
|
+
|
|
7
|
+
module WurflCloud
|
|
8
|
+
class Environment
|
|
9
|
+
|
|
10
|
+
USER_AGENT_FIELDS = [
|
|
11
|
+
'HTTP_X_DEVICE_USER_AGENT',
|
|
12
|
+
'HTTP_X_ORIGINAL_USER_AGENT',
|
|
13
|
+
'HTTP_X_OPERAMINI_PHONE_UA',
|
|
14
|
+
'HTTP_X_SKYFIRE_PHONE',
|
|
15
|
+
'HTTP_X_BOLT_PHONE_UA',
|
|
16
|
+
'HTTP_USER_AGENT'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
attr_reader :user_agent, :x_forwarded_for, :x_accept, :x_wap_profile
|
|
20
|
+
|
|
21
|
+
# Extracts the http headers that are relevant
|
|
22
|
+
# to the library. They are used by the client
|
|
23
|
+
# when communicating with the API server.
|
|
24
|
+
def initialize(http_env={})
|
|
25
|
+
USER_AGENT_FIELDS.each do |ua_field|
|
|
26
|
+
@user_agent ||= http_env[ua_field]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
@x_accept = http_env["HTTP_ACCEPT"]
|
|
30
|
+
|
|
31
|
+
if !(@x_wap_profile = http_env["HTTP_X_WAP_PROFILE"])
|
|
32
|
+
@x_wap_profile = http_env["HTTP_PROFILE"]
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if http_env["REMOTE_ADDR"]
|
|
36
|
+
@x_forwarded_for = http_env["REMOTE_ADDR"]
|
|
37
|
+
@x_forwarded_for = "#{x_forwarded_for}, #{http_env["HTTP_X_FORWARDED_FOR"]}" if http_env["HTTP_X_FORWARDED_FOR"]
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
module WurflCloud
|
|
6
|
+
module Errors
|
|
7
|
+
class GenericError < StandardError
|
|
8
|
+
end
|
|
9
|
+
class MalformedResponseError < GenericError
|
|
10
|
+
end
|
|
11
|
+
class ConfigurationError < GenericError
|
|
12
|
+
end
|
|
13
|
+
class ConnectionError < GenericError
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
module WurflCloud
|
|
6
|
+
module Helper
|
|
7
|
+
|
|
8
|
+
def wurfl_detect_device(env)
|
|
9
|
+
wurfl_env = WurflCloud::Environment.new(env)
|
|
10
|
+
wurfl_cache = WurflCloud.configuration.cache(env)
|
|
11
|
+
@device ||= WurflCloud::Client.detect_device(wurfl_env, wurfl_cache)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
module WurflCloud::Rack
|
|
6
|
+
class CacheManager
|
|
7
|
+
# to be refactored: make configurable
|
|
8
|
+
COOKIE_NAME = 'WurflCloud_Client'
|
|
9
|
+
EXPIRY = 86400
|
|
10
|
+
|
|
11
|
+
def initialize(app, options={})
|
|
12
|
+
@app = app
|
|
13
|
+
end
|
|
14
|
+
def call(env)
|
|
15
|
+
# extract cookie
|
|
16
|
+
request = Rack::Request.new(env)
|
|
17
|
+
env['wurfl.cookie.device_cache'] = extract_wurfl_cookie(request.cookies)
|
|
18
|
+
|
|
19
|
+
# execute upstream request
|
|
20
|
+
status, headers, body = @app.call(env)
|
|
21
|
+
|
|
22
|
+
# store cookie
|
|
23
|
+
response = Rack::Response.new body, status, headers
|
|
24
|
+
response.set_cookie(COOKIE_NAME, {:value => {'date_set'=>Time.now.to_i, 'capabilities'=>env['wurfl.cookie.device_cache']}.to_json, :path => "/", :expires => Time.now+EXPIRY})
|
|
25
|
+
response.finish
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def extract_wurfl_cookie(cookies)
|
|
31
|
+
# read the cookie and try to parse it
|
|
32
|
+
raw_cookie = cookies[COOKIE_NAME]
|
|
33
|
+
parsed_cookie = JSON.parse(raw_cookie)
|
|
34
|
+
|
|
35
|
+
# if parsed then check the expiry
|
|
36
|
+
return nil if !parsed_cookie.has_key?('date_set') || (parsed_cookie['date_set'].to_i+EXPIRY < Time.now.to_i)
|
|
37
|
+
|
|
38
|
+
# check if the capabilities params are present
|
|
39
|
+
return nil if !parsed_cookie.has_key?('capabilities') || !parsed_cookie['capabilities'].is_a?(Hash) || parsed_cookie['capabilities'].empty?
|
|
40
|
+
|
|
41
|
+
parsed_cookie['capabilities']
|
|
42
|
+
|
|
43
|
+
rescue Exception=>e
|
|
44
|
+
nil
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
require 'wurfl_cloud/helper'
|
|
6
|
+
require 'wurfl_cloud/rack/cache_manager'
|
|
7
|
+
|
|
8
|
+
module WurflCloud
|
|
9
|
+
class Engine < ::Rails::Engine
|
|
10
|
+
|
|
11
|
+
# # Initialize the cache manager rack middleware
|
|
12
|
+
# config.app_middleware.use WurflCloud::Rack::CacheManager
|
|
13
|
+
|
|
14
|
+
# adds the moethods to the controller and views
|
|
15
|
+
initializer "wurf_cloud.helpers" do
|
|
16
|
+
ActiveSupport.on_load(:action_controller) do
|
|
17
|
+
include WurflCloud::Helper
|
|
18
|
+
helper_method :wurfl_detect_device
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
ActiveSupport.on_load(:action_view) do
|
|
22
|
+
include WurflCloud::Helper
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/wurfl_cloud.rb
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
require 'wurfl_cloud/configuration'
|
|
6
|
+
require 'wurfl_cloud/cache/null'
|
|
7
|
+
require 'wurfl_cloud/cache/cookie'
|
|
8
|
+
require 'wurfl_cloud/version'
|
|
9
|
+
require 'wurfl_cloud/client'
|
|
10
|
+
require 'wurfl_cloud/environment'
|
|
11
|
+
require 'wurfl_cloud/device_capabilities'
|
|
12
|
+
require 'wurfl_cloud/errors'
|
|
13
|
+
|
|
14
|
+
module WurflCloud
|
|
15
|
+
|
|
16
|
+
class << self
|
|
17
|
+
|
|
18
|
+
# A configuration object. See WurflCloud::Configuration.
|
|
19
|
+
attr_writer :configuration
|
|
20
|
+
|
|
21
|
+
# Call this method to modify defaults in your initializers.
|
|
22
|
+
#
|
|
23
|
+
# @example
|
|
24
|
+
# WurflCloud.configure do |config|
|
|
25
|
+
# config.api_key = '00000000:xxxxxxxxxxxxxxxxxxxxxxxxxxx'
|
|
26
|
+
# config.host = 'staging.wurflcloud.com'
|
|
27
|
+
# end
|
|
28
|
+
def configure(silent = false)
|
|
29
|
+
yield(configuration)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# The configuration object.
|
|
33
|
+
# @see WurflCloud.configure
|
|
34
|
+
def configuration
|
|
35
|
+
@configuration ||= WurflCloud::Configuration.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
require 'wurfl_cloud/rails' if defined?(Rails)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"id":"generic","user_agent":"","fall_back":"root","browser_id":"browser_root","mobile_browser":"","nokia_feature_pack":0,"device_os":"","nokia_series":0,"has_qwerty_keyboard":false,"pointing_method":"mouse","mobile_browser_version":"","is_tablet":false,"nokia_edition":0,"uaprof":"","can_skip_aligned_link_row":false,"device_claims_web_support":false,"ununiqueness_handler":"","model_name":"","device_os_version":"","uaprof2":"","is_wireless_device":false,"uaprof3":"","brand_name":"generic web browser","model_extra_info":"","marketing_name":"","can_assign_phone_number":true,"release_date":"2002_january","unique":true,"icons_on_menu_items_support":false,"opwv_wml_extensions_support":false,"built_in_back_button_support":false,"proportional_font":false,"insert_br_element_after_widget_recommended":false,"wizards_recommended":false,"wml_can_display_images_and_text_on_same_line":false,"softkey_support":false,"wml_make_phone_call_string":"wtai:\/\/wp\/mc;","deck_prefetch_support":false,"menu_with_select_element_recommended":false,"numbered_menus":false,"card_title_support":true,"image_as_link_support":false,"wrap_mode_support":false,"table_support":true,"access_key_support":false,"wml_displays_image_in_center":false,"elective_forms_recommended":true,"times_square_mode_support":false,"break_list_of_links_with_br_element_recommended":true,"menu_with_list_of_links_recommended":true,"imode_region":"none","chtml_can_display_images_and_text_on_same_line":false,"chtml_displays_image_in_center":false,"chtml_make_phone_call_string":"tel:","chtml_table_support":false,"chtml_display_accesskey":false,"emoji":false,"xhtml_preferred_charset":"utf8","xhtml_supports_css_cell_table_coloring":false,"xhtml_select_as_radiobutton":false,"xhtml_autoexpand_select":false,"xhtml_avoid_accesskeys":false,"accept_third_party_cookie":true,"xhtml_make_phone_call_string":"tel:","xhtml_allows_disabled_form_elements":false,"xhtml_supports_invisible_text":false,"xhtml_select_as_dropdown":false,"cookie_support":true,"xhtml_send_mms_string":"none","xhtml_table_support":false,"xhtml_display_accesskey":false,"xhtml_can_embed_video":"none","xhtml_supports_iframe":"none","xhtmlmp_preferred_mime_type":"application\/vnd.wap.xhtml+xml","xhtml_supports_monospace_font":false,"xhtml_supports_inline_input":false,"xhtml_supports_forms_in_table":false,"xhtml_document_title_support":true,"xhtml_support_wml2_namespace":false,"xhtml_readable_background_color1":"#FFFFFF","xhtml_format_as_attribute":false,"xhtml_supports_table_for_layout":false,"xhtml_readable_background_color2":"#FFFFFF","xhtml_select_as_popup":false,"xhtml_send_sms_string":"none","xhtml_format_as_css_property":false,"xhtml_file_upload":"not_supported","xhtml_honors_bgcolor":false,"opwv_xhtml_extensions_support":false,"xhtml_marquee_as_css_property":false,"xhtml_nowrap_mode":false,"ajax_preferred_geoloc_api":"none","ajax_xhr_type":"none","ajax_support_getelementbyid":false,"ajax_support_event_listener":false,"ajax_manipulate_dom":false,"ajax_support_javascript":false,"ajax_support_inner_html":false,"ajax_manipulate_css":false,"ajax_support_events":false,"html_web_3_2":false,"html_wi_imode_htmlx_1":false,"html_wi_imode_html_1":false,"html_wi_oma_xhtmlmp_1_0":true,"html_wi_imode_html_2":false,"html_wi_w3_xhtmlbasic":true,"html_wi_imode_compact_generic":false,"html_wi_imode_html_3":false,"wml_1_1":true,"html_wi_imode_html_4":false,"wml_1_2":false,"html_wi_imode_html_5":false,"wml_1_3":false,"preferred_markup":"html_wi_oma_xhtmlmp_1_0","xhtml_support_level":1,"voicexml":false,"html_wi_imode_htmlx_1_1":false,"multipart_support":false,"html_web_4_0":false,"time_to_live_support":false,"total_cache_disable_support":false,"physical_screen_height":27,"columns":11,"dual_orientation":false,"physical_screen_width":27,"rows":6,"max_image_width":90,"resolution_height":40,"resolution_width":90,"max_image_height":35,"greyscale":false,"jpg":false,"gif":true,"transparent_png_index":false,"epoc_bmp":false,"bmp":false,"wbmp":true,"gif_animated":false,"colors":256,"svgt_1_1_plus":false,"svgt_1_1":false,"transparent_png_alpha":false,"png":false,"tiff":false,"emptyok":false,"empty_option_value_support":true,"basic_authentication_support":true,"post_method_support":true,"nokia_voice_call":false,"wta_pdc":false,"wta_voice_call":false,"wta_misc":false,"wta_phonebook":false,"phone_id_provided":false,"https_support":true,"sdio":false,"wifi":false,"has_cellular_radio":true,"max_data_rate":9,"vpn":false,"max_length_of_username":0,"max_url_length_bookmark":0,"max_no_of_bookmarks":0,"max_deck_size":4000,"max_url_length_cached_page":0,"max_length_of_password":0,"max_no_of_connection_settings":0,"max_url_length_in_requests":128,"max_object_size":0,"max_url_length_homepage":0,"video":false,"picture_bmp":false,"picture":false,"wallpaper_df_size_limit":0,"picture_preferred_width":0,"wallpaper_oma_size_limit":0,"picture_greyscale":false,"inline_support":false,"ringtone_qcelp":false,"screensaver_oma_size_limit":0,"screensaver_wbmp":false,"picture_resize":"none","picture_preferred_height":0,"ringtone_rmf":false,"wallpaper_wbmp":false,"wallpaper_jpg":false,"screensaver_bmp":false,"screensaver_max_width":0,"picture_inline_size_limit":0,"picture_colors":2,"ringtone_midi_polyphonic":false,"ringtone_midi_monophonic":false,"screensaver_preferred_height":0,"ringtone_voices":1,"ringtone_3gpp":false,"oma_support":false,"ringtone_inline_size_limit":0,"wallpaper_preferred_width":0,"wallpaper_greyscale":false,"screensaver_preferred_width":0,"wallpaper_preferred_height":0,"picture_max_width":0,"picture_jpg":false,"ringtone_aac":false,"ringtone_oma_size_limit":0,"wallpaper_directdownload_size_limit":0,"screensaver_inline_size_limit":0,"ringtone_xmf":false,"picture_max_height":0,"screensaver_max_height":0,"ringtone_mp3":false,"wallpaper_png":false,"screensaver_jpg":false,"ringtone_directdownload_size_limit":0,"wallpaper_max_width":0,"wallpaper_max_height":0,"screensaver":false,"ringtone_wav":false,"wallpaper_gif":false,"screensaver_directdownload_size_limit":0,"picture_df_size_limit":0,"wallpaper_tiff":false,"screensaver_df_size_limit":0,"ringtone_awb":false,"ringtone":false,"wallpaper_inline_size_limit":0,"picture_directdownload_size_limit":0,"picture_png":false,"wallpaper_bmp":false,"picture_wbmp":false,"ringtone_df_size_limit":0,"picture_oma_size_limit":0,"picture_gif":false,"screensaver_png":false,"wallpaper_resize":"none","screensaver_greyscale":false,"ringtone_mmf":false,"ringtone_amr":false,"wallpaper":false,"ringtone_digiplug":false,"ringtone_spmidi":false,"ringtone_compactmidi":false,"ringtone_imelody":false,"screensaver_resize":"none","wallpaper_colors":2,"directdownload_support":false,"downloadfun_support":false,"screensaver_colors":2,"screensaver_gif":false,"oma_v_1_0_combined_delivery":false,"oma_v_1_0_separate_delivery":false,"oma_v_1_0_forwardlock":false,"streaming_vcodec_mpeg4_asp":-1,"streaming_video_size_limit":0,"streaming_mov":false,"streaming_wmv":"none","streaming_acodec_aac":"none","streaming_vcodec_h263_0":-1,"streaming_real_media":"none","streaming_3g2":false,"streaming_3gpp":false,"streaming_acodec_amr":"none","streaming_vcodec_h264_bp":-1,"streaming_vcodec_h263_3":-1,"streaming_preferred_protocol":"rtsp","streaming_vcodec_mpeg4_sp":-1,"streaming_flv":false,"streaming_video":false,"streaming_preferred_http_protocol":"none","streaming_mp4":false,"expiration_date":false,"utf8_support":false,"connectionless_cache_operation":false,"connectionless_service_load":false,"iso8859_support":false,"connectionoriented_confirmed_service_indication":false,"connectionless_service_indication":false,"ascii_support":false,"connectionoriented_confirmed_cache_operation":false,"connectionoriented_confirmed_service_load":false,"wap_push_support":false,"connectionoriented_unconfirmed_cache_operation":false,"connectionoriented_unconfirmed_service_load":false,"connectionoriented_unconfirmed_service_indication":false,"doja_1_5":false,"j2me_datefield_broken":false,"j2me_clear_key_code":0,"j2me_right_softkey_code":0,"j2me_heap_size":0,"j2me_canvas_width":0,"j2me_motorola_lwt":false,"doja_3_5":false,"j2me_wbmp":false,"j2me_rmf":false,"j2me_wma":false,"j2me_left_softkey_code":0,"j2me_jtwi":false,"j2me_jpg":false,"j2me_return_key_code":0,"j2me_real8":false,"j2me_max_record_store_size":0,"j2me_realmedia":false,"j2me_midp_1_0":false,"j2me_bmp3":false,"j2me_midi":false,"j2me_btapi":false,"j2me_locapi":false,"j2me_siemens_extension":false,"j2me_h263":false,"j2me_audio_capture_enabled":false,"j2me_midp_2_0":false,"j2me_datefield_no_accepts_null_date":false,"j2me_aac":false,"j2me_capture_image_formats":"none","j2me_select_key_code":0,"j2me_xmf":false,"j2me_photo_capture_enabled":false,"j2me_realaudio":false,"j2me_realvideo":false,"j2me_mp3":false,"j2me_png":false,"j2me_au":false,"j2me_screen_width":0,"j2me_mp4":false,"j2me_mmapi_1_0":false,"j2me_http":false,"j2me_imelody":false,"j2me_socket":false,"j2me_3dapi":false,"j2me_bits_per_pixel":0,"j2me_mmapi_1_1":false,"j2me_udp":false,"j2me_wav":false,"j2me_middle_softkey_code":0,"j2me_svgt":false,"j2me_gif":false,"j2me_siemens_color_game":false,"j2me_max_jar_size":0,"j2me_wmapi_1_0":false,"j2me_nokia_ui":false,"j2me_screen_height":0,"j2me_wmapi_1_1":false,"j2me_wmapi_2_0":false,"doja_1_0":false,"j2me_serial":false,"doja_2_0":false,"j2me_bmp":false,"j2me_amr":false,"j2me_gif89a":false,"j2me_cldc_1_0":false,"doja_2_1":false,"doja_3_0":false,"j2me_cldc_1_1":false,"doja_2_2":false,"doja_4_0":false,"j2me_3gpp":false,"j2me_video_capture_enabled":false,"j2me_canvas_height":0,"j2me_https":false,"j2me_mpeg4":false,"j2me_storage_size":0,"mms_3gpp":false,"mms_wbxml":false,"mms_symbian_install":false,"mms_png":false,"mms_max_size":0,"mms_rmf":false,"mms_nokia_operatorlogo":false,"mms_max_width":0,"mms_max_frame_rate":0,"mms_wml":false,"mms_evrc":false,"mms_spmidi":false,"mms_gif_static":false,"mms_max_height":0,"sender":false,"mms_video":false,"mms_vcard":false,"mms_nokia_3dscreensaver":false,"mms_qcelp":false,"mms_midi_polyphonic":false,"mms_wav":false,"mms_jpeg_progressive":false,"mms_jad":false,"mms_nokia_ringingtone":false,"built_in_recorder":false,"mms_midi_monophonic":false,"mms_3gpp2":false,"mms_wmlc":false,"mms_nokia_wallpaper":false,"mms_bmp":false,"mms_vcalendar":false,"mms_jar":false,"mms_ota_bitmap":false,"mms_mp3":false,"mms_mmf":false,"mms_amr":false,"mms_wbmp":false,"built_in_camera":false,"receiver":false,"mms_mp4":false,"mms_xmf":false,"mms_jpeg_baseline":false,"mms_midi_polyphonic_voices":0,"mms_gif_animated":false,"ems":false,"text_imelody":false,"nokiaring":false,"siemens_logo_height":29,"ems_variablesizedpictures":false,"sckl_groupgraphic":false,"siemens_ota":false,"sagem_v1":false,"largeoperatorlogo":false,"sagem_v2":false,"ems_version":0,"ems_odi":false,"nokiavcal":false,"operatorlogo":false,"siemens_logo_width":101,"ems_imelody":false,"sckl_vcard":false,"siemens_screensaver_width":101,"sckl_operatorlogo":false,"panasonic":false,"ems_upi":false,"nokiavcard":false,"callericon":false,"sms_enabled":true,"gprtf":false,"siemens_screensaver_height":50,"sckl_ringtone":false,"picturemessage":false,"sckl_vcalendar":false,"rmf":false,"qcelp":false,"awb":false,"smf":false,"wav":false,"nokia_ringtone":false,"aac":false,"digiplug":false,"sp_midi":false,"compactmidi":false,"voices":1,"mp3":false,"mld":false,"evrc":false,"amr":false,"xmf":false,"mmf":false,"imelody":false,"midi_monophonic":false,"au":false,"midi_polyphonic":false,"flash_lite_version":"","fl_wallpaper":false,"fl_browser":false,"fl_screensaver":false,"fl_standalone":false,"full_flash_support":false,"fl_sub_lcd":false,"css_gradient":"none","css_border_image":"none","css_rounded_corners":"none","css_spriting":false,"css_supports_width_as_percentage":true,"is_transcoder":false,"transcoder_ua_header":"user-agent","rss_support":false,"pdf_support":false,"playback_oma_size_limit":0,"playback_acodec_aac":"none","playback_vcodec_h263_3":-1,"playback_vcodec_mpeg4_asp":-1,"playback_mp4":false,"playback_3gpp":false,"playback_df_size_limit":0,"playback_acodec_amr":"none","playback_mov":false,"playback_wmv":"none","playback_acodec_qcelp":false,"progressive_download":false,"playback_directdownload_size_limit":0,"playback_real_media":"none","playback_3g2":false,"playback_vcodec_mpeg4_sp":-1,"playback_vcodec_h263_0":-1,"playback_inline_size_limit":0,"hinted_progressive_download":false,"playback_vcodec_h264_bp":-1,"streaming_video_acodec_amr":false,"streaming_video_vcodec_h263_0":false,"streaming_video_max_video_bit_rate":0,"video_acodec_amr":false,"video_vcodec_h263_3":false,"video_directdownload_size_limit":0,"video_max_width":0,"streaming_video_sqcif":false,"streaming_real_media_10":false,"has_pointing_device":false,"streaming_video_sqcif_max_width":0,"video_vcodec_mpeg4":false,"video_inline_size_limit":0,"streaming_video_vcodec_h263_3":false,"streaming_video_max_bit_rate":0,"video_vcodec_h264":"none","streaming_video_sqcif_max_height":0,"video_df_size_limit":0,"video_3gpp2":false,"video_real_media_8":false,"streaming_video_max_audio_bit_rate":0,"video_real_media_10":false,"video_real_media_9":false,"xhtml_supports_file_upload":false,"streaming_video_vcodec_mpeg4":false,"video_acodec_qcelp":false,"video_acodec_awb":false,"video_max_height":0,"video_mp4":false,"video_3gpp":false,"streaming_video_acodec_aac_ltp":false,"streaming_video_acodec_awb":false,"streaming_video_max_frame_rate":0,"streaming_real_media_8":false,"video_acodec_aac":false,"video_oma_size_limit":0,"streaming_video_acodec_aac":false,"streaming_video_min_video_bit_rate":0,"streaming_real_media_9":false,"video_vcodec_h263_0":false,"video_preferred_width":0,"video_sqcif":false,"video_qcif":false,"streaming_video_qcif":false,"video_preferred_height":0,"video_mov":false,"streaming_prefered_http_protocol":"none","streaming_video_vcodec_h264":"none","streaming_video_qcif_max_height":0,"streaming_video_qcif_max_width":0,"video_acodec_aac_ltp":false,"video_max_frame_rate":0,"video_wmv":false,"https_detectable":false,"canvas_support":"none","viewport_width":"","html_preferred_dtd":"html4","viewport_supported":false,"viewport_minimum_scale":"","viewport_initial_scale":"","mobileoptimized":false,"viewport_maximum_scale":"","viewport_userscalable":"","image_inlining":false,"handheldfriendly":false,"is_smarttv":false,"fm_tuner_support":false,"nfc_support":false,"ux_full_desktop":false,"ux_full_web_usability_index":-100,"num_queries":3,"match_type":"none","matcher":"none","match":false,"lookup_time":0.0031659603118896,"matcher_history":"CatchAllUserAgentMatcher(exact),CatchAllUserAgentMatcher(conclusive),CatchAllUserAgentMatcher(recovery),http_accept","actual_root_device":"","fall_back_tree":"generic"},"errors":{}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"is_wireless_device":false,"browser_id":"browser_root","fall_back":"root","user_agent":"","resolution_width": 800,"device_os_version":10.5},"errors":{}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"nokia_lumia_800_ver1","capabilities":{"id":"nokia_lumia_800_ver1","user_agent":"Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800)","fall_back":"generic_ms_nokia_phone_os7_5","actual_device_root":1,"browser_id":"browser_winmo_iemobile9","mobile_browser":"IEMobile","nokia_feature_pack":0,"device_os":"Windows Phone OS","nokia_series":0,"has_qwerty_keyboard":true,"pointing_method":"touchscreen","mobile_browser_version":"9.0","is_tablet":false,"nokia_edition":0,"uaprof":"http:\/\/nds1.nds.nokia.com\/uaprof\/Nokia800r100.xml","can_skip_aligned_link_row":true,"device_claims_web_support":true,"ununiqueness_handler":"","model_name":"Lumia 800","device_os_version":7.5,"uaprof2":"","is_wireless_device":true,"uaprof3":"","brand_name":"Nokia","model_extra_info":"","marketing_name":"","can_assign_phone_number":true,"release_date":"2011_october","unique":true,"icons_on_menu_items_support":false,"opwv_wml_extensions_support":false,"built_in_back_button_support":false,"proportional_font":false,"insert_br_element_after_widget_recommended":false,"wizards_recommended":false,"wml_can_display_images_and_text_on_same_line":false,"softkey_support":false,"wml_make_phone_call_string":"wtai:\/\/wp\/mc;","deck_prefetch_support":false,"menu_with_select_element_recommended":false,"numbered_menus":false,"card_title_support":true,"image_as_link_support":false,"wrap_mode_support":false,"table_support":true,"access_key_support":false,"wml_displays_image_in_center":false,"elective_forms_recommended":true,"times_square_mode_support":false,"break_list_of_links_with_br_element_recommended":true,"menu_with_list_of_links_recommended":true,"imode_region":"none","chtml_can_display_images_and_text_on_same_line":false,"chtml_displays_image_in_center":false,"chtml_make_phone_call_string":"tel:","chtml_table_support":false,"chtml_display_accesskey":false,"emoji":false,"xhtml_preferred_charset":"utf8","xhtml_supports_css_cell_table_coloring":false,"xhtml_select_as_radiobutton":false,"xhtml_autoexpand_select":false,"xhtml_avoid_accesskeys":false,"accept_third_party_cookie":true,"xhtml_make_phone_call_string":"tel:","xhtml_allows_disabled_form_elements":false,"xhtml_supports_invisible_text":false,"xhtml_select_as_dropdown":false,"cookie_support":true,"xhtml_send_mms_string":"none","xhtml_table_support":true,"xhtml_display_accesskey":false,"xhtml_can_embed_video":"none","xhtml_supports_iframe":"full","xhtmlmp_preferred_mime_type":"application\/vnd.wap.xhtml+xml","xhtml_supports_monospace_font":false,"xhtml_supports_inline_input":false,"xhtml_supports_forms_in_table":false,"xhtml_document_title_support":true,"xhtml_support_wml2_namespace":false,"xhtml_readable_background_color1":"#FFFFFF","xhtml_format_as_attribute":false,"xhtml_supports_table_for_layout":false,"xhtml_readable_background_color2":"#FFFFFF","xhtml_select_as_popup":false,"xhtml_send_sms_string":"none","xhtml_format_as_css_property":false,"xhtml_file_upload":"not_supported","xhtml_honors_bgcolor":false,"opwv_xhtml_extensions_support":false,"xhtml_marquee_as_css_property":false,"xhtml_nowrap_mode":false,"ajax_preferred_geoloc_api":"none","ajax_xhr_type":"standard","ajax_support_getelementbyid":true,"ajax_support_event_listener":true,"ajax_manipulate_dom":true,"ajax_support_javascript":true,"ajax_support_inner_html":true,"ajax_manipulate_css":true,"ajax_support_events":true,"html_web_3_2":false,"html_wi_imode_htmlx_1":false,"html_wi_imode_html_1":false,"html_wi_oma_xhtmlmp_1_0":true,"html_wi_imode_html_2":false,"html_wi_w3_xhtmlbasic":true,"html_wi_imode_compact_generic":false,"html_wi_imode_html_3":false,"wml_1_1":false,"html_wi_imode_html_4":false,"wml_1_2":false,"html_wi_imode_html_5":false,"wml_1_3":false,"preferred_markup":"html_web_4_0","xhtml_support_level":4,"voicexml":false,"html_wi_imode_htmlx_1_1":false,"multipart_support":false,"html_web_4_0":true,"time_to_live_support":false,"total_cache_disable_support":false,"physical_screen_height":161,"columns":16,"dual_orientation":true,"physical_screen_width":97,"rows":12,"max_image_width":320,"resolution_height":800,"resolution_width":480,"max_image_height":480,"greyscale":false,"jpg":true,"gif":true,"transparent_png_index":false,"epoc_bmp":false,"bmp":false,"wbmp":false,"gif_animated":true,"colors":65536,"svgt_1_1_plus":false,"svgt_1_1":false,"transparent_png_alpha":false,"png":true,"tiff":false,"emptyok":false,"empty_option_value_support":true,"basic_authentication_support":true,"post_method_support":true,"nokia_voice_call":false,"wta_pdc":false,"wta_voice_call":false,"wta_misc":false,"wta_phonebook":false,"phone_id_provided":false,"https_support":true,"sdio":false,"wifi":true,"has_cellular_radio":true,"max_data_rate":384,"vpn":false,"max_length_of_username":0,"max_url_length_bookmark":0,"max_no_of_bookmarks":0,"max_deck_size":100000,"max_url_length_cached_page":0,"max_length_of_password":0,"max_no_of_connection_settings":0,"max_url_length_in_requests":512,"max_object_size":0,"max_url_length_homepage":0,"video":false,"picture_bmp":false,"picture":false,"wallpaper_df_size_limit":0,"picture_preferred_width":0,"wallpaper_oma_size_limit":0,"picture_greyscale":false,"inline_support":false,"ringtone_qcelp":false,"screensaver_oma_size_limit":0,"screensaver_wbmp":false,"picture_resize":"none","picture_preferred_height":0,"ringtone_rmf":false,"wallpaper_wbmp":false,"wallpaper_jpg":false,"screensaver_bmp":false,"screensaver_max_width":0,"picture_inline_size_limit":0,"picture_colors":2,"ringtone_midi_polyphonic":false,"ringtone_midi_monophonic":false,"screensaver_preferred_height":0,"ringtone_voices":1,"ringtone_3gpp":false,"oma_support":false,"ringtone_inline_size_limit":0,"wallpaper_preferred_width":0,"wallpaper_greyscale":false,"screensaver_preferred_width":0,"wallpaper_preferred_height":0,"picture_max_width":0,"picture_jpg":false,"ringtone_aac":false,"ringtone_oma_size_limit":0,"wallpaper_directdownload_size_limit":0,"screensaver_inline_size_limit":0,"ringtone_xmf":false,"picture_max_height":0,"screensaver_max_height":0,"ringtone_mp3":false,"wallpaper_png":false,"screensaver_jpg":false,"ringtone_directdownload_size_limit":0,"wallpaper_max_width":0,"wallpaper_max_height":0,"screensaver":false,"ringtone_wav":false,"wallpaper_gif":false,"screensaver_directdownload_size_limit":0,"picture_df_size_limit":0,"wallpaper_tiff":false,"screensaver_df_size_limit":0,"ringtone_awb":false,"ringtone":false,"wallpaper_inline_size_limit":0,"picture_directdownload_size_limit":0,"picture_png":false,"wallpaper_bmp":false,"picture_wbmp":false,"ringtone_df_size_limit":0,"picture_oma_size_limit":0,"picture_gif":false,"screensaver_png":false,"wallpaper_resize":"none","screensaver_greyscale":false,"ringtone_mmf":false,"ringtone_amr":false,"wallpaper":false,"ringtone_digiplug":false,"ringtone_spmidi":false,"ringtone_compactmidi":false,"ringtone_imelody":false,"screensaver_resize":"none","wallpaper_colors":2,"directdownload_support":false,"downloadfun_support":false,"screensaver_colors":2,"screensaver_gif":false,"oma_v_1_0_combined_delivery":false,"oma_v_1_0_separate_delivery":false,"oma_v_1_0_forwardlock":false,"streaming_vcodec_mpeg4_asp":-1,"streaming_video_size_limit":0,"streaming_mov":false,"streaming_wmv":9,"streaming_acodec_aac":"lc","streaming_vcodec_h263_0":10,"streaming_real_media":"none","streaming_3g2":true,"streaming_3gpp":true,"streaming_acodec_amr":"nb","streaming_vcodec_h264_bp":0,"streaming_vcodec_h263_3":-1,"streaming_preferred_protocol":"http","streaming_vcodec_mpeg4_sp":0,"streaming_flv":false,"streaming_video":true,"streaming_preferred_http_protocol":"microsoft_smooth_streaming","streaming_mp4":true,"expiration_date":false,"utf8_support":false,"connectionless_cache_operation":false,"connectionless_service_load":true,"iso8859_support":false,"connectionoriented_confirmed_service_indication":false,"connectionless_service_indication":true,"ascii_support":false,"connectionoriented_confirmed_cache_operation":false,"connectionoriented_confirmed_service_load":false,"wap_push_support":true,"connectionoriented_unconfirmed_cache_operation":false,"connectionoriented_unconfirmed_service_load":false,"connectionoriented_unconfirmed_service_indication":false,"doja_1_5":false,"j2me_datefield_broken":false,"j2me_clear_key_code":0,"j2me_right_softkey_code":0,"j2me_heap_size":0,"j2me_canvas_width":0,"j2me_motorola_lwt":false,"doja_3_5":false,"j2me_wbmp":false,"j2me_rmf":false,"j2me_wma":false,"j2me_left_softkey_code":0,"j2me_jtwi":false,"j2me_jpg":false,"j2me_return_key_code":0,"j2me_real8":false,"j2me_max_record_store_size":0,"j2me_realmedia":false,"j2me_midp_1_0":false,"j2me_bmp3":false,"j2me_midi":false,"j2me_btapi":false,"j2me_locapi":false,"j2me_siemens_extension":false,"j2me_h263":false,"j2me_audio_capture_enabled":false,"j2me_midp_2_0":false,"j2me_datefield_no_accepts_null_date":false,"j2me_aac":false,"j2me_capture_image_formats":"none","j2me_select_key_code":0,"j2me_xmf":false,"j2me_photo_capture_enabled":false,"j2me_realaudio":false,"j2me_realvideo":false,"j2me_mp3":false,"j2me_png":false,"j2me_au":false,"j2me_screen_width":0,"j2me_mp4":false,"j2me_mmapi_1_0":false,"j2me_http":false,"j2me_imelody":false,"j2me_socket":false,"j2me_3dapi":false,"j2me_bits_per_pixel":0,"j2me_mmapi_1_1":false,"j2me_udp":false,"j2me_wav":false,"j2me_middle_softkey_code":0,"j2me_svgt":false,"j2me_gif":false,"j2me_siemens_color_game":false,"j2me_max_jar_size":0,"j2me_wmapi_1_0":false,"j2me_nokia_ui":false,"j2me_screen_height":0,"j2me_wmapi_1_1":false,"j2me_wmapi_2_0":false,"doja_1_0":false,"j2me_serial":false,"doja_2_0":false,"j2me_bmp":false,"j2me_amr":false,"j2me_gif89a":false,"j2me_cldc_1_0":false,"doja_2_1":false,"doja_3_0":false,"j2me_cldc_1_1":false,"doja_2_2":false,"doja_4_0":false,"j2me_3gpp":false,"j2me_video_capture_enabled":false,"j2me_canvas_height":0,"j2me_https":false,"j2me_mpeg4":false,"j2me_storage_size":0,"mms_3gpp":true,"mms_wbxml":false,"mms_symbian_install":false,"mms_png":true,"mms_max_size":614400,"mms_rmf":false,"mms_nokia_operatorlogo":false,"mms_max_width":1600,"mms_max_frame_rate":0,"mms_wml":false,"mms_evrc":false,"mms_spmidi":false,"mms_gif_static":true,"mms_max_height":1600,"sender":true,"mms_video":true,"mms_vcard":false,"mms_nokia_3dscreensaver":false,"mms_qcelp":false,"mms_midi_polyphonic":false,"mms_wav":true,"mms_jpeg_progressive":false,"mms_jad":false,"mms_nokia_ringingtone":false,"built_in_recorder":false,"mms_midi_monophonic":false,"mms_3gpp2":true,"mms_wmlc":false,"mms_nokia_wallpaper":false,"mms_bmp":true,"mms_vcalendar":false,"mms_jar":false,"mms_ota_bitmap":false,"mms_mp3":true,"mms_mmf":false,"mms_amr":false,"mms_wbmp":false,"built_in_camera":false,"receiver":true,"mms_mp4":true,"mms_xmf":false,"mms_jpeg_baseline":true,"mms_midi_polyphonic_voices":0,"mms_gif_animated":true,"ems":false,"text_imelody":false,"nokiaring":false,"siemens_logo_height":29,"ems_variablesizedpictures":false,"sckl_groupgraphic":false,"siemens_ota":false,"sagem_v1":false,"largeoperatorlogo":false,"sagem_v2":false,"ems_version":0,"ems_odi":false,"nokiavcal":false,"operatorlogo":false,"siemens_logo_width":101,"ems_imelody":false,"sckl_vcard":false,"siemens_screensaver_width":101,"sckl_operatorlogo":false,"panasonic":false,"ems_upi":false,"nokiavcard":false,"callericon":false,"sms_enabled":true,"gprtf":false,"siemens_screensaver_height":50,"sckl_ringtone":false,"picturemessage":false,"sckl_vcalendar":false,"rmf":false,"qcelp":false,"awb":false,"smf":false,"wav":true,"nokia_ringtone":false,"aac":true,"digiplug":false,"sp_midi":false,"compactmidi":false,"voices":1,"mp3":true,"mld":false,"evrc":false,"amr":false,"xmf":false,"mmf":false,"imelody":false,"midi_monophonic":false,"au":false,"midi_polyphonic":false,"flash_lite_version":"","fl_wallpaper":false,"fl_browser":false,"fl_screensaver":false,"fl_standalone":false,"full_flash_support":false,"fl_sub_lcd":false,"css_gradient":"none","css_border_image":"none","css_rounded_corners":"none","css_spriting":true,"css_supports_width_as_percentage":true,"is_transcoder":false,"transcoder_ua_header":"user-agent","rss_support":true,"pdf_support":true,"playback_oma_size_limit":0,"playback_acodec_aac":"lc","playback_vcodec_h263_3":-1,"playback_vcodec_mpeg4_asp":-1,"playback_mp4":true,"playback_3gpp":true,"playback_df_size_limit":0,"playback_acodec_amr":"nb","playback_mov":false,"playback_wmv":9,"playback_acodec_qcelp":false,"progressive_download":true,"playback_directdownload_size_limit":0,"playback_real_media":"none","playback_3g2":true,"playback_vcodec_mpeg4_sp":0,"playback_vcodec_h263_0":10,"playback_inline_size_limit":0,"hinted_progressive_download":false,"playback_vcodec_h264_bp":0,"streaming_video_acodec_amr":false,"streaming_video_vcodec_h263_0":false,"streaming_video_max_video_bit_rate":0,"video_acodec_amr":false,"video_vcodec_h263_3":false,"video_directdownload_size_limit":0,"video_max_width":0,"streaming_video_sqcif":false,"streaming_real_media_10":false,"has_pointing_device":false,"streaming_video_sqcif_max_width":0,"video_vcodec_mpeg4":false,"video_inline_size_limit":0,"streaming_video_vcodec_h263_3":false,"streaming_video_max_bit_rate":0,"video_vcodec_h264":"none","streaming_video_sqcif_max_height":0,"video_df_size_limit":0,"video_3gpp2":false,"video_real_media_8":false,"streaming_video_max_audio_bit_rate":0,"video_real_media_10":false,"video_real_media_9":false,"xhtml_supports_file_upload":false,"streaming_video_vcodec_mpeg4":false,"video_acodec_qcelp":false,"video_acodec_awb":false,"video_max_height":0,"video_mp4":false,"video_3gpp":false,"streaming_video_acodec_aac_ltp":false,"streaming_video_acodec_awb":false,"streaming_video_max_frame_rate":0,"streaming_real_media_8":false,"video_acodec_aac":false,"video_oma_size_limit":0,"streaming_video_acodec_aac":false,"streaming_video_min_video_bit_rate":0,"streaming_real_media_9":false,"video_vcodec_h263_0":false,"video_preferred_width":0,"video_sqcif":false,"video_qcif":false,"streaming_video_qcif":false,"video_preferred_height":0,"video_mov":false,"streaming_prefered_http_protocol":"microsoft_smooth_streaming","streaming_video_vcodec_h264":"none","streaming_video_qcif_max_height":0,"streaming_video_qcif_max_width":0,"video_acodec_aac_ltp":false,"video_max_frame_rate":0,"video_wmv":false,"https_detectable":false,"canvas_support":"none","viewport_width":"device_width_token","html_preferred_dtd":"html4","viewport_supported":true,"viewport_minimum_scale":"","viewport_initial_scale":"","mobileoptimized":false,"viewport_maximum_scale":"","viewport_userscalable":"no","image_inlining":true,"handheldfriendly":false,"is_smarttv":false,"fm_tuner_support":false,"nfc_support":false,"ux_full_desktop":false,"ux_full_web_usability_index":-50,"num_queries":2,"match_type":"exact","matcher":"WindowsPhoneUserAgentMatcher","match":true,"lookup_time":0.0045168399810791,"matcher_history":"WindowsPhoneUserAgentMatcher(exact)","actual_root_device":"nokia_lumia_800_ver1","fall_back_tree":"nokia_lumia_800_ver1,generic_ms_nokia_phone_os7_5,generic_ms_phone_os7_5,generic_ms_phone_os7,generic_xhtml,generic_mobile,generic"},"errors":{}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"nokia_lumia_800_ver1","capabilities":{"is_wireless_device":true,"browser_id":"browser_winmo_iemobile9","fall_back":"generic_ms_nokia_phone_os7_5","user_agent":"Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800)"},"errors":{}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"release_date": "1994_january","is_wireless_device":"true","is_tablet":"false","resolution_width": "800"},"errors":{}}
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
require 'simplecov'
|
|
6
|
+
SimpleCov.start do
|
|
7
|
+
add_filter "/spec/"
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
require 'wurfl_cloud'
|
|
12
|
+
require 'webmock/rspec'
|
|
13
|
+
require 'rack'
|
|
14
|
+
|
|
15
|
+
# Load support files
|
|
16
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
|
17
|
+
|
|
18
|
+
RSpec.configure do |config|
|
|
19
|
+
config.include(WurflCloud::Spec::RackHelpers)
|
|
20
|
+
end
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
# adapted from warden
|
|
3
|
+
#
|
|
4
|
+
# Copyright (c) 2009 Daniel Neighman
|
|
5
|
+
#
|
|
6
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
|
7
|
+
# a copy of this software and associated documentation files (the
|
|
8
|
+
# "Software"), to deal in the Software without restriction, including
|
|
9
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
|
10
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
|
11
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
|
12
|
+
# the following conditions:
|
|
13
|
+
#
|
|
14
|
+
# The above copyright notice and this permission notice shall be
|
|
15
|
+
# included in all copies or substantial portions of the Software.
|
|
16
|
+
#
|
|
17
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
18
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
20
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
21
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
22
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
23
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
24
|
+
#
|
|
25
|
+
require 'wurfl_cloud/rack/cache_manager'
|
|
26
|
+
|
|
27
|
+
module WurflCloud::Spec
|
|
28
|
+
module RackHelpers
|
|
29
|
+
FAILURE_APP = lambda{|e|[401, {"Content-Type" => "text/plain"}, ["You Fail!"]] }
|
|
30
|
+
|
|
31
|
+
def env_with_params(path = "/", params = {}, env = {})
|
|
32
|
+
method = params.delete(:method) || "GET"
|
|
33
|
+
env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
|
|
34
|
+
Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def setup_rack(app = nil, opts = {}, &block)
|
|
38
|
+
app ||= block if block_given?
|
|
39
|
+
|
|
40
|
+
opts[:failure_app] ||= failure_app
|
|
41
|
+
|
|
42
|
+
Rack::Builder.new do
|
|
43
|
+
use opts[:session] || WurflCloud::Spec::RackHelpers::Session
|
|
44
|
+
use WurflCloud::Rack::CacheManager, opts
|
|
45
|
+
run app
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def valid_response
|
|
50
|
+
Rack::Response.new("OK").finish
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def failure_app
|
|
54
|
+
WurflCloud::Spec::RackHelpers::FAILURE_APP
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def success_app
|
|
58
|
+
lambda{|e| [200, {"Content-Type" => "text/plain"}, ["You Win"]]}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
class Session
|
|
62
|
+
attr_accessor :app
|
|
63
|
+
def initialize(app,configs = {})
|
|
64
|
+
@app = app
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def call(e)
|
|
68
|
+
e['rack.session'] ||= {}
|
|
69
|
+
@app.call(e)
|
|
70
|
+
end
|
|
71
|
+
end # session
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def authenticated_uri
|
|
75
|
+
c = WurflCloud.configuration
|
|
76
|
+
"#{c.schema}://#{c.api_user}:#{c.api_password}@#{c.host}:#{c.port}#{c.path}"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
class String
|
|
6
|
+
class << self
|
|
7
|
+
def random(length=20)
|
|
8
|
+
self.generic_random(length, ("0".."z"))
|
|
9
|
+
end
|
|
10
|
+
def az_random(length=20)
|
|
11
|
+
self.generic_random(length, ("a".."z"))
|
|
12
|
+
end
|
|
13
|
+
def aznum_random(length=20)
|
|
14
|
+
self.generic_random(length, ("a".."z").to_a + ("0".."9").to_a)
|
|
15
|
+
end
|
|
16
|
+
def az_random_with_num(length=20, num_lenght=20)
|
|
17
|
+
self.generic_random(length, ("a".."z").to_a)+self.generic_random(length, ("0".."9").to_a)
|
|
18
|
+
end
|
|
19
|
+
def generic_random(length,char_range)
|
|
20
|
+
chars = char_range.to_a
|
|
21
|
+
Array.new.tap do |a|
|
|
22
|
+
1.upto(length) { |i| a << chars[rand(chars.size-1)]}
|
|
23
|
+
end.join
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
#
|
|
2
|
+
# This software is the Copyright of ScientiaMobile, Inc.
|
|
3
|
+
# Please refer to the LICENSE.txt file distributed with the software for licensing information
|
|
4
|
+
#
|
|
5
|
+
require 'spec_helper'
|
|
6
|
+
require 'wurfl_cloud/cache/local_memory'
|
|
7
|
+
|
|
8
|
+
describe WurflCloud::Client do
|
|
9
|
+
subject { WurflCloud::Client.new(WurflCloud::Environment.new, nil) }
|
|
10
|
+
|
|
11
|
+
it "should contain a device_capabilities object" do
|
|
12
|
+
subject.device_capabilities.should be_instance_of(WurflCloud::DeviceCapabilities)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "should delegate the [] method to the device_capabilities object" do
|
|
16
|
+
capability_name = String.random
|
|
17
|
+
subject.device_capabilities.should_receive(:[]).with(capability_name)
|
|
18
|
+
subject[capability_name]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should have a read_from_cache method" do
|
|
22
|
+
subject.should respond_to(:read_from_cache)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
context "the detect_device method" do
|
|
26
|
+
it "should be defined with 2 parameters" do
|
|
27
|
+
WurflCloud::Client.should respond_to(:detect_device).with(2).arguments
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
context "when using with the default null cache" do
|
|
33
|
+
before(:each) do
|
|
34
|
+
@http_env = {
|
|
35
|
+
"HTTP_USER_AGENT"=>String.random,
|
|
36
|
+
"HTTP_ACCEPT"=>String.random,
|
|
37
|
+
"HTTP_X_WAP_PROFILE"=>String.random,
|
|
38
|
+
"REMOTE_ADDR"=>String.random
|
|
39
|
+
}
|
|
40
|
+
@environment = WurflCloud::Environment.new(@http_env)
|
|
41
|
+
@cache = WurflCloud.configuration.cache(nil)
|
|
42
|
+
|
|
43
|
+
@device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
|
|
44
|
+
|
|
45
|
+
stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
|
|
46
|
+
|
|
47
|
+
@wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
|
|
48
|
+
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should validate the cache when loading from server" do
|
|
52
|
+
@cache.should_receive(:validate).with(1330016154)
|
|
53
|
+
@wurfl_client.load_from_server!
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should return an instance of the client class" do
|
|
57
|
+
@wurfl_client.should be_instance_of(WurflCloud::Client)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should call the remote webservice" do
|
|
61
|
+
WebMock.should have_requested(:get, authenticated_uri)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should call the remote webservice each time detect_device is called" do
|
|
65
|
+
WurflCloud::Client.detect_device(@environment, @cache)
|
|
66
|
+
WebMock.should have_requested(:get, authenticated_uri).times(2)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
it "should pass the correct headers" do
|
|
71
|
+
headers = {
|
|
72
|
+
'User-Agent' => @http_env["HTTP_USER_AGENT"],
|
|
73
|
+
'X-Cloud-Client' => "WurflCloudClient/Ruby_#{WurflCloud::VERSION}",
|
|
74
|
+
'X-Forwarded-For' => @http_env["REMOTE_ADDR"],
|
|
75
|
+
'X-Accept' => @http_env["HTTP_ACCEPT"],
|
|
76
|
+
'X-Wap-Profile' => @http_env["HTTP_X_WAP_PROFILE"],
|
|
77
|
+
}
|
|
78
|
+
stub_request(:any, authenticated_uri).with(:headers=>headers).to_return(:status=>200, :body => @device_data)
|
|
79
|
+
WurflCloud::Client.detect_device(@environment, @cache)
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
{ "is_wireless_device"=>false,
|
|
83
|
+
"browser_id"=>"browser_root",
|
|
84
|
+
"fall_back"=>"root",
|
|
85
|
+
"user_agent"=>"",
|
|
86
|
+
"resolution_width"=>90
|
|
87
|
+
}.each do |key, value|
|
|
88
|
+
it "should return the right values for the capability #{key}" do
|
|
89
|
+
@wurfl_client[key].should ==value
|
|
90
|
+
end
|
|
91
|
+
it "should not call the webservice to read a capability that's present in the answer" do
|
|
92
|
+
value = @wurfl_client[key]
|
|
93
|
+
WebMock.should have_requested(:get, authenticated_uri).times(1)
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
context "when using with a simple local memory cache" do
|
|
100
|
+
|
|
101
|
+
before(:each) do
|
|
102
|
+
@http_env = {
|
|
103
|
+
"HTTP_USER_AGENT"=>String.random,
|
|
104
|
+
"HTTP_ACCEPT"=>String.random,
|
|
105
|
+
"HTTP_X_WAP_PROFILE"=>String.random,
|
|
106
|
+
"REMOTE_ADDR"=>String.random
|
|
107
|
+
}
|
|
108
|
+
@environment = WurflCloud::Environment.new(@http_env)
|
|
109
|
+
@cache = WurflCloud::Cache::LocalMemory.new
|
|
110
|
+
|
|
111
|
+
@device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
|
|
112
|
+
|
|
113
|
+
stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
|
|
114
|
+
@wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
it "should call the remote webservice once if the same agent is detected twice" do
|
|
119
|
+
WurflCloud::Client.detect_device(@environment, @cache)
|
|
120
|
+
WebMock.should have_requested(:get, authenticated_uri).times(1)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
context "requesting a non existent capability" do
|
|
124
|
+
context "just after the capabilities have been read from the server" do
|
|
125
|
+
it "should not call again the webservice" do
|
|
126
|
+
value = @wurfl_client['my_non_existent_capability']
|
|
127
|
+
WebMock.should have_requested(:get, authenticated_uri).times(1)
|
|
128
|
+
end
|
|
129
|
+
it "should return nil" do
|
|
130
|
+
@wurfl_client['my_non_existent_capability'].should be_nil
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
context "detecting the device from the cache" do
|
|
135
|
+
before(:each) do
|
|
136
|
+
@wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should call again the webservice" do
|
|
140
|
+
value = @wurfl_client['my_non_existent_capability']
|
|
141
|
+
WebMock.should have_requested(:get, authenticated_uri).times(2)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should return nil if it doesn't exist" do
|
|
145
|
+
@wurfl_client['my_non_existent_capability'].should be_nil
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
it "should return the right value if exists" do
|
|
149
|
+
stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"my_non_existent_capability":"OK"},"errors":{}}})
|
|
150
|
+
@wurfl_client['my_non_existent_capability'].should =="OK"
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "should call the webservice only once for each access to the capability value" do
|
|
154
|
+
stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"my_non_existent_capability":"OK"},"errors":{}}})
|
|
155
|
+
value = @wurfl_client['my_non_existent_capability']
|
|
156
|
+
value = @wurfl_client['my_non_existent_capability']
|
|
157
|
+
WebMock.should have_requested(:get, authenticated_uri).times(2)
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
context "when the webservice has errors" do
|
|
164
|
+
before(:each) do
|
|
165
|
+
@http_env = {
|
|
166
|
+
"HTTP_USER_AGENT"=>String.random,
|
|
167
|
+
"HTTP_ACCEPT"=>String.random,
|
|
168
|
+
"HTTP_X_WAP_PROFILE"=>String.random,
|
|
169
|
+
"REMOTE_ADDR"=>String.random
|
|
170
|
+
}
|
|
171
|
+
@environment = WurflCloud::Environment.new(@http_env)
|
|
172
|
+
@cache = WurflCloud.configuration.cache(nil)
|
|
173
|
+
|
|
174
|
+
@device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "should raise WurflCloud::Errors::ConnectionError if there are connection timeouts" do
|
|
178
|
+
stub_request(:any, authenticated_uri).to_timeout
|
|
179
|
+
|
|
180
|
+
expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
|
|
181
|
+
end
|
|
182
|
+
it "should raise WurflCloud::Errors::ConnectionError if there are connection errors" do
|
|
183
|
+
stub_request(:any, authenticated_uri).to_raise("some error")
|
|
184
|
+
|
|
185
|
+
expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
|
|
186
|
+
end
|
|
187
|
+
it "should raise WurflCloud::Errors::ConnectionError if there are server errors" do
|
|
188
|
+
stub_request(:any, authenticated_uri).to_return(:status=>500)
|
|
189
|
+
|
|
190
|
+
expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
|
|
191
|
+
end
|
|
192
|
+
it "should raise WurflCloud::Errors::MalformedResponseError if there are unparsable responses" do
|
|
193
|
+
stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{badjson})
|
|
194
|
+
|
|
195
|
+
expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::MalformedResponseError)
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
end
|