001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.servlet;
016    
017    import com.liferay.portal.kernel.security.pacl.DoPrivileged;
018    import com.liferay.portal.kernel.servlet.BrowserSniffer;
019    import com.liferay.portal.kernel.servlet.HttpHeaders;
020    import com.liferay.portal.kernel.util.CharPool;
021    import com.liferay.portal.kernel.util.GetterUtil;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.StringUtil;
024    import com.liferay.portal.kernel.util.Validator;
025    import com.liferay.portal.kernel.util.WebKeys;
026    
027    import javax.servlet.http.HttpServletRequest;
028    
029    /**
030     * See http://www.zytrax.com/tech/web/browser_ids.htm for examples.
031     *
032     * @author Eduardo Lundgren
033     * @author Nate Cavanaugh
034     */
035    @DoPrivileged
036    public class BrowserSnifferImpl implements BrowserSniffer {
037    
038            @Override
039            public boolean acceptsGzip(HttpServletRequest request) {
040                    String acceptEncoding = request.getHeader(HttpHeaders.ACCEPT_ENCODING);
041    
042                    if ((acceptEncoding != null) && acceptEncoding.contains("gzip")) {
043                            return true;
044                    }
045                    else {
046                            return false;
047                    }
048            }
049    
050            @Override
051            public String getBrowserId(HttpServletRequest request) {
052                    if (isIe(request)) {
053                            return BROWSER_ID_IE;
054                    }
055                    else if (isFirefox(request)) {
056                            return BROWSER_ID_FIREFOX;
057                    }
058                    else {
059                            return BROWSER_ID_OTHER;
060                    }
061            }
062    
063            @Override
064            public float getMajorVersion(HttpServletRequest request) {
065                    return GetterUtil.getFloat(getVersion(request));
066            }
067    
068            @Override
069            public String getRevision(HttpServletRequest request) {
070                    String revision = (String)request.getAttribute(
071                            WebKeys.BROWSER_SNIFFER_REVISION);
072    
073                    if (revision != null) {
074                            return revision;
075                    }
076    
077                    revision = parseVersion(
078                            getUserAgent(request), revisionLeadings, revisionSeparators);
079    
080                    request.setAttribute(WebKeys.BROWSER_SNIFFER_REVISION, revision);
081    
082                    return revision;
083            }
084    
085            @Override
086            public String getVersion(HttpServletRequest request) {
087                    String version = (String)request.getAttribute(
088                            WebKeys.BROWSER_SNIFFER_VERSION);
089    
090                    if (version != null) {
091                            return version;
092                    }
093    
094                    String userAgent = getUserAgent(request);
095    
096                    version = parseVersion(userAgent, versionLeadings, versionSeparators);
097    
098                    if (version.isEmpty()) {
099                            version = parseVersion(
100                                    userAgent, revisionLeadings, revisionSeparators);
101                    }
102    
103                    request.setAttribute(WebKeys.BROWSER_SNIFFER_VERSION, version);
104    
105                    return version;
106            }
107    
108            @Override
109            public boolean isAir(HttpServletRequest request) {
110                    String userAgent = getUserAgent(request);
111    
112                    if (userAgent.contains("adobeair")) {
113                            return true;
114                    }
115    
116                    return false;
117            }
118    
119            @Override
120            public boolean isAndroid(HttpServletRequest request) {
121                    String userAgent = getUserAgent(request);
122    
123                    if (userAgent.contains("android")) {
124                            return true;
125                    }
126    
127                    return false;
128            }
129    
130            @Override
131            public boolean isChrome(HttpServletRequest request) {
132                    String userAgent = getUserAgent(request);
133    
134                    if (userAgent.contains("chrome")) {
135                            return true;
136                    }
137    
138                    return false;
139            }
140    
141            @Override
142            public boolean isFirefox(HttpServletRequest request) {
143                    if (!isMozilla(request)) {
144                            return false;
145                    }
146    
147                    String userAgent = getUserAgent(request);
148    
149                    for (String firefoxAlias : _FIREFOX_ALIASES) {
150                            if (userAgent.contains(firefoxAlias)) {
151                                    return true;
152                            }
153                    }
154    
155                    return false;
156            }
157    
158            @Override
159            public boolean isGecko(HttpServletRequest request) {
160                    String userAgent = getUserAgent(request);
161    
162                    if (userAgent.contains("gecko")) {
163                            return true;
164                    }
165    
166                    return false;
167            }
168    
169            @Override
170            public boolean isIe(HttpServletRequest request) {
171                    return isIe(getUserAgent(request));
172            }
173    
174            @Override
175            public boolean isIeOnWin32(HttpServletRequest request) {
176                    String userAgent = getUserAgent(request);
177    
178                    if (isIe(userAgent) &&
179                            !(userAgent.contains("wow64") || userAgent.contains("win64"))) {
180    
181                            return true;
182                    }
183    
184                    return false;
185            }
186    
187            @Override
188            public boolean isIeOnWin64(HttpServletRequest request) {
189                    String userAgent = getUserAgent(request);
190    
191                    if (isIe(userAgent) &&
192                            (userAgent.contains("wow64") || userAgent.contains("win64"))) {
193    
194                            return true;
195                    }
196    
197                    return false;
198            }
199    
200            @Override
201            public boolean isIphone(HttpServletRequest request) {
202                    String userAgent = getUserAgent(request);
203    
204                    if (userAgent.contains("iphone")) {
205                            return true;
206                    }
207    
208                    return false;
209            }
210    
211            @Override
212            public boolean isLinux(HttpServletRequest request) {
213                    String userAgent = getUserAgent(request);
214    
215                    if (userAgent.contains("linux")) {
216                            return true;
217                    }
218    
219                    return false;
220            }
221    
222            @Override
223            public boolean isMac(HttpServletRequest request) {
224                    String userAgent = getUserAgent(request);
225    
226                    if (userAgent.contains("mac")) {
227                            return true;
228                    }
229    
230                    return false;
231            }
232    
233            @Override
234            public boolean isMobile(HttpServletRequest request) {
235                    String userAgent = getUserAgent(request);
236    
237                    if (userAgent.contains("mobile") ||
238                            (isAndroid(request) && userAgent.contains("nexus"))) {
239    
240                            return true;
241                    }
242    
243                    return false;
244            }
245    
246            @Override
247            public boolean isMozilla(HttpServletRequest request) {
248                    String userAgent = getUserAgent(request);
249    
250                    if (userAgent.contains("mozilla") &&
251                            !(userAgent.contains("compatible") ||
252                              userAgent.contains("webkit"))) {
253    
254                            return true;
255                    }
256    
257                    return false;
258            }
259    
260            @Override
261            public boolean isOpera(HttpServletRequest request) {
262                    String userAgent = getUserAgent(request);
263    
264                    if (userAgent.contains("opera")) {
265                            return true;
266                    }
267    
268                    return false;
269            }
270    
271            @Override
272            public boolean isRtf(HttpServletRequest request) {
273                    if (isAndroid(request)) {
274                            return true;
275                    }
276    
277                    if (isChrome(request)) {
278                            return true;
279                    }
280    
281                    float majorVersion = getMajorVersion(request);
282    
283                    if (isIe(request) && (majorVersion >= 5.5)) {
284                            return true;
285                    }
286    
287                    if (isMozilla(request) && (majorVersion >= 1.3)) {
288                            return true;
289                    }
290    
291                    if (isOpera(request)) {
292                            if (isMobile(request) && (majorVersion >= 10.0)) {
293                                    return true;
294                            }
295                            else if (!isMobile(request)) {
296                                    return true;
297                            }
298                    }
299    
300                    if (isSafari(request)) {
301                            if (isMobile(request) && (majorVersion >= 5.0)) {
302                                    return true;
303                            }
304                            else if (!isMobile(request) && (majorVersion >= 3.0)) {
305                                    return true;
306                            }
307                    }
308    
309                    return false;
310            }
311    
312            @Override
313            public boolean isSafari(HttpServletRequest request) {
314                    String userAgent = getUserAgent(request);
315    
316                    if (isWebKit(request) && userAgent.contains("safari")) {
317                            return true;
318                    }
319    
320                    return false;
321            }
322    
323            @Override
324            public boolean isSun(HttpServletRequest request) {
325                    String userAgent = getUserAgent(request);
326    
327                    if (userAgent.contains("sunos")) {
328                            return true;
329                    }
330    
331                    return false;
332            }
333    
334            @Override
335            public boolean isWap(HttpServletRequest request) {
336                    return isWapXhtml(request);
337            }
338    
339            @Override
340            public boolean isWapXhtml(HttpServletRequest request) {
341                    String accept = getAccept(request);
342    
343                    if (accept.contains("wap.xhtml")) {
344                            return true;
345                    }
346    
347                    return false;
348            }
349    
350            @Override
351            public boolean isWebKit(HttpServletRequest request) {
352                    String userAgent = getUserAgent(request);
353    
354                    for (String webKitAlias : _WEBKIT_ALIASES) {
355                            if (userAgent.contains(webKitAlias)) {
356                                    return true;
357                            }
358                    }
359    
360                    return false;
361            }
362    
363            @Override
364            public boolean isWindows(HttpServletRequest request) {
365                    String userAgent = getUserAgent(request);
366    
367                    for (String windowsAlias : _WINDOWS_ALIASES) {
368                            if (userAgent.contains(windowsAlias)) {
369                                    return true;
370                            }
371                    }
372    
373                    return false;
374            }
375    
376            @Override
377            public boolean isWml(HttpServletRequest request) {
378                    String accept = getAccept(request);
379    
380                    if (accept.contains("wap.wml")) {
381                            return true;
382                    }
383    
384                    return false;
385            }
386    
387            protected static String parseVersion(
388                    String userAgent, String[] leadings, char[] separators) {
389    
390                    leading:
391                    for (String leading : leadings) {
392                            int index = 0;
393    
394                            version:
395                            while (true) {
396                                    index = userAgent.indexOf(leading, index);
397    
398                                    if ((index < 0) ||
399                                            (((index += leading.length()) + 2) > userAgent.length())) {
400    
401                                            continue leading;
402                                    }
403    
404                                    char c1 = userAgent.charAt(index);
405                                    char c2 = userAgent.charAt(++index);
406    
407                                    if (((c2 >= '0') && (c2 <= '9')) || (c2 == '.')) {
408                                            for (char separator : separators) {
409                                                    if (c1 == separator) {
410                                                            break version;
411                                                    }
412                                            }
413                                    }
414                            }
415    
416                            // Major
417    
418                            int majorStart = index;
419                            int majorEnd = index + 1;
420    
421                            for (int i = majorStart; i < userAgent.length(); i++) {
422                                    char c = userAgent.charAt(i);
423    
424                                    if ((c < '0') || (c > '9')) {
425                                            majorEnd = i;
426    
427                                            break;
428                                    }
429                            }
430    
431                            String major = userAgent.substring(majorStart, majorEnd);
432    
433                            if (userAgent.charAt(majorEnd) != '.') {
434                                    return major;
435                            }
436    
437                            // Minor
438    
439                            int minorStart = majorEnd + 1;
440                            int minorEnd = userAgent.length();
441    
442                            for (int i = minorStart; i < userAgent.length(); i++) {
443                                    char c = userAgent.charAt(i);
444    
445                                    if ((c < '0') || (c > '9')) {
446                                            minorEnd = i;
447    
448                                            break;
449                                    }
450                            }
451    
452                            String minor = userAgent.substring(minorStart, minorEnd);
453    
454                            return major.concat(StringPool.PERIOD).concat(minor);
455                    }
456    
457                    return StringPool.BLANK;
458            }
459    
460            protected String getAccept(HttpServletRequest request) {
461                    String accept = StringPool.BLANK;
462    
463                    if (request == null) {
464                            return accept;
465                    }
466    
467                    accept = String.valueOf(request.getAttribute(HttpHeaders.ACCEPT));
468    
469                    if (Validator.isNotNull(accept)) {
470                            return accept;
471                    }
472    
473                    accept = request.getHeader(HttpHeaders.ACCEPT);
474    
475                    if (accept != null) {
476                            accept = StringUtil.toLowerCase(accept);
477                    }
478                    else {
479                            accept = StringPool.BLANK;
480                    }
481    
482                    request.setAttribute(HttpHeaders.ACCEPT, accept);
483    
484                    return accept;
485            }
486    
487            protected String getUserAgent(HttpServletRequest request) {
488                    String userAgent = StringPool.BLANK;
489    
490                    if (request == null) {
491                            return userAgent;
492                    }
493    
494                    userAgent = String.valueOf(
495                            request.getAttribute(HttpHeaders.USER_AGENT));
496    
497                    if (Validator.isNotNull(userAgent)) {
498                            return userAgent;
499                    }
500    
501                    userAgent = request.getHeader(HttpHeaders.USER_AGENT);
502    
503                    if (userAgent != null) {
504                            userAgent = StringUtil.toLowerCase(userAgent);
505                    }
506                    else {
507                            userAgent = StringPool.BLANK;
508                    }
509    
510                    request.setAttribute(HttpHeaders.USER_AGENT, userAgent);
511    
512                    return userAgent;
513            }
514    
515            protected boolean isIe(String userAgent) {
516                    if ((userAgent.contains("msie") || userAgent.contains("trident")) &&
517                            !userAgent.contains("opera")) {
518    
519                            return true;
520                    }
521    
522                    return false;
523            }
524    
525            protected static String[] revisionLeadings = {"rv", "it", "ra", "ie"};
526            protected static char[] revisionSeparators =
527                    {CharPool.BACK_SLASH, CharPool.COLON, CharPool.SLASH, CharPool.SPACE};
528            protected static String[] versionLeadings =
529                    {"version", "firefox", "minefield", "chrome"};
530            protected static char[] versionSeparators =
531                    {CharPool.BACK_SLASH, CharPool.SLASH};
532    
533            private static final String[] _FIREFOX_ALIASES = {
534                    "firefox", "minefield", "granparadiso", "bonecho", "firebird",
535                    "phoenix", "camino"
536            };
537    
538            private static final String[] _WEBKIT_ALIASES = {"khtml", "applewebkit"};
539    
540            private static final String[] _WINDOWS_ALIASES = {
541                    "windows", "win32", "16bit"
542            };
543    
544    }