PageRenderTime 140ms CodeModel.GetById 34ms app.highlight 81ms RepoModel.GetById 15ms app.codeStats 0ms

/indra/llprimitive/llmediaentry.cpp

https://bitbucket.org/lindenlab/viewer-beta/
C++ | 596 lines | 467 code | 47 blank | 82 comment | 81 complexity | bd7cbfdb06edb77da17383ac0513fa20 MD5 | raw file
  1/** 
  2 * @file llmediaentry.cpp
  3 * @brief This is a single instance of media data related to the face of a prim
  4 *
  5 * $LicenseInfo:firstyear=2001&license=viewerlgpl$
  6 * Second Life Viewer Source Code
  7 * Copyright (C) 2010, Linden Research, Inc.
  8 * 
  9 * This library is free software; you can redistribute it and/or
 10 * modify it under the terms of the GNU Lesser General Public
 11 * License as published by the Free Software Foundation;
 12 * version 2.1 of the License only.
 13 * 
 14 * This library is distributed in the hope that it will be useful,
 15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 17 * Lesser General Public License for more details.
 18 * 
 19 * You should have received a copy of the GNU Lesser General Public
 20 * License along with this library; if not, write to the Free Software
 21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 22 * 
 23 * Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA
 24 * $/LicenseInfo$
 25 */
 26
 27#include "linden_common.h"
 28#include "llmediaentry.h"
 29#include "lllslconstants.h"
 30
 31#include <boost/regex.hpp>
 32
 33// LLSD key defines
 34// DO NOT REORDER OR REMOVE THESE!
 35
 36// Some LLSD keys.  Do not change!
 37#define MEDIA_ALT_IMAGE_ENABLE_KEY_STR   "alt_image_enable"
 38#define MEDIA_CONTROLS_KEY_STR           "controls"
 39#define MEDIA_CURRENT_URL_KEY_STR        "current_url"
 40#define MEDIA_HOME_URL_KEY_STR           "home_url"
 41#define MEDIA_AUTO_LOOP_KEY_STR          "auto_loop"
 42#define MEDIA_AUTO_PLAY_KEY_STR          "auto_play"
 43#define MEDIA_AUTO_SCALE_KEY_STR         "auto_scale"
 44#define MEDIA_AUTO_ZOOM_KEY_STR          "auto_zoom"
 45#define MEDIA_FIRST_CLICK_INTERACT_KEY_STR  "first_click_interact"
 46#define MEDIA_WIDTH_PIXELS_KEY_STR       "width_pixels"
 47#define MEDIA_HEIGHT_PIXELS_KEY_STR      "height_pixels"
 48
 49// "security" fields
 50#define MEDIA_WHITELIST_ENABLE_KEY_STR   "whitelist_enable"
 51#define MEDIA_WHITELIST_KEY_STR          "whitelist"
 52
 53// "permissions" fields
 54#define MEDIA_PERMS_INTERACT_KEY_STR     "perms_interact"
 55#define MEDIA_PERMS_CONTROL_KEY_STR      "perms_control"
 56
 57// "general" fields
 58const char* LLMediaEntry::ALT_IMAGE_ENABLE_KEY  = MEDIA_ALT_IMAGE_ENABLE_KEY_STR;
 59const char* LLMediaEntry::CONTROLS_KEY          = MEDIA_CONTROLS_KEY_STR;
 60const char* LLMediaEntry::CURRENT_URL_KEY       = MEDIA_CURRENT_URL_KEY_STR;
 61const char* LLMediaEntry::HOME_URL_KEY          = MEDIA_HOME_URL_KEY_STR;
 62const char* LLMediaEntry::AUTO_LOOP_KEY         = MEDIA_AUTO_LOOP_KEY_STR;
 63const char* LLMediaEntry::AUTO_PLAY_KEY         = MEDIA_AUTO_PLAY_KEY_STR;
 64const char* LLMediaEntry::AUTO_SCALE_KEY        = MEDIA_AUTO_SCALE_KEY_STR;
 65const char* LLMediaEntry::AUTO_ZOOM_KEY         = MEDIA_AUTO_ZOOM_KEY_STR;
 66const char* LLMediaEntry::FIRST_CLICK_INTERACT_KEY = MEDIA_FIRST_CLICK_INTERACT_KEY_STR;
 67const char* LLMediaEntry::WIDTH_PIXELS_KEY      = MEDIA_WIDTH_PIXELS_KEY_STR;
 68const char* LLMediaEntry::HEIGHT_PIXELS_KEY     = MEDIA_HEIGHT_PIXELS_KEY_STR;
 69
 70// "security" fields
 71const char* LLMediaEntry::WHITELIST_ENABLE_KEY  = MEDIA_WHITELIST_ENABLE_KEY_STR;
 72const char* LLMediaEntry::WHITELIST_KEY         = MEDIA_WHITELIST_KEY_STR;
 73
 74// "permissions" fields
 75const char* LLMediaEntry::PERMS_INTERACT_KEY    = MEDIA_PERMS_INTERACT_KEY_STR;
 76const char* LLMediaEntry::PERMS_CONTROL_KEY     = MEDIA_PERMS_CONTROL_KEY_STR;
 77
 78#define DEFAULT_URL_PREFIX  "http://"
 79
 80// Constructor(s)
 81LLMediaEntry::LLMediaEntry() :
 82    mAltImageEnable(false),
 83    mControls(STANDARD),
 84    mCurrentURL(""),
 85    mHomeURL(""),
 86    mAutoLoop(false),
 87    mAutoPlay(false),
 88    mAutoScale(false),
 89    mAutoZoom(false),
 90    mFirstClickInteract(false),
 91    mWidthPixels(0),
 92    mHeightPixels(0),
 93    mWhiteListEnable(false),
 94    // mWhiteList
 95    mPermsInteract(PERM_ALL),
 96    mPermsControl(PERM_ALL),
 97    mMediaIDp(NULL)
 98{
 99}
100
101LLMediaEntry::LLMediaEntry(const LLMediaEntry &rhs) :
102    mMediaIDp(NULL)
103{
104    // "general" fields
105    mAltImageEnable = rhs.mAltImageEnable;
106    mControls = rhs.mControls;
107    mCurrentURL = rhs.mCurrentURL;
108    mHomeURL = rhs.mHomeURL;
109    mAutoLoop = rhs.mAutoLoop;
110    mAutoPlay = rhs.mAutoPlay;
111    mAutoScale = rhs.mAutoScale;
112    mAutoZoom = rhs.mAutoZoom;
113    mFirstClickInteract = rhs.mFirstClickInteract;
114    mWidthPixels = rhs.mWidthPixels;
115    mHeightPixels = rhs.mHeightPixels;
116
117    // "security" fields
118    mWhiteListEnable = rhs.mWhiteListEnable;
119    mWhiteList = rhs.mWhiteList;
120
121    // "permissions" fields
122    mPermsInteract = rhs.mPermsInteract;
123    mPermsControl = rhs.mPermsControl;
124}
125
126LLMediaEntry::~LLMediaEntry()
127{
128    if (NULL != mMediaIDp)
129    {
130        delete mMediaIDp;
131    }
132}
133
134LLSD LLMediaEntry::asLLSD() const
135{
136    LLSD sd;
137    asLLSD(sd);
138    return sd;
139}
140
141//
142// LLSD functions
143//
144void LLMediaEntry::asLLSD(LLSD& sd) const
145{
146    // "general" fields
147    sd[ALT_IMAGE_ENABLE_KEY] = mAltImageEnable;
148    sd[CONTROLS_KEY] = (LLSD::Integer)mControls;
149    sd[CURRENT_URL_KEY] = mCurrentURL;
150    sd[HOME_URL_KEY] = mHomeURL;
151    sd[AUTO_LOOP_KEY] = mAutoLoop;
152    sd[AUTO_PLAY_KEY] = mAutoPlay;
153    sd[AUTO_SCALE_KEY] = mAutoScale;
154    sd[AUTO_ZOOM_KEY] = mAutoZoom;
155    sd[FIRST_CLICK_INTERACT_KEY] = mFirstClickInteract;
156    sd[WIDTH_PIXELS_KEY] = mWidthPixels;
157    sd[HEIGHT_PIXELS_KEY] = mHeightPixels;
158
159    // "security" fields
160    sd[WHITELIST_ENABLE_KEY] = mWhiteListEnable;
161	sd.erase(WHITELIST_KEY);
162    for (U32 i=0; i<mWhiteList.size(); i++) 
163	{
164        sd[WHITELIST_KEY].append(mWhiteList[i]);
165    }
166
167    // "permissions" fields
168    sd[PERMS_INTERACT_KEY] = mPermsInteract;
169    sd[PERMS_CONTROL_KEY] = mPermsControl;
170}
171
172// static
173bool LLMediaEntry::checkLLSD(const LLSD& sd)
174{
175    if (sd.isUndefined()) return true;
176    LLMediaEntry temp;
177    return temp.fromLLSDInternal(sd, true);
178}
179
180void LLMediaEntry::fromLLSD(const LLSD& sd)
181{
182    (void)fromLLSDInternal(sd, true);
183}
184
185void LLMediaEntry::mergeFromLLSD(const LLSD& sd)
186{
187    (void)fromLLSDInternal(sd, false);
188}
189
190// *NOTE: returns true if NO failures to set occurred, false otherwise.
191//        However, be aware that if a failure to set does occur, it does
192//        not stop setting fields from the LLSD!
193bool LLMediaEntry::fromLLSDInternal(const LLSD& sd, bool overwrite)
194{
195    // *HACK: we sort of cheat here and assume that status is a
196    // bit field.  We "or" into status and instead of returning
197    // it, we return whether it finishes off as LSL_STATUS_OK or not.
198    U32 status = LSL_STATUS_OK;
199    
200    // "general" fields
201    if ( overwrite || sd.has(ALT_IMAGE_ENABLE_KEY) )
202    {
203        status |= setAltImageEnable( sd[ALT_IMAGE_ENABLE_KEY] );
204    }
205    if ( overwrite || sd.has(CONTROLS_KEY) )
206    {
207        status |= setControls( (MediaControls)(LLSD::Integer)sd[CONTROLS_KEY] );
208    }
209    if ( overwrite || sd.has(CURRENT_URL_KEY) )
210    {
211        // Don't check whitelist
212        status |= setCurrentURLInternal( sd[CURRENT_URL_KEY], false );
213    }
214    if ( overwrite || sd.has(HOME_URL_KEY) )
215    {
216        status |= setHomeURL( sd[HOME_URL_KEY] );
217    }
218    if ( overwrite || sd.has(AUTO_LOOP_KEY) )
219    {
220        status |= setAutoLoop( sd[AUTO_LOOP_KEY] );
221    }
222    if ( overwrite || sd.has(AUTO_PLAY_KEY) )
223    {
224        status |= setAutoPlay( sd[AUTO_PLAY_KEY] );
225    }
226    if ( overwrite || sd.has(AUTO_SCALE_KEY) )
227    {
228        status |= setAutoScale( sd[AUTO_SCALE_KEY] );
229    }
230    if ( overwrite || sd.has(AUTO_ZOOM_KEY) )
231    {
232        status |= setAutoZoom( sd[AUTO_ZOOM_KEY] );
233    }
234    if ( overwrite || sd.has(FIRST_CLICK_INTERACT_KEY) )
235    {
236        status |= setFirstClickInteract( sd[FIRST_CLICK_INTERACT_KEY] );
237    }
238    if ( overwrite || sd.has(WIDTH_PIXELS_KEY) )
239    {
240        status |= setWidthPixels( (LLSD::Integer)sd[WIDTH_PIXELS_KEY] );
241    }
242    if ( overwrite || sd.has(HEIGHT_PIXELS_KEY) )
243    {
244        status |= setHeightPixels( (LLSD::Integer)sd[HEIGHT_PIXELS_KEY] );
245    }
246
247    // "security" fields
248    if ( overwrite || sd.has(WHITELIST_ENABLE_KEY) )
249    {
250        status |= setWhiteListEnable( sd[WHITELIST_ENABLE_KEY] );
251    }
252    if ( overwrite || sd.has(WHITELIST_KEY) )
253    {
254        status |= setWhiteList( sd[WHITELIST_KEY] );
255    }
256
257    // "permissions" fields
258    if ( overwrite || sd.has(PERMS_INTERACT_KEY) )
259    {
260        status |= setPermsInteract( 0xff & (LLSD::Integer)sd[PERMS_INTERACT_KEY] );
261    }
262    if ( overwrite || sd.has(PERMS_CONTROL_KEY) )
263    {
264        status |= setPermsControl( 0xff & (LLSD::Integer)sd[PERMS_CONTROL_KEY] );
265    }
266    
267    return LSL_STATUS_OK == status;
268}
269
270LLMediaEntry& LLMediaEntry::operator=(const LLMediaEntry &rhs)
271{
272    if (this != &rhs)
273    {
274        // "general" fields
275        mAltImageEnable = rhs.mAltImageEnable;
276        mControls = rhs.mControls;
277        mCurrentURL = rhs.mCurrentURL;
278        mHomeURL = rhs.mHomeURL;
279        mAutoLoop = rhs.mAutoLoop;
280        mAutoPlay = rhs.mAutoPlay;
281        mAutoScale = rhs.mAutoScale;
282        mAutoZoom = rhs.mAutoZoom;
283        mFirstClickInteract = rhs.mFirstClickInteract;
284        mWidthPixels = rhs.mWidthPixels;
285        mHeightPixels = rhs.mHeightPixels;
286
287        // "security" fields
288        mWhiteListEnable = rhs.mWhiteListEnable;
289        mWhiteList = rhs.mWhiteList;
290
291        // "permissions" fields
292        mPermsInteract = rhs.mPermsInteract;
293        mPermsControl = rhs.mPermsControl;
294    }
295
296    return *this;
297}
298
299bool LLMediaEntry::operator==(const LLMediaEntry &rhs) const
300{
301    return (
302        // "general" fields
303        mAltImageEnable == rhs.mAltImageEnable &&
304        mControls == rhs.mControls &&
305        mCurrentURL == rhs.mCurrentURL &&
306        mHomeURL == rhs.mHomeURL &&
307        mAutoLoop == rhs.mAutoLoop &&
308        mAutoPlay == rhs.mAutoPlay &&
309        mAutoScale == rhs.mAutoScale &&
310        mAutoZoom == rhs.mAutoZoom &&
311        mFirstClickInteract == rhs.mFirstClickInteract &&
312        mWidthPixels == rhs.mWidthPixels &&
313        mHeightPixels == rhs.mHeightPixels &&
314
315        // "security" fields
316        mWhiteListEnable == rhs.mWhiteListEnable &&
317        mWhiteList == rhs.mWhiteList &&
318
319        // "permissions" fields
320        mPermsInteract == rhs.mPermsInteract &&
321        mPermsControl == rhs.mPermsControl
322
323        );
324}
325 
326bool LLMediaEntry::operator!=(const LLMediaEntry &rhs) const
327{
328    return (
329        // "general" fields
330        mAltImageEnable != rhs.mAltImageEnable ||
331        mControls != rhs.mControls ||
332        mCurrentURL != rhs.mCurrentURL ||
333        mHomeURL != rhs.mHomeURL ||
334        mAutoLoop != rhs.mAutoLoop ||
335        mAutoPlay != rhs.mAutoPlay ||
336        mAutoScale != rhs.mAutoScale ||
337        mAutoZoom != rhs.mAutoZoom ||
338        mFirstClickInteract != rhs.mFirstClickInteract ||
339        mWidthPixels != rhs.mWidthPixels ||
340        mHeightPixels != rhs.mHeightPixels ||
341
342        // "security" fields
343        mWhiteListEnable != rhs.mWhiteListEnable ||
344        mWhiteList != rhs.mWhiteList ||
345
346        // "permissions" fields
347        mPermsInteract != rhs.mPermsInteract ||
348        mPermsControl != rhs.mPermsControl 
349        
350        );
351}
352
353U32 LLMediaEntry::setWhiteList( const std::vector<std::string> &whitelist )
354{
355    // *NOTE: This code is VERY similar to the setWhitelist below.
356    // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
357    U32 size = 0;
358    U32 count = 0;
359    // First count to make sure the size constraint is not violated
360    std::vector<std::string>::const_iterator iter = whitelist.begin();
361    std::vector<std::string>::const_iterator end = whitelist.end();
362    for ( ; iter < end; ++iter) 
363    {
364        const std::string &entry = (*iter);
365        size += entry.length() + 1; // Include one for \0
366        count ++;
367        if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) 
368		{
369            return LSL_STATUS_BOUNDS_ERROR;
370        }
371    }
372    // Next clear the vector
373    mWhiteList.clear();
374    // Then re-iterate and copy entries
375    iter = whitelist.begin();
376    for ( ; iter < end; ++iter)
377    {
378        const std::string &entry = (*iter);
379        mWhiteList.push_back(entry);
380    }
381    return LSL_STATUS_OK;
382}
383
384U32 LLMediaEntry::setWhiteList( const LLSD &whitelist )
385{
386    // If whitelist is undef, the whitelist is cleared
387    if (whitelist.isUndefined()) 
388	{
389		mWhiteList.clear();
390		return LSL_STATUS_OK;
391	}
392
393    // However, if the whitelist is an empty array, erase it.
394    if (whitelist.isArray()) 
395    {
396        // *NOTE: This code is VERY similar to the setWhitelist above.
397        // IF YOU CHANGE THIS IMPLEMENTATION, BE SURE TO CHANGE THE OTHER!
398        U32 size = 0;
399        U32 count = 0;
400        // First check to make sure the size and count constraints are not violated
401        LLSD::array_const_iterator iter = whitelist.beginArray();
402        LLSD::array_const_iterator end = whitelist.endArray();
403        for ( ; iter < end; ++iter) 
404        {
405            const std::string &entry = (*iter).asString();
406            size += entry.length() + 1; // Include one for \0
407            count ++;
408            if (size > MAX_WHITELIST_SIZE || count > MAX_WHITELIST_COUNT) 
409			{
410                return LSL_STATUS_BOUNDS_ERROR;
411            }
412        }
413        // Next clear the vector
414        mWhiteList.clear();
415        // Then re-iterate and copy entries
416        iter = whitelist.beginArray();
417        for ( ; iter < end; ++iter)
418        {
419            const std::string &entry = (*iter).asString();
420            mWhiteList.push_back(entry);
421        }
422        return LSL_STATUS_OK;
423    }
424    else 
425	{
426        return LSL_STATUS_MALFORMED_PARAMS;
427    }
428}
429
430
431static void prefix_with(std::string &str, const char *chars, const char *prefix)
432{
433    // Given string 'str', prefix all instances of any character in 'chars'
434    // with 'prefix'
435    size_t found = str.find_first_of(chars);
436    size_t prefix_len = strlen(prefix);
437    while (found != std::string::npos)
438    {
439        str.insert(found, prefix, prefix_len);
440        found = str.find_first_of(chars, found+prefix_len+1);
441    }
442}
443
444static bool pattern_match(const std::string &candidate_str, const std::string &pattern)
445{
446    // If the pattern is empty, it matches
447    if (pattern.empty()) return true;
448    
449    // 'pattern' is a glob pattern, we only accept '*' chars
450    // copy it
451    std::string expression = pattern;
452    
453    // Escape perl's regexp chars with a backslash, except all "*" chars
454    prefix_with(expression, ".[{()\\+?|^$", "\\");
455    prefix_with(expression, "*", ".");
456                    
457    // case-insensitive matching:
458    boost::regex regexp(expression, boost::regex::perl|boost::regex::icase);
459    return boost::regex_match(candidate_str, regexp);
460}
461
462bool LLMediaEntry::checkCandidateUrl(const std::string& url) const
463{
464    if (getWhiteListEnable()) 
465    {
466        return checkUrlAgainstWhitelist(url, getWhiteList());
467    }
468    else 
469	{
470        return true;
471    }
472}
473
474// static
475bool LLMediaEntry::checkUrlAgainstWhitelist(const std::string& url, 
476                                            const std::vector<std::string> &whitelist)
477{
478    bool passes = true;
479    // *NOTE: no entries?  Don't check
480    if (whitelist.size() > 0) 
481    {
482        passes = false;
483            
484        // Case insensitive: the reason why we toUpper both this and the
485        // filter
486        std::string candidate_url = url;
487        // Use lluri to see if there is a path part in the candidate URL.  No path?  Assume "/"
488        LLURI candidate_uri(candidate_url);
489        std::vector<std::string>::const_iterator iter = whitelist.begin();
490        std::vector<std::string>::const_iterator end = whitelist.end();
491        for ( ; iter < end; ++iter )
492        {
493            std::string filter = *iter;
494                
495            LLURI filter_uri(filter);
496            bool scheme_passes = pattern_match( candidate_uri.scheme(), filter_uri.scheme() );
497            if (filter_uri.scheme().empty()) 
498            {
499                filter_uri = LLURI(DEFAULT_URL_PREFIX + filter);
500            }
501            bool authority_passes = pattern_match( candidate_uri.authority(), filter_uri.authority() );
502            bool path_passes = pattern_match( candidate_uri.escapedPath(), filter_uri.escapedPath() );
503
504            if (scheme_passes && authority_passes && path_passes)
505            {
506                passes = true;
507                break;
508            }
509        }
510    }
511    return passes;
512}
513
514U32 LLMediaEntry::setStringFieldWithLimit( std::string &field, const std::string &value, U32 limit )
515{
516    if ( value.length() > limit ) 
517	{
518        return LSL_STATUS_BOUNDS_ERROR;
519    }
520    else 
521	{
522        field = value;
523        return LSL_STATUS_OK;
524    }
525}
526
527U32 LLMediaEntry::setControls(LLMediaEntry::MediaControls controls)
528{
529    if (controls == STANDARD ||
530        controls == MINI)
531    {
532        mControls = controls;
533        return LSL_STATUS_OK;
534    }
535    return LSL_STATUS_BOUNDS_ERROR;
536}
537
538U32 LLMediaEntry::setPermsInteract( U8 val )
539{
540    mPermsInteract = val & PERM_MASK;
541    return LSL_STATUS_OK;
542}
543
544U32 LLMediaEntry::setPermsControl( U8 val )
545{
546    mPermsControl = val & PERM_MASK;
547    return LSL_STATUS_OK;
548}
549
550U32 LLMediaEntry::setCurrentURL(const std::string& current_url)
551{
552    return setCurrentURLInternal( current_url, true );
553}
554
555U32 LLMediaEntry::setCurrentURLInternal(const std::string& current_url, bool check_whitelist)
556{
557    if ( ! check_whitelist || checkCandidateUrl(current_url)) 
558    {
559        return setStringFieldWithLimit( mCurrentURL, current_url, MAX_URL_LENGTH );
560    }
561    else 
562	{
563        return LSL_STATUS_WHITELIST_FAILED;
564    }
565}
566
567U32 LLMediaEntry::setHomeURL(const std::string& home_url)
568{
569    return setStringFieldWithLimit( mHomeURL, home_url, MAX_URL_LENGTH );
570}
571
572U32 LLMediaEntry::setWidthPixels(U16 width)
573{
574    if (width > MAX_WIDTH_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
575    mWidthPixels = width;
576    return LSL_STATUS_OK; 
577}
578
579U32 LLMediaEntry::setHeightPixels(U16 height)
580{
581    if (height > MAX_HEIGHT_PIXELS) return LSL_STATUS_BOUNDS_ERROR;
582    mHeightPixels = height;
583    return LSL_STATUS_OK; 
584}
585
586const LLUUID &LLMediaEntry::getMediaID() const
587{
588    // Lazily generate media ID
589    if (NULL == mMediaIDp)
590    {
591        mMediaIDp = new LLUUID();
592        mMediaIDp->generate();
593    }
594    return *mMediaIDp;
595}
596