/* like strcasecmp(s1.raw_buf(),s2.raw_buf()) but for unicode * TODO: slow! */ int tiny_string::strcasecmp(tiny_string& s2) const { char* str1 = g_utf8_casefold(this->raw_buf(),this->numBytes()); char* str2 = g_utf8_casefold(s2.raw_buf(),s2.numBytes()); int ret = g_utf8_collate(str1,str2); g_free(str1); g_free(str2); return ret; }
/* start is an index of characters. * returns index of character */ uint32_t tiny_string::find(const tiny_string& needle, uint32_t start) const { //TODO: omit copy into std::string size_t bytestart = g_utf8_offset_to_pointer(buf,start) - buf; size_t bytepos = std::string(*this).find(needle.raw_buf(),bytestart,needle.numBytes()); if(bytepos == std::string::npos) return npos; else return g_utf8_pointer_to_offset(buf,buf+bytepos); }
void ByteArray::writeUTF(const tiny_string& str) { getBuffer(position+str.numBytes()+2,true); if(str.numBytes() > 65535) { throwError<RangeError>(kParamRangeError); } uint16_t numBytes=endianIn((uint16_t)str.numBytes()); memcpy(bytes+position,&numBytes,2); memcpy(bytes+position+2,str.raw_buf(),str.numBytes()); position+=str.numBytes()+2; }
bool SocketIO::connect(const tiny_string& hostname, int port) { struct addrinfo hints; struct addrinfo *servinfo; struct addrinfo *p; if (fd != -1) return false; fd = -1; if (port <= 0 || port > 65535) return false; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; tiny_string portstr = Integer::toString(port); if (getaddrinfo(hostname.raw_buf(), portstr.raw_buf(), &hints, &servinfo) != 0) { return false; } for(p = servinfo; p != NULL; p = p->ai_next) { if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) continue; // TODO: timeout on connect if (::connect(fd, p->ai_addr, p->ai_addrlen) == -1) { ::close(fd); continue; } break; } freeaddrinfo(servinfo); if (!p) fd = -1; return fd != -1; }
const pugi::xml_node XMLBase::buildFromString(const tiny_string& str, unsigned int xmlparsemode, const tiny_string& default_ns) { tiny_string buf = quirkEncodeNull(removeWhitespace(str)); if (buf.numBytes() > 0 && buf.charAt(0) == '<') { pugi::xml_parse_result res = xmldoc.load_buffer((void*)buf.raw_buf(),buf.numBytes(),xmlparsemode); switch (res.status) { case pugi::status_ok: break; case pugi::status_end_element_mismatch: throwError<TypeError>(kXMLUnterminatedElementTag); break; case pugi::status_unrecognized_tag: throwError<TypeError>(kXMLMalformedElement); break; case pugi::status_bad_pi: throwError<TypeError>(kXMLUnterminatedXMLDecl); break; case pugi::status_bad_attribute: throwError<TypeError>(kXMLUnterminatedAttribute); break; case pugi::status_bad_cdata: throwError<TypeError>(kXMLUnterminatedCData); break; case pugi::status_bad_doctype: throwError<TypeError>(kXMLUnterminatedDocTypeDecl); break; case pugi::status_bad_comment: throwError<TypeError>(kXMLUnterminatedComment); break; default: LOG(LOG_ERROR,"xml parser error:"<<buf<<" "<<res.status<<" "<<res.description()); break; } } else { pugi::xml_node n = xmldoc.append_child(pugi::node_pcdata); n.set_value(str.raw_buf()); } return xmldoc.root(); }
void XMLSocket::connect(tiny_string host, int port) { if (port <= 0 || port > 65535) throw Class<SecurityError>::getInstanceS(getSystemState(),"Invalid port"); if (host.empty()) host = getSys()->mainClip->getOrigin().getHostname(); if (isConnected()) throw Class<IOError>::getInstanceS(getSystemState(),"Already connected"); // Host shouldn't contain scheme or port if (host.strchr(':') != NULL) throw Class<SecurityError>::getInstanceS(getSystemState(),"Invalid hostname"); // Check sandbox and policy file size_t buflen = host.numBytes() + 22; char *urlbuf = g_newa(char, buflen); snprintf(urlbuf, buflen, "xmlsocket://%s:%d", host.raw_buf(), port); URLInfo url(urlbuf); getSystemState()->securityManager->checkURLStaticAndThrow(url, ~(SecurityManager::LOCAL_WITH_FILE), SecurityManager::LOCAL_WITH_FILE | SecurityManager::LOCAL_TRUSTED, true); SecurityManager::EVALUATIONRESULT evaluationResult; evaluationResult = getSys()->securityManager->evaluateSocketConnection(url, true); if(evaluationResult != SecurityManager::ALLOWED) { incRef(); getVm(getSystemState())->addEvent(_MR(this), _MR(Class<SecurityErrorEvent>::getInstanceS(getSystemState(),"No policy file allows socket connection"))); return; } incRef(); XMLSocketThread *thread = new XMLSocketThread(_MR(this), host, port, timeout); getSys()->addJob(thread); job = thread; }
ASString::ASString(const tiny_string& s):data(s.raw_buf()) { type=T_STRING; }
/** * \brief Checks URL policy files to see if the player is allowed to send a given request header * as part of a request for the given URL * * Waits for mutex at start and releases mutex when finished * \param url The URL of the request to which the request header belongs * \param header The request header to evaluate * \param loadPendingPolicies Whether or not to load (and thus check) pending policy files * \return \c ALLOWED if allowed or otherwise \c NA_HEADER */ SecurityManager::EVALUATIONRESULT SecurityManager::evaluateHeader(const URLInfo& url, const tiny_string& header, bool loadPendingPolicies) { //This check doesn't apply to local files if(url.getProtocol() == "file" && getSys()->getOrigin().getProtocol() == "file") return ALLOWED; LOG(LOG_INFO, _("SECURITY: Evaluating header for cross domain policies ('") << header << "'):"); LOG(LOG_INFO, _("SECURITY: --> URL: ") << url); LOG(LOG_INFO, _("SECURITY: --> Origin: ") << getSys()->getOrigin()); string headerStrLower(header.raw_buf()); transform(headerStrLower.begin(), headerStrLower.end(), headerStrLower.begin(), ::tolower); string headerStr = headerStrLower; if(headerStr.find("_") != string::npos) headerStr.replace(headerStr.find("_"), 1, "-"); //Disallowed headers, in any case if(headerStr == "accept-charset" && headerStr == "accept-encoding" && headerStr == "accept-ranges" && headerStr == "age" && headerStr == "allow" && headerStr == "allowed" && headerStr == "authorization" && headerStr == "charge-to" && headerStr == "connect" && headerStr == "connection" && headerStr == "content-length" && headerStr == "content-location" && headerStr == "content-range" && headerStr == "cookie" && headerStr == "date" && headerStr == "delete" && headerStr == "etag" && headerStr == "expect" && headerStr == "get" && headerStr == "head" && headerStr == "host" && headerStr == "if-modified-since" && headerStr == "keep-alive" && headerStr == "last-modified" && headerStr == "location" && headerStr == "max-forwards" && headerStr == "options" && headerStr == "origin" && headerStr == "post" && headerStr == "proxy-authenticate" && headerStr == "proxy-authorization" && headerStr == "proxy-connection" && headerStr == "public" && headerStr == "put" && headerStr == "range" && headerStr == "referer" && headerStr == "request-range" && headerStr == "retry-after" && headerStr == "server" && headerStr == "te" && headerStr == "trace" && headerStr == "trailer" && headerStr == "transfer-encoding" && headerStr == "upgrade" && headerStr == "uri" && headerStr == "user-agent" && headerStr == "vary" && headerStr == "via" && headerStr == "warning" && headerStr == "www-authenticate" && headerStr == "x-flash-version") { LOG(LOG_INFO, _("SECURITY: DISALLOWED: Header is restricted")); return NA_HEADER; } //The URL has exactly the same domain name as the origin, always allowed if(url.getProtocol() == getSys()->getOrigin().getProtocol() && url.getHostname() == getSys()->getOrigin().getHostname()) { LOG(LOG_INFO, _("SECURITY: ALLOWED: Same hostname as origin")); return ALLOWED; } //Search for the policy files to check URLPFileList* files = searchURLPolicyFiles(url, loadPendingPolicies); RecMutex::Lock l(mutex); //Check the policy files if(files != NULL) { URLPFileListConstIt it = files->begin(); for(; it != files->end(); ++it) { if((*it)->allowsHTTPRequestHeaderFrom(getSys()->getOrigin(), url, headerStrLower)) { LOG(LOG_INFO, _("SECURITY: ALLOWED: A policy file explicitly allowed the header")); delete files; return ALLOWED; } } } LOG(LOG_INFO, _("SECURITY: DISALLOWED: No policy file explicitly allowed the header")); delete files; return NA_CROSSDOMAIN_POLICY; }
void URLVariables::decode(const tiny_string& s) { const char* nameStart=NULL; const char* nameEnd=NULL; const char* valueStart=NULL; const char* valueEnd=NULL; const char* cur=s.raw_buf(); while(1) { if(nameStart==NULL) nameStart=cur; if(*cur == '=') { if(nameStart==NULL || valueStart!=NULL) //Skip this { nameStart=NULL; nameEnd=NULL; valueStart=NULL; valueEnd=NULL; cur++; continue; } nameEnd=cur; valueStart=cur+1; } else if(*cur == '&' || *cur==0) { if(nameStart==NULL || nameEnd==NULL || valueStart==NULL || valueEnd!=NULL) { nameStart=NULL; nameEnd=NULL; valueStart=NULL; valueEnd=NULL; cur++; continue; } valueEnd=cur; char* name=g_uri_unescape_segment(nameStart,nameEnd,NULL); char* value=g_uri_unescape_segment(valueStart,valueEnd,NULL); nameStart=NULL; nameEnd=NULL; valueStart=NULL; valueEnd=NULL; //Check if the variable already exists multiname propName; propName.name_type=multiname::NAME_STRING; propName.name_s=name; propName.ns.push_back(nsNameAndKind("",NAMESPACE)); ASObject* curValue=getVariableByMultiname(propName); if(curValue) { //If the variable already exists we have to create an Array of values Array* arr=NULL; if(curValue->getObjectType()!=T_ARRAY) { arr=Class<Array>::getInstanceS(); curValue->incRef(); arr->push(curValue); setVariableByMultiname(propName,arr); } else arr=Class<Array>::cast(curValue); arr->push(Class<ASString>::getInstanceS(value)); } else setVariableByMultiname(propName,Class<ASString>::getInstanceS(value)); g_free(name); g_free(value); if(*cur==0) break; } cur++; } }