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 isChrome(HttpServletRequest request) {
121                    String userAgent = getUserAgent(request);
122    
123                    if (userAgent.contains("chrome")) {
124                            return true;
125                    }
126    
127                    return false;
128            }
129    
130            @Override
131            public boolean isFirefox(HttpServletRequest request) {
132                    if (!isMozilla(request)) {
133                            return false;
134                    }
135    
136                    String userAgent = getUserAgent(request);
137    
138                    for (String firefoxAlias : _FIREFOX_ALIASES) {
139                            if (userAgent.contains(firefoxAlias)) {
140                                    return true;
141                            }
142                    }
143    
144                    return false;
145            }
146    
147            @Override
148            public boolean isGecko(HttpServletRequest request) {
149                    String userAgent = getUserAgent(request);
150    
151                    if (userAgent.contains("gecko")) {
152                            return true;
153                    }
154    
155                    return false;
156            }
157    
158            @Override
159            public boolean isIe(HttpServletRequest request) {
160                    return isIe(getUserAgent(request));
161            }
162    
163            @Override
164            public boolean isIeOnWin32(HttpServletRequest request) {
165                    String userAgent = getUserAgent(request);
166    
167                    if (isIe(userAgent) &&
168                            !(userAgent.contains("wow64") || userAgent.contains("win64"))) {
169    
170                            return true;
171                    }
172    
173                    return false;
174            }
175    
176            @Override
177            public boolean isIeOnWin64(HttpServletRequest request) {
178                    String userAgent = getUserAgent(request);
179    
180                    if (isIe(userAgent) &&
181                            (userAgent.contains("wow64") || userAgent.contains("win64"))) {
182    
183                            return true;
184                    }
185    
186                    return false;
187            }
188    
189            @Override
190            public boolean isIphone(HttpServletRequest request) {
191                    String userAgent = getUserAgent(request);
192    
193                    if (userAgent.contains("iphone")) {
194                            return true;
195                    }
196    
197                    return false;
198            }
199    
200            @Override
201            public boolean isLinux(HttpServletRequest request) {
202                    String userAgent = getUserAgent(request);
203    
204                    if (userAgent.contains("linux")) {
205                            return true;
206                    }
207    
208                    return false;
209            }
210    
211            @Override
212            public boolean isMac(HttpServletRequest request) {
213                    String userAgent = getUserAgent(request);
214    
215                    if (userAgent.contains("mac")) {
216                            return true;
217                    }
218    
219                    return false;
220            }
221    
222            @Override
223            public boolean isMobile(HttpServletRequest request) {
224                    String userAgent = getUserAgent(request);
225    
226                    if (userAgent.contains("mobile")) {
227                            return true;
228                    }
229    
230                    return false;
231            }
232    
233            @Override
234            public boolean isMozilla(HttpServletRequest request) {
235                    String userAgent = getUserAgent(request);
236    
237                    if (userAgent.contains("mozilla") &&
238                            !(userAgent.contains("compatible") ||
239                              userAgent.contains("webkit"))) {
240    
241                            return true;
242                    }
243    
244                    return false;
245            }
246    
247            @Override
248            public boolean isOpera(HttpServletRequest request) {
249                    String userAgent = getUserAgent(request);
250    
251                    if (userAgent.contains("opera")) {
252                            return true;
253                    }
254    
255                    return false;
256            }
257    
258            @Override
259            public boolean isRtf(HttpServletRequest request) {
260                    float majorVersion = getMajorVersion(request);
261    
262                    if (isChrome(request)) {
263                            return true;
264                    }
265    
266                    if (isIe(request) && (majorVersion >= 5.5)) {
267                            return true;
268                    }
269    
270                    if (isMozilla(request) && (majorVersion >= 1.3)) {
271                            return true;
272                    }
273    
274                    if (isOpera(request)) {
275                            if (isMobile(request) && (majorVersion >= 10.0)) {
276                                    return true;
277                            }
278                            else if (!isMobile(request)) {
279                                    return true;
280                            }
281                    }
282    
283                    if (isSafari(request)) {
284                            if (isMobile(request) && (majorVersion >= 5.0)) {
285                                    return true;
286                            }
287                            else if (!isMobile(request) && (majorVersion >= 3.0)) {
288                                    return true;
289                            }
290                    }
291    
292                    return false;
293            }
294    
295            @Override
296            public boolean isSafari(HttpServletRequest request) {
297                    String userAgent = getUserAgent(request);
298    
299                    if (isWebKit(request) && userAgent.contains("safari")) {
300                            return true;
301                    }
302    
303                    return false;
304            }
305    
306            @Override
307            public boolean isSun(HttpServletRequest request) {
308                    String userAgent = getUserAgent(request);
309    
310                    if (userAgent.contains("sunos")) {
311                            return true;
312                    }
313    
314                    return false;
315            }
316    
317            @Override
318            public boolean isWap(HttpServletRequest request) {
319                    return isWapXhtml(request);
320            }
321    
322            @Override
323            public boolean isWapXhtml(HttpServletRequest request) {
324                    String accept = getAccept(request);
325    
326                    if (accept.contains("wap.xhtml")) {
327                            return true;
328                    }
329    
330                    return false;
331            }
332    
333            @Override
334            public boolean isWebKit(HttpServletRequest request) {
335                    String userAgent = getUserAgent(request);
336    
337                    for (String webKitAlias : _WEBKIT_ALIASES) {
338                            if (userAgent.contains(webKitAlias)) {
339                                    return true;
340                            }
341                    }
342    
343                    return false;
344            }
345    
346            @Override
347            public boolean isWindows(HttpServletRequest request) {
348                    String userAgent = getUserAgent(request);
349    
350                    for (String windowsAlias : _WINDOWS_ALIASES) {
351                            if (userAgent.contains(windowsAlias)) {
352                                    return true;
353                            }
354                    }
355    
356                    return false;
357            }
358    
359            @Override
360            public boolean isWml(HttpServletRequest request) {
361                    String accept = getAccept(request);
362    
363                    if (accept.contains("wap.wml")) {
364                            return true;
365                    }
366    
367                    return false;
368            }
369    
370            protected static String parseVersion(
371                    String userAgent, String[] leadings, char[] separators) {
372    
373                    leading:
374                    for (String leading : leadings) {
375                            int index = 0;
376    
377                            version:
378                            while (true) {
379                                    index = userAgent.indexOf(leading, index);
380    
381                                    if ((index < 0) ||
382                                            (((index += leading.length()) + 2) > userAgent.length())) {
383    
384                                            continue leading;
385                                    }
386    
387                                    char c1 = userAgent.charAt(index);
388                                    char c2 = userAgent.charAt(++index);
389    
390                                    if (((c2 >= '0') && (c2 <= '9')) || (c2 == '.')) {
391                                            for (char separator : separators) {
392                                                    if (c1 == separator) {
393                                                            break version;
394                                                    }
395                                            }
396                                    }
397                            }
398    
399                            // Major
400    
401                            int majorStart = index;
402                            int majorEnd = index + 1;
403    
404                            for (int i = majorStart; i < userAgent.length(); i++) {
405                                    char c = userAgent.charAt(i);
406    
407                                    if ((c < '0') || (c > '9')) {
408                                            majorEnd = i;
409    
410                                            break;
411                                    }
412                            }
413    
414                            String major = userAgent.substring(majorStart, majorEnd);
415    
416                            if (userAgent.charAt(majorEnd) != '.') {
417                                    return major;
418                            }
419    
420                            // Minor
421    
422                            int minorStart = majorEnd + 1;
423                            int minorEnd = userAgent.length();
424    
425                            for (int i = minorStart; i < userAgent.length(); i++) {
426                                    char c = userAgent.charAt(i);
427    
428                                    if ((c < '0') || (c > '9')) {
429                                            minorEnd = i;
430    
431                                            break;
432                                    }
433                            }
434    
435                            String minor = userAgent.substring(minorStart, minorEnd);
436    
437                            return major.concat(StringPool.PERIOD).concat(minor);
438                    }
439    
440                    return StringPool.BLANK;
441            }
442    
443            protected String getAccept(HttpServletRequest request) {
444                    String accept = StringPool.BLANK;
445    
446                    if (request == null) {
447                            return accept;
448                    }
449    
450                    accept = String.valueOf(request.getAttribute(HttpHeaders.ACCEPT));
451    
452                    if (Validator.isNotNull(accept)) {
453                            return accept;
454                    }
455    
456                    accept = request.getHeader(HttpHeaders.ACCEPT);
457    
458                    if (accept != null) {
459                            accept = StringUtil.toLowerCase(accept);
460                    }
461                    else {
462                            accept = StringPool.BLANK;
463                    }
464    
465                    request.setAttribute(HttpHeaders.ACCEPT, accept);
466    
467                    return accept;
468            }
469    
470            protected String getUserAgent(HttpServletRequest request) {
471                    String userAgent = StringPool.BLANK;
472    
473                    if (request == null) {
474                            return userAgent;
475                    }
476    
477                    userAgent = String.valueOf(
478                            request.getAttribute(HttpHeaders.USER_AGENT));
479    
480                    if (Validator.isNotNull(userAgent)) {
481                            return userAgent;
482                    }
483    
484                    userAgent = request.getHeader(HttpHeaders.USER_AGENT);
485    
486                    if (userAgent != null) {
487                            userAgent = StringUtil.toLowerCase(userAgent);
488                    }
489                    else {
490                            userAgent = StringPool.BLANK;
491                    }
492    
493                    request.setAttribute(HttpHeaders.USER_AGENT, userAgent);
494    
495                    return userAgent;
496            }
497    
498            protected boolean isIe(String userAgent) {
499                    if (userAgent.contains("msie") && !userAgent.contains("opera")) {
500                            return true;
501                    }
502    
503                    return false;
504            }
505    
506            protected static String[] revisionLeadings = {"rv", "it", "ra", "ie"};
507            protected static char[] revisionSeparators =
508                    {CharPool.BACK_SLASH, CharPool.COLON, CharPool.SLASH, CharPool.SPACE};
509            protected static String[] versionLeadings =
510                    {"version", "firefox", "minefield", "chrome"};
511            protected static char[] versionSeparators =
512                    {CharPool.BACK_SLASH, CharPool.SLASH};
513    
514            private static final String[] _FIREFOX_ALIASES = {
515                    "firefox", "minefield", "granparadiso", "bonecho", "firebird",
516                    "phoenix", "camino"
517            };
518    
519            private static final String[] _WEBKIT_ALIASES = {"khtml", "applewebkit"};
520    
521            private static final String[] _WINDOWS_ALIASES = {
522                    "windows", "win32", "16bit"
523            };
524    
525    }