browserx 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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +29 -0
- data/LICENSE.md +21 -0
- data/README.md +438 -0
- data/bot_exceptions.yml +5 -0
- data/bots.yml +327 -0
- data/languages.yml +113 -0
- data/lib/browser/accept_language.rb +55 -0
- data/lib/browser/action_controller.rb +20 -0
- data/lib/browser/aliases.rb +33 -0
- data/lib/browser/alipay.rb +21 -0
- data/lib/browser/base.rb +292 -0
- data/lib/browser/blackberry.rb +23 -0
- data/lib/browser/bot/empty_user_agent_matcher.rb +11 -0
- data/lib/browser/bot/keyword_matcher.rb +11 -0
- data/lib/browser/bot/known_bots_matcher.rb +11 -0
- data/lib/browser/bot.rb +119 -0
- data/lib/browser/browser.rb +116 -0
- data/lib/browser/chrome.rb +43 -0
- data/lib/browser/detect_version.rb +22 -0
- data/lib/browser/device/android.rb +20 -0
- data/lib/browser/device/base.rb +13 -0
- data/lib/browser/device/blackberry_playbook.rb +19 -0
- data/lib/browser/device/ipad.rb +19 -0
- data/lib/browser/device/iphone.rb +19 -0
- data/lib/browser/device/ipod_touch.rb +19 -0
- data/lib/browser/device/kindle.rb +19 -0
- data/lib/browser/device/kindle_fire.rb +19 -0
- data/lib/browser/device/playstation3.rb +19 -0
- data/lib/browser/device/playstation4.rb +19 -0
- data/lib/browser/device/psp.rb +19 -0
- data/lib/browser/device/psvita.rb +19 -0
- data/lib/browser/device/samsung.rb +33 -0
- data/lib/browser/device/surface.rb +23 -0
- data/lib/browser/device/switch.rb +19 -0
- data/lib/browser/device/tv.rb +19 -0
- data/lib/browser/device/unknown.rb +19 -0
- data/lib/browser/device/wii.rb +19 -0
- data/lib/browser/device/wiiu.rb +19 -0
- data/lib/browser/device/xbox_360.rb +19 -0
- data/lib/browser/device/xbox_one.rb +19 -0
- data/lib/browser/device.rb +222 -0
- data/lib/browser/duck_duck_go.rb +22 -0
- data/lib/browser/edge.rb +25 -0
- data/lib/browser/electron.rb +22 -0
- data/lib/browser/epiphany.rb +21 -0
- data/lib/browser/facebook.rb +23 -0
- data/lib/browser/firefox.rb +21 -0
- data/lib/browser/google_search_app.rb +21 -0
- data/lib/browser/huawei_browser.rb +21 -0
- data/lib/browser/instagram.rb +21 -0
- data/lib/browser/internet_explorer.rb +63 -0
- data/lib/browser/maxthon.rb +21 -0
- data/lib/browser/meta/base.rb +42 -0
- data/lib/browser/meta/device.rb +11 -0
- data/lib/browser/meta/generic_browser.rb +15 -0
- data/lib/browser/meta/id.rb +11 -0
- data/lib/browser/meta/ie.rb +20 -0
- data/lib/browser/meta/ios.rb +11 -0
- data/lib/browser/meta/mobile.rb +11 -0
- data/lib/browser/meta/platform.rb +11 -0
- data/lib/browser/meta/proxy.rb +11 -0
- data/lib/browser/meta/safari.rb +11 -0
- data/lib/browser/meta/tablet.rb +11 -0
- data/lib/browser/meta/webkit.rb +11 -0
- data/lib/browser/meta.rb +14 -0
- data/lib/browser/micro_messenger.rb +21 -0
- data/lib/browser/middleware/context/additions.rb +18 -0
- data/lib/browser/middleware/context/url_methods.rb +15 -0
- data/lib/browser/middleware/context.rb +22 -0
- data/lib/browser/middleware.rb +70 -0
- data/lib/browser/miui_browser.rb +21 -0
- data/lib/browser/nokia.rb +21 -0
- data/lib/browser/opera.rb +21 -0
- data/lib/browser/otter.rb +21 -0
- data/lib/browser/phantom_js.rb +21 -0
- data/lib/browser/platform/adobe_air.rb +23 -0
- data/lib/browser/platform/android.rb +23 -0
- data/lib/browser/platform/base.rb +18 -0
- data/lib/browser/platform/blackberry.rb +23 -0
- data/lib/browser/platform/chrome_os.rb +23 -0
- data/lib/browser/platform/firefox_os.rb +23 -0
- data/lib/browser/platform/ios.rb +36 -0
- data/lib/browser/platform/kai_os.rb +23 -0
- data/lib/browser/platform/linux.rb +23 -0
- data/lib/browser/platform/mac.rb +25 -0
- data/lib/browser/platform/unknown.rb +23 -0
- data/lib/browser/platform/windows.rb +23 -0
- data/lib/browser/platform/windows_mobile.rb +23 -0
- data/lib/browser/platform/windows_phone.rb +23 -0
- data/lib/browser/platform.rb +193 -0
- data/lib/browser/qq.rb +25 -0
- data/lib/browser/rails.rb +23 -0
- data/lib/browser/safari.rb +40 -0
- data/lib/browser/samsung_browser.rb +21 -0
- data/lib/browser/snapchat.rb +21 -0
- data/lib/browser/sougou_browser.rb +24 -0
- data/lib/browser/sputnik.rb +21 -0
- data/lib/browser/testing.rb +27 -0
- data/lib/browser/uc_browser.rb +21 -0
- data/lib/browser/unknown.rb +32 -0
- data/lib/browser/version.rb +5 -0
- data/lib/browser/weibo.rb +21 -0
- data/lib/browser/yandex.rb +21 -0
- data/lib/browser.rb +4 -0
- data/lib/browserx.rb +3 -0
- data/samsung.yml +138 -0
- data/search_engines.yml +7 -0
- data/test/ua.yml +181 -0
- data/test/ua_bots.yml +121 -0
- data/test/ua_search_engines.yml +7 -0
- metadata +267 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: b8b37f466da96715f58be6f7581204d5a46fe12ed3ea96995b46cbcc48a95e1f
|
|
4
|
+
data.tar.gz: ff7419bb6d7162a3abcf82dfac7e851dd50d55605dbea351eac97b11d819cacb
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: be7daa1b157872be556fe319352180b12f978f42aedf23e9e43eb880905e4d6d849cf7ea268281ca86cf56d3baf46707f4aafd785ab0c589a5fdef57d99e650f
|
|
7
|
+
data.tar.gz: 19d21da9ee4eb84763cb4609c2b160f9ac71f6656a783ec4d31d87c2558ee71a7d27e99f4e5437119998dcc2f13c2c00abb8ce478e8d8314b1012c76773cc1fd
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [Unreleased]
|
|
4
|
+
|
|
5
|
+
## [1.0.0] — 2026-11-04
|
|
6
|
+
|
|
7
|
+
First release as `browserx`, forked from browser 6.2.0 (`dd88933`). Same API: `gem "browserx"` replaces
|
|
8
|
+
`gem "browser"` without touching a call site. Earlier versions are browser's: see its
|
|
9
|
+
[changelog](https://github.com/fnando/browser/blob/main/CHANGELOG.md).
|
|
10
|
+
|
|
11
|
+
**Breaking**
|
|
12
|
+
- Requires Ruby 3.3 or later: 3.2 reached its end of life on 2026-03-31.
|
|
13
|
+
- Tested against Rails 8.0 and 8.1 only: 7.0, 7.1 and 7.2 reached their end of life.
|
|
14
|
+
|
|
15
|
+
**Faster**
|
|
16
|
+
- Bots are detected through one prefix-trie regexp instead of one match per entry, and without detecting the
|
|
17
|
+
browser twice; platform and device matchers are built lazily. A request takes 45% less time and half the
|
|
18
|
+
allocations.
|
|
19
|
+
|
|
20
|
+
**Fixed**
|
|
21
|
+
- The railtie loads Rails, not only itself, so it works without a preloaded ActiveSupport.
|
|
22
|
+
- `lib/browserx.rb` exists, so Bundler's auto-require loads the gem.
|
|
23
|
+
|
|
24
|
+
**New**
|
|
25
|
+
- A corpus of 20,328 user agents, with snapshot and diff scripts proving answers match upstream, and a
|
|
26
|
+
request benchmark.
|
|
27
|
+
|
|
28
|
+
[Unreleased]: https://github.com/next-gen-gems/browserx/compare/v1.0.0...HEAD
|
|
29
|
+
[1.0.0]: https://github.com/next-gen-gems/browserx/releases/tag/v1.0.0
|
data/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2010 Nando Vieira
|
|
4
|
+
Copyright (c) 2026 Level UP Solutions
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
7
|
+
this software and associated documentation files (the "Software"), to deal in
|
|
8
|
+
the Software without restriction, including without limitation the rights to
|
|
9
|
+
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
10
|
+
the Software, and to permit persons to whom the Software is furnished to do so,
|
|
11
|
+
subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in all
|
|
14
|
+
copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
18
|
+
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
19
|
+
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
20
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
21
|
+
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
# BrowserX
|
|
2
|
+
|
|
3
|
+
Browser detection for Ruby, with ActionController integration. BrowserX is a drop-in replacement for the
|
|
4
|
+
[browser](https://rubygems.org/gems/browser) gem: put `gem "browserx"` in your Gemfile instead of
|
|
5
|
+
`gem "browser"`, and every call site keeps working — same `Browser` namespace, same `require "browser"`, same
|
|
6
|
+
predicates. It answers nearly twice as fast (61 µs and 129 objects per request instead of 110 µs and 245 on
|
|
7
|
+
Ruby 4.0 with YJIT), and its bot list is meant to be kept fresh from permissively licensed sources
|
|
8
|
+
([crawler-user-agents](https://github.com/monperrus/crawler-user-agents),
|
|
9
|
+
[ai.robots.txt](https://github.com/ai-robots-txt/ai.robots.txt)).
|
|
10
|
+
|
|
11
|
+
Site: https://next-gen-gems.github.io/browserx/
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```ruby
|
|
16
|
+
gem "browserx"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
require "browser"
|
|
23
|
+
|
|
24
|
+
browser = Browser.new("Some User Agent", accept_language: "en-us")
|
|
25
|
+
|
|
26
|
+
# General info
|
|
27
|
+
browser.bot?
|
|
28
|
+
browser.chrome?
|
|
29
|
+
browser.chromium_based?
|
|
30
|
+
browser.core_media?
|
|
31
|
+
browser.duck_duck_go?
|
|
32
|
+
browser.edge? # Newest MS browser
|
|
33
|
+
browser.electron? # Electron Framework
|
|
34
|
+
browser.firefox?
|
|
35
|
+
browser.full_version
|
|
36
|
+
browser.ie?
|
|
37
|
+
browser.ie?(6) # detect specific IE version
|
|
38
|
+
browser.ie?([">8", "<10"]) # detect specific IE (IE9).
|
|
39
|
+
browser.known? # has the browser been successfully detected?
|
|
40
|
+
browser.unknown? # the browser wasn't detected.
|
|
41
|
+
browser.meta # an array with several attributes
|
|
42
|
+
browser.name # readable browser name
|
|
43
|
+
browser.nokia?
|
|
44
|
+
browser.opera?
|
|
45
|
+
browser.opera_mini?
|
|
46
|
+
browser.phantom_js?
|
|
47
|
+
browser.quicktime?
|
|
48
|
+
browser.safari?
|
|
49
|
+
browser.safari_webapp_mode?
|
|
50
|
+
browser.samsung_browser?
|
|
51
|
+
browser.to_s # the meta info joined by space
|
|
52
|
+
browser.uc_browser?
|
|
53
|
+
browser.version # major version number
|
|
54
|
+
browser.webkit?
|
|
55
|
+
browser.webkit_full_version
|
|
56
|
+
browser.yandex?
|
|
57
|
+
browser.wechat?
|
|
58
|
+
browser.qq?
|
|
59
|
+
browser.weibo?
|
|
60
|
+
browser.sputnik?
|
|
61
|
+
browser.sougou_browser?
|
|
62
|
+
browser.epiphany?
|
|
63
|
+
|
|
64
|
+
# Get bot info
|
|
65
|
+
browser.bot.name
|
|
66
|
+
browser.bot.search_engine?
|
|
67
|
+
browser.bot?
|
|
68
|
+
browser.bot.why? # shows which matcher detected this user agent as a bot.
|
|
69
|
+
Browser::Bot.why?(ua)
|
|
70
|
+
|
|
71
|
+
# Get device info
|
|
72
|
+
browser.device
|
|
73
|
+
browser.device.id
|
|
74
|
+
browser.device.name
|
|
75
|
+
browser.device.unknown?
|
|
76
|
+
browser.device.blackberry_playbook?
|
|
77
|
+
browser.device.console?
|
|
78
|
+
browser.device.ipad?
|
|
79
|
+
browser.device.iphone?
|
|
80
|
+
browser.device.ipod_touch?
|
|
81
|
+
browser.device.kindle?
|
|
82
|
+
browser.device.kindle_fire?
|
|
83
|
+
browser.device.mobile?
|
|
84
|
+
browser.device.nintendo?
|
|
85
|
+
browser.device.playstation?
|
|
86
|
+
browser.device.ps3?
|
|
87
|
+
browser.device.ps4?
|
|
88
|
+
browser.device.psp?
|
|
89
|
+
browser.device.silk?
|
|
90
|
+
browser.device.surface?
|
|
91
|
+
browser.device.tablet?
|
|
92
|
+
browser.device.tv?
|
|
93
|
+
browser.device.vita?
|
|
94
|
+
browser.device.wii?
|
|
95
|
+
browser.device.wiiu?
|
|
96
|
+
browser.device.samsung?
|
|
97
|
+
browser.device.switch?
|
|
98
|
+
browser.device.xbox?
|
|
99
|
+
browser.device.xbox_360?
|
|
100
|
+
browser.device.xbox_one?
|
|
101
|
+
|
|
102
|
+
# Get platform info
|
|
103
|
+
browser.platform
|
|
104
|
+
browser.platform.id
|
|
105
|
+
browser.platform.name
|
|
106
|
+
browser.platform.version # e.g. 9 (for iOS9)
|
|
107
|
+
browser.platform.adobe_air?
|
|
108
|
+
browser.platform.android?
|
|
109
|
+
browser.platform.android?(4.2) # detect Android Jelly Bean 4.2
|
|
110
|
+
browser.platform.android_app? # detect webview in an Android app
|
|
111
|
+
browser.platform.android_webview? # alias for android_app?
|
|
112
|
+
browser.platform.blackberry?
|
|
113
|
+
browser.platform.blackberry?(10) # detect specific BlackBerry version
|
|
114
|
+
browser.platform.chrome_os?
|
|
115
|
+
browser.platform.firefox_os?
|
|
116
|
+
browser.platform.ios? # detect iOS
|
|
117
|
+
browser.platform.ios?(9) # detect specific iOS version
|
|
118
|
+
browser.platform.ios_app? # detect webview in an iOS app
|
|
119
|
+
browser.platform.ios_webview? # alias for ios_app?
|
|
120
|
+
browser.platform.linux?
|
|
121
|
+
browser.platform.mac?
|
|
122
|
+
browser.platform.unknown?
|
|
123
|
+
browser.platform.windows10?
|
|
124
|
+
browser.platform.windows7?
|
|
125
|
+
browser.platform.windows8?
|
|
126
|
+
browser.platform.windows8_1?
|
|
127
|
+
browser.platform.windows?
|
|
128
|
+
browser.platform.windows_mobile?
|
|
129
|
+
browser.platform.windows_phone?
|
|
130
|
+
browser.platform.windows_rt?
|
|
131
|
+
browser.platform.windows_touchscreen_desktop?
|
|
132
|
+
browser.platform.windows_vista?
|
|
133
|
+
browser.platform.windows_wow64?
|
|
134
|
+
browser.platform.windows_x64?
|
|
135
|
+
browser.platform.windows_x64_inclusive?
|
|
136
|
+
browser.platform.windows_xp?
|
|
137
|
+
browser.platform.kai_os?
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Aliases
|
|
141
|
+
|
|
142
|
+
To add aliases like `mobile?` and `tablet?` to the base object (e.g
|
|
143
|
+
`browser.mobile?`), require the `browser/aliases` file and extend the
|
|
144
|
+
Browser::Base object like the following:
|
|
145
|
+
|
|
146
|
+
```ruby
|
|
147
|
+
require "browser/aliases"
|
|
148
|
+
Browser::Base.include(Browser::Aliases)
|
|
149
|
+
|
|
150
|
+
browser = Browser.new("Some user agent")
|
|
151
|
+
browser.mobile? #=> false
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
### What's being detected?
|
|
155
|
+
|
|
156
|
+
- For a list of platform detections, check
|
|
157
|
+
[lib/browser/platform.rb](lib/browser/platform.rb)
|
|
158
|
+
- For a list of device detections, check
|
|
159
|
+
[lib/browser/device.rb](lib/browser/device.rb)
|
|
160
|
+
- For a list of bot detections, check
|
|
161
|
+
[bots.yml](bots.yml)
|
|
162
|
+
|
|
163
|
+
### Detecting modern browsers
|
|
164
|
+
|
|
165
|
+
To detect whether a browser can be considered as modern or not, create a method
|
|
166
|
+
that abstracts your versioning constraints. The following example will consider
|
|
167
|
+
any of the following browsers as a modern:
|
|
168
|
+
|
|
169
|
+
```ruby
|
|
170
|
+
# Expects an Browser instance,
|
|
171
|
+
# like in `Browser.new(user_agent, accept_language: language)`.
|
|
172
|
+
def modern_browser?(browser)
|
|
173
|
+
[
|
|
174
|
+
browser.chrome?(">= 65"),
|
|
175
|
+
browser.safari?(">= 10"),
|
|
176
|
+
browser.firefox?(">= 52"),
|
|
177
|
+
browser.ie?(">= 11") && !browser.compatibility_view?,
|
|
178
|
+
browser.edge?(">= 15"),
|
|
179
|
+
browser.opera?(">= 50"),
|
|
180
|
+
browser.facebook?
|
|
181
|
+
&& browser.safari_webapp_mode?
|
|
182
|
+
&& browser.webkit_full_version.to_i >= 602
|
|
183
|
+
].any?
|
|
184
|
+
end
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Migrating from browser
|
|
188
|
+
|
|
189
|
+
Replace `gem "browser"` with `gem "browserx"` in the Gemfile, nothing else: `require "browser"`, the `Browser`
|
|
190
|
+
namespace and every predicate stay. To roll back, put `gem "browser"` back. BrowserX requires Ruby 3.3 or later
|
|
191
|
+
and is tested on Rails 8.0 and 8.1.
|
|
192
|
+
|
|
193
|
+
### Rails integration
|
|
194
|
+
|
|
195
|
+
Just add it to the Gemfile.
|
|
196
|
+
|
|
197
|
+
```ruby
|
|
198
|
+
gem "browserx"
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
This adds a helper method called `browser`, that inspects your current user
|
|
202
|
+
agent.
|
|
203
|
+
|
|
204
|
+
```erb
|
|
205
|
+
<% if browser.ie?(6) %>
|
|
206
|
+
<p class="disclaimer">You're running an older IE version. Please update it!</p>
|
|
207
|
+
<% end %>
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
If you want to use Browser on your Rails app but don't want to taint your
|
|
211
|
+
controller, use the following line on your Gemfile:
|
|
212
|
+
|
|
213
|
+
```ruby
|
|
214
|
+
gem "browserx", require: "browser/browser"
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### Accept Language
|
|
218
|
+
|
|
219
|
+
Parses the accept-language header from an HTTP request and produces an array of
|
|
220
|
+
language objects sorted by quality.
|
|
221
|
+
|
|
222
|
+
```ruby
|
|
223
|
+
browser = Browser.new("Some User Agent", accept_language: "en-us")
|
|
224
|
+
|
|
225
|
+
browser.accept_language.class
|
|
226
|
+
#=> Array
|
|
227
|
+
|
|
228
|
+
language = browser.accept_language.first
|
|
229
|
+
|
|
230
|
+
language.code
|
|
231
|
+
#=> "en"
|
|
232
|
+
|
|
233
|
+
language.region
|
|
234
|
+
#=> "US"
|
|
235
|
+
|
|
236
|
+
language.full
|
|
237
|
+
#=> "en-US"
|
|
238
|
+
|
|
239
|
+
language.quality
|
|
240
|
+
#=> 1.0
|
|
241
|
+
|
|
242
|
+
language.name
|
|
243
|
+
#=> "English/United States"
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Result is always sorted in quality order from highest to lowest. As per the HTTP
|
|
247
|
+
spec:
|
|
248
|
+
|
|
249
|
+
- omitting the quality value implies 1.0.
|
|
250
|
+
- quality value equal to zero means that is not accepted by the client.
|
|
251
|
+
|
|
252
|
+
### Internet Explorer
|
|
253
|
+
|
|
254
|
+
Internet Explorer has a compatibility view mode that allows newer versions
|
|
255
|
+
(IE8+) to run as an older version. Browser will always return the navigator
|
|
256
|
+
version, ignoring the compatibility view version, when defined. If you need to
|
|
257
|
+
get the engine's version, you have to use `Browser#msie_version` and
|
|
258
|
+
`Browser#msie_full_version`.
|
|
259
|
+
|
|
260
|
+
So, let's say an user activates compatibility view in a IE11 browser. This is
|
|
261
|
+
what you'll get:
|
|
262
|
+
|
|
263
|
+
```ruby
|
|
264
|
+
browser.version
|
|
265
|
+
#=> 11
|
|
266
|
+
|
|
267
|
+
browser.full_version
|
|
268
|
+
#=> 11.0
|
|
269
|
+
|
|
270
|
+
browser.msie_version
|
|
271
|
+
#=> 7
|
|
272
|
+
|
|
273
|
+
browser.msie_full_version
|
|
274
|
+
#=> 7.0
|
|
275
|
+
|
|
276
|
+
browser.compatibility_view?
|
|
277
|
+
#=> true
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
This behavior changed in browser v1.0.0; previously there wasn't a way of getting the
|
|
281
|
+
real browser version.
|
|
282
|
+
|
|
283
|
+
### Safari
|
|
284
|
+
|
|
285
|
+
iOS webviews and web apps aren't detected as Safari anymore, so be aware of that
|
|
286
|
+
if that's your case. You can use a combination of platform and webkit detection
|
|
287
|
+
to do whatever you want.
|
|
288
|
+
|
|
289
|
+
```ruby
|
|
290
|
+
# iPad's Safari running as web app mode.
|
|
291
|
+
browser = Browser.new("Mozilla/5.0 (iPad; U; CPU OS 3_2_1 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Mobile/7B405")
|
|
292
|
+
|
|
293
|
+
browser.safari?
|
|
294
|
+
#=> false
|
|
295
|
+
|
|
296
|
+
browser.webkit?
|
|
297
|
+
#=> true
|
|
298
|
+
|
|
299
|
+
browser.platform.ios?
|
|
300
|
+
#=> true
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Bots
|
|
304
|
+
|
|
305
|
+
The bot detection is quite aggressive. Anything that matches at least one of the
|
|
306
|
+
following requirements will be considered a bot.
|
|
307
|
+
|
|
308
|
+
- Empty user agent string
|
|
309
|
+
- User agent that matches `/crawl|fetch|search|monitoring|spider|bot/`
|
|
310
|
+
- Any known bot listed under
|
|
311
|
+
[bots.yml](bots.yml)
|
|
312
|
+
|
|
313
|
+
To add custom matchers, you can add a callable object to
|
|
314
|
+
`Browser::Bot.matchers`. The following example matches everything that has a
|
|
315
|
+
`externalhit` substring on it. The bot name will always be `General Bot`.
|
|
316
|
+
|
|
317
|
+
```ruby
|
|
318
|
+
Browser::Bot.matchers << ->(ua, _browser) { ua.match?(/externalhit/i) }
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
To clear all matchers, including the ones that are bundled, use
|
|
322
|
+
`Browser::Bot.matchers.clear`. You can re-add built-in matchers by doing the
|
|
323
|
+
following:
|
|
324
|
+
|
|
325
|
+
```ruby
|
|
326
|
+
Browser::Bot.matchers += Browser::Bot.default_matchers
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
To restore v2's bot detection, remove the following matchers:
|
|
330
|
+
|
|
331
|
+
```ruby
|
|
332
|
+
Browser::Bot.matchers.delete(Browser::Bot::KeywordMatcher)
|
|
333
|
+
Browser::Bot.matchers.delete(Browser::Bot::EmptyUserAgentMatcher)
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
To extend the bot list, you can manipulate the methods below:
|
|
337
|
+
|
|
338
|
+
```ruby
|
|
339
|
+
Browser::Bot.bots.merge!(new_bots_hash)
|
|
340
|
+
Browser::Bot.bot_exceptions += new_exceptions
|
|
341
|
+
Browser::Bot.search_engines.merge!(new_search_engines_hash)
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Middleware
|
|
345
|
+
|
|
346
|
+
You can use the `Browser::Middleware` to redirect user agents.
|
|
347
|
+
|
|
348
|
+
```ruby
|
|
349
|
+
use Browser::Middleware do
|
|
350
|
+
redirect_to "/upgrade" if browser.ie?
|
|
351
|
+
end
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
If you're using Rails, you can use the route helper methods. Just add something
|
|
355
|
+
like the following to a initializer file (`config/initializers/browser.rb`).
|
|
356
|
+
|
|
357
|
+
```ruby
|
|
358
|
+
Rails.configuration.middleware.use Browser::Middleware do
|
|
359
|
+
redirect_to upgrade_path if browser.ie?
|
|
360
|
+
end
|
|
361
|
+
```
|
|
362
|
+
|
|
363
|
+
If you need access to the `Rack::Request` object (e.g. to exclude a path), you
|
|
364
|
+
can do so with `request`.
|
|
365
|
+
|
|
366
|
+
```ruby
|
|
367
|
+
Rails.configuration.middleware.use Browser::Middleware do
|
|
368
|
+
redirect_to upgrade_path if browser.ie? && request.env["PATH_INFO"] != "/exclude_me"
|
|
369
|
+
end
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
### Restrictions
|
|
373
|
+
|
|
374
|
+
- User agent has a size limit of 2048 bytes. This can be customized through
|
|
375
|
+
`Browser.user_agent_size_limit=(size)`.
|
|
376
|
+
- Accept-Language has a size limit of 2048 bytes. This can be customized through
|
|
377
|
+
`Browser.accept_language_size_limit=(size)`.
|
|
378
|
+
|
|
379
|
+
If size is not respected, then `Browser::Error` is raised.
|
|
380
|
+
|
|
381
|
+
```ruby
|
|
382
|
+
Browser.user_agent_size_limit = 4096
|
|
383
|
+
Browser.accept_language_size_limit = 4096
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
## Performance
|
|
387
|
+
|
|
388
|
+
`bench/request.rb` replays what a web request asks (name, version, `bot?`, platform, device, accept-language) over
|
|
389
|
+
2,000 distinct user agents of the corpus and over 20 repeated ones, median of 7. On Ruby 4.0.9 with YJIT, browser
|
|
390
|
+
6.2.0 takes 110 µs and 245 objects per request, BrowserX 1.0.0 61 µs and 129 objects.
|
|
391
|
+
|
|
392
|
+
```bash
|
|
393
|
+
ruby --yjit -I path/to/upstream/lib bench/request.rb
|
|
394
|
+
ruby --yjit -I lib bench/request.rb
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
## Development
|
|
398
|
+
|
|
399
|
+
```bash
|
|
400
|
+
bundle install
|
|
401
|
+
bundle exec rake test
|
|
402
|
+
bundle exec rubocop
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
A change that is not meant to change an answer proves it on the corpus of 20,000 user agents, against a plain
|
|
406
|
+
clone of [fnando/browser](https://github.com/fnando/browser) at `dd88933`:
|
|
407
|
+
|
|
408
|
+
```bash
|
|
409
|
+
ruby -I path/to/upstream/lib script/corpus_snapshot.rb > /tmp/upstream.jsonl
|
|
410
|
+
ruby -I lib script/corpus_snapshot.rb > /tmp/browserx.jsonl
|
|
411
|
+
ruby script/corpus_diff.rb /tmp/upstream.jsonl /tmp/browserx.jsonl
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
To add a bot, add its user agent to `test/ua_bots.yml` and its readable name to `bots.yml`, keyed by a
|
|
415
|
+
lowercased string the user agent contains. A search engine goes in `test/ua_search_engines.yml`,
|
|
416
|
+
`test/ua_bots.yml` and `search_engines.yml`.
|
|
417
|
+
|
|
418
|
+
### Releasing
|
|
419
|
+
|
|
420
|
+
Changes go under `## [Unreleased]` in `CHANGELOG.md` as they land. To release them, from an up-to-date `main`
|
|
421
|
+
whose CI is green:
|
|
422
|
+
|
|
423
|
+
```sh
|
|
424
|
+
bin/release minor --dry-run # the notes and the changes, nothing written
|
|
425
|
+
bin/release minor # or patch, major, or an exact version such as 1.2.0
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
`bin/release` dates the Unreleased section, bumps the version, commits, and pushes the commit with a signed tag
|
|
429
|
+
`vX.Y.Z`. The tag starts the Release workflow, which publishes the gem to RubyGems through trusted publishing and
|
|
430
|
+
creates the GitHub release with the version's notes and the `.gem`.
|
|
431
|
+
|
|
432
|
+
## License
|
|
433
|
+
|
|
434
|
+
MIT, by Level UP Solutions, see [LICENSE.md](LICENSE.md). Originally written by Nando Vieira as
|
|
435
|
+
[fnando/browser](https://github.com/fnando/browser) (MIT). The corpus gathers user agents from
|
|
436
|
+
[ua-parser/uap-core](https://github.com/ua-parser/uap-core) (Apache 2.0),
|
|
437
|
+
[crawler-user-agents](https://github.com/monperrus/crawler-user-agents) (MIT) and browser's test fixtures: see
|
|
438
|
+
[corpus/SOURCES.md](corpus/SOURCES.md).
|