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    
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                            return true;
239                    }
240    
241                    return false;
242            }
243    
244            @Override
245            public boolean isMozilla(HttpServletRequest request) {
246                    String userAgent = getUserAgent(request);
247    
248                    if (userAgent.contains("mozilla") &&
249                            !(userAgent.contains("compatible") ||
250                              userAgent.contains("webkit"))) {
251    
252                            return true;
253                    }
254    
255                    return false;
256            }
257    
258            @Override
259            public boolean isOpera(HttpServletRequest request) {
260                    String userAgent = getUserAgent(request);
261    
262                    if (userAgent.contains("opera")) {
263                            return true;
264                    }
265    
266                    return false;
267            }
268    
269            @Override
270            public boolean isRtf(HttpServletRequest request) {
271                    if (isAndroid(request)) {
272                            return true;
273                    }
274    
275                    if (isChrome(request)) {
276                            return true;
277                    }
278    
279                    float majorVersion = getMajorVersion(request);
280    
281                    if (isIe(request) && (majorVersion >= 5.5)) {
282                            return true;
283                    }
284    
285                    if (isMozilla(request) && (majorVersion >= 1.3)) {
286                            return true;
287                    }
288    
289                    if (isOpera(request)) {
290                            if (isMobile(request) && (majorVersion >= 10.0)) {
291                                    return true;
292                            }
293                            else if (!isMobile(request)) {
294                                    return true;
295                            }
296                    }
297    
298                    if (isSafari(request)) {
299                            if (isMobile(request) && (majorVersion >= 5.0)) {
300                                    return true;
301                            }
302                            else if (!isMobile(request) && (majorVersion >= 3.0)) {
303                                    return true;
304                            }
305                    }
306    
307                    return false;
308            }
309    
310            @Override
311            public boolean isSafari(HttpServletRequest request) {
312                    String userAgent = getUserAgent(request);
313    
314                    if (isWebKit(request) && userAgent.contains("safari")) {
315                            return true;
316                    }
317    
318                    return false;
319            }
320    
321            @Override
322            public boolean isSun(HttpServletRequest request) {
323                    String userAgent = getUserAgent(request);
324    
325                    if (userAgent.contains("sunos")) {
326                            return true;
327                    }
328    
329                    return false;
330            }
331    
332            @Override
333            public boolean isWap(HttpServletRequest request) {
334                    return isWapXhtml(request);
335            }
336    
337            @Override
338            public boolean isWapXhtml(HttpServletRequest request) {
339                    String accept = getAccept(request);
340    
341                    if (accept.contains("wap.xhtml")) {
342                            return true;
343                    }
344    
345                    return false;
346            }
347    
348            @Override
349            public boolean isWebKit(HttpServletRequest request) {
350                    String userAgent = getUserAgent(request);
351    
352                    for (String webKitAlias : _WEBKIT_ALIASES) {
353                            if (userAgent.contains(webKitAlias)) {
354                                    return true;
355                            }
356                    }
357    
358                    return false;
359            }
360    
361            @Override
362            public boolean isWindows(HttpServletRequest request) {
363                    String userAgent = getUserAgent(request);
364    
365                    for (String windowsAlias : _WINDOWS_ALIASES) {
366                            if (userAgent.contains(windowsAlias)) {
367                                    return true;
368                            }
369                    }
370    
371                    return false;
372            }
373    
374            @Override
375            public boolean isWml(HttpServletRequest request) {
376                    String accept = getAccept(request);
377    
378                    if (accept.contains("wap.wml")) {
379                            return true;
380                    }
381    
382                    return false;
383            }
384    
385            protected static String parseVersion(
386                    String userAgent, String[] leadings, char[] separators) {
387    
388                    leading:
389                    for (String leading : leadings) {
390                            int index = 0;
391    
392                            version:
393                            while (true) {
394                                    index = userAgent.indexOf(leading, index);
395    
396                                    if ((index < 0) ||
397                                            (((index += leading.length()) + 2) > userAgent.length())) {
398    
399                                            continue leading;
400                                    }
401    
402                                    char c1 = userAgent.charAt(index);
403                                    char c2 = userAgent.charAt(++index);
404    
405                                    if (((c2 >= '0') && (c2 <= '9')) || (c2 == '.')) {
406                                            for (char separator : separators) {
407                                                    if (c1 == separator) {
408                                                            break version;
409                                                    }
410                                            }
411                                    }
412                            }
413    
414                            // Major
415    
416                            int majorStart = index;
417                            int majorEnd = index + 1;
418    
419                            for (int i = majorStart; i < userAgent.length(); i++) {
420                                    char c = userAgent.charAt(i);
421    
422                                    if ((c < '0') || (c > '9')) {
423                                            majorEnd = i;
424    
425                                            break;
426                                    }
427                            }
428    
429                            String major = userAgent.substring(majorStart, majorEnd);
430    
431                            if (userAgent.charAt(majorEnd) != '.') {
432                                    return major;
433                            }
434    
435                            // Minor
436    
437                            int minorStart = majorEnd + 1;
438                            int minorEnd = userAgent.length();
439    
440                            for (int i = minorStart; i < userAgent.length(); i++) {
441                                    char c = userAgent.charAt(i);
442    
443                                    if ((c < '0') || (c > '9')) {
444                                            minorEnd = i;
445    
446                                            break;
447                                    }
448                            }
449    
450                            String minor = userAgent.substring(minorStart, minorEnd);
451    
452                            return major.concat(StringPool.PERIOD).concat(minor);
453                    }
454    
455                    return StringPool.BLANK;
456            }
457    
458            protected String getAccept(HttpServletRequest request) {
459                    String accept = StringPool.BLANK;
460    
461                    if (request == null) {
462                            return accept;
463                    }
464    
465                    accept = String.valueOf(request.getAttribute(HttpHeaders.ACCEPT));
466    
467                    if (Validator.isNotNull(accept)) {
468                            return accept;
469                    }
470    
471                    accept = request.getHeader(HttpHeaders.ACCEPT);
472    
473                    if (accept != null) {
474                            accept = StringUtil.toLowerCase(accept);
475                    }
476                    else {
477                            accept = StringPool.BLANK;
478                    }
479    
480                    request.setAttribute(HttpHeaders.ACCEPT, accept);
481    
482                    return accept;
483            }
484    
485            protected String getUserAgent(HttpServletRequest request) {
486                    String userAgent = StringPool.BLANK;
487    
488                    if (request == null) {
489                            return userAgent;
490                    }
491    
492                    userAgent = String.valueOf(
493                            request.getAttribute(HttpHeaders.USER_AGENT));
494    
495                    if (Validator.isNotNull(userAgent)) {
496                            return userAgent;
497                    }
498    
499                    userAgent = request.getHeader(HttpHeaders.USER_AGENT);
500    
501                    if (userAgent != null) {
502                            userAgent = StringUtil.toLowerCase(userAgent);
503                    }
504                    else {
505                            userAgent = StringPool.BLANK;
506                    }
507    
508                    request.setAttribute(HttpHeaders.USER_AGENT, userAgent);
509    
510                    return userAgent;
511            }
512    
513            protected boolean isIe(String userAgent) {
514                    if (userAgent.contains("msie") && !userAgent.contains("opera")) {
515                            return true;
516                    }
517    
518                    return false;
519            }
520    
521            protected static String[] revisionLeadings = {"rv", "it", "ra", "ie"};
522            protected static char[] revisionSeparators =
523                    {CharPool.BACK_SLASH, CharPool.COLON, CharPool.SLASH, CharPool.SPACE};
524            protected static String[] versionLeadings =
525                    {"version", "firefox", "minefield", "chrome"};
526            protected static char[] versionSeparators =
527                    {CharPool.BACK_SLASH, CharPool.SLASH};
528    
529            private static final String[] _FIREFOX_ALIASES = {
530                    "firefox", "minefield", "granparadiso", "bonecho", "firebird",
531                    "phoenix", "camino"
532            };
533    
534            private static final String[] _WEBKIT_ALIASES = {"khtml", "applewebkit"};
535    
536            private static final String[] _WINDOWS_ALIASES = {
537                    "windows", "win32", "16bit"
538            };
539    
540    }