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