void binary_deserialize_spec(const Object& zthis, PHPInputTransport& transport, const Array& spec) { // SET and LIST have 'elem' => array('type', [optional] 'class') // MAP has 'val' => array('type', [optiona] 'class') while (true) { Variant val; int8_t ttype = transport.readI8(); if (ttype == T_STOP) return; int16_t fieldno = transport.readI16(); if (!(val = spec.rvalAt(fieldno)).isNull()) { Array fieldspec = val.toArray(); // pull the field name // zend hash tables use the null at the end in the length... so strlen(hash key) + 1. String varname = fieldspec.rvalAt(PHPTransport::s_var).toString(); // and the type int8_t expected_ttype = fieldspec.rvalAt(PHPTransport::s_type).toInt64(); if (ttypes_are_compatible(ttype, expected_ttype)) { Variant rv = binary_deserialize(ttype, transport, fieldspec); zthis->o_set(varname, rv, zthis->getClassName()); } else { skip_element(ttype, transport); } } else { skip_element(ttype, transport); } } }
SourceRootInfo::SourceRootInfo(const char *host) : m_sandboxCond(RuntimeOption::SandboxMode ? SandboxOn : SandboxOff) { s_path.destroy(); s_phproot.destroy(); if (!sandboxOn()) return; Variant matches; Variant r = preg_match(String(RuntimeOption::SandboxPattern.c_str(), RuntimeOption::SandboxPattern.size(), AttachLiteral), host, matches); if (!r.same(1)) { m_sandboxCond = SandboxOff; return; } if (RuntimeOption::SandboxFromCommonRoot) { String sandboxName = matches.rvalAt(1).toString(); createFromCommonRoot(sandboxName); } else { Array pair = StringUtil::Explode(matches.rvalAt(1), "-", 2); m_user = pair.rvalAt(0).toString(); bool defaultSb = pair.size() == 1; if (defaultSb) { m_sandbox = "default"; } else { m_sandbox = pair.rvalAt(1).toString(); } createFromUserConfig(); } *s_path.getCheck() = m_path.c_str(); }
Variant HHVM_FUNCTION(xbox_process_call_message, const String& msg) { Variant v = unserialize_from_string(msg); if (!v.isArray()) { raise_error("Error decoding xbox call message"); } Array arr = v.toArray(); if (arr.size() != 2 || !arr.exists(0) || !arr.exists(1)) { raise_error("Error decoding xbox call message"); } Variant fn = arr.rvalAt(0); if (fn.isArray()) { Array farr = fn.toArray(); if (!array_is_valid_callback(farr)) { raise_error("Error decoding xbox call message"); } } else if (!fn.isString()) { raise_error("Error decoding xbox call message"); } Variant args = arr.rvalAt(1); if (!args.isArray()) { raise_error("Error decoding xbox call message"); } return vm_call_user_func(fn, args.toArray()); }
void binary_serialize_spec(const Object& zthis, PHPOutputTransport& transport, const Array& spec) { for (ArrayIter key_ptr = spec.begin(); !key_ptr.end(); ++key_ptr) { Variant key = key_ptr.first(); if (!key.isInteger()) { throw_tprotocolexception("Bad keytype in TSPEC (expected 'long')", INVALID_DATA); return; } unsigned long fieldno = key.toInt64(); Array fieldspec = key_ptr.second().toArray(); // field name String varname = fieldspec.rvalAt(PHPTransport::s_var, AccessFlags::Error_Key).toString(); // thrift type int8_t ttype = fieldspec.rvalAt(PHPTransport::s_type, AccessFlags::Error_Key).toByte(); Variant prop = zthis->o_get(varname, true, zthis->getClassName()); if (!prop.isNull()) { transport.writeI8(ttype); transport.writeI16(fieldno); binary_serialize(ttype, transport, prop, fieldspec); } } transport.writeI8(T_STOP); // struct end }
bool BaseExecutionContext::onFatalError(const Exception &e) { recordLastError(e); const char *file = NULL; int line = 0; if (RuntimeOption::InjectedStackTrace) { const ExtendedException *ee = dynamic_cast<const ExtendedException *>(&e); if (ee) { ArrayPtr bt = ee->getBackTrace(); if (!bt->empty()) { Array top = bt->rvalAt(0).toArray(); if (top.exists("file")) file = top.rvalAt("file").toString(); if (top.exists("line")) line = top.rvalAt("line"); } } } if (RuntimeOption::AlwaysLogUnhandledExceptions) { Logger::Log(Logger::LogError, "HipHop Fatal error: ", e, file, line); } bool handled = false; if (RuntimeOption::CallUserHandlerOnFatals) { int errnum = ErrorConstants::FATAL_ERROR; handled = callUserErrorHandler(e, errnum, true); } if (!handled && !RuntimeOption::AlwaysLogUnhandledExceptions) { Logger::Log(Logger::LogError, "HipHop Fatal error: ", e, file, line); } return handled; }
File* HttpStreamWrapper::open(CStrRef filename, CStrRef mode, int options, CVarRef context) { if (RuntimeOption::ServerHttpSafeMode) { return nullptr; } if (strncmp(filename.data(), "http://", sizeof("http://") - 1) && strncmp(filename.data(), "https://", sizeof("https://") - 1)) { return nullptr; } std::unique_ptr<UrlFile> file; StreamContext *ctx = !context.isResource() ? nullptr : context.toResource().getTyped<StreamContext>(); if (!ctx || ctx->m_options.isNull() || ctx->m_options[s_http].isNull()) { file = std::unique_ptr<UrlFile>(NEWOBJ(UrlFile)()); } else { Array opts = ctx->m_options[s_http].toArray(); String method = s_GET; if (opts.exists(s_method)) { method = opts[s_method].toString(); } Array headers; if (opts.exists(s_header)) { Array lines = StringUtil::Explode( opts[s_header].toString(), "\r\n").toArray(); for (ArrayIter it(lines); it; ++it) { Array parts = StringUtil::Explode( it.second().toString(), ": ").toArray(); headers.set(parts.rvalAt(0), parts.rvalAt(1)); } } static const StaticString s_user_agent("user_agent"); static const StaticString s_User_Agent("User-Agent"); if (opts.exists(s_user_agent) && !headers.exists(s_User_Agent)) { headers.set(s_User_Agent, opts[s_user_agent]); } int max_redirs = 20; if (opts.exists(s_max_redirects)) { max_redirs = opts[s_max_redirects].toInt64(); } int timeout = -1; if (opts.exists(s_timeout)) { timeout = opts[s_timeout].toInt64(); } file = std::unique_ptr<UrlFile>(NEWOBJ(UrlFile)(method.data(), headers, opts[s_content].toString(), max_redirs, timeout)); } bool ret = file->open(filename, mode); if (!ret) { raise_warning("Failed to open %s (%s)", filename.data(), file->getLastError().c_str()); return nullptr; } return file.release(); }
std::pair<String, int> ExtendedException::getFileAndLine() const { String file = empty_string(); int line = 0; Array bt = getBacktrace(); if (!bt.empty()) { Array top = bt.rvalAt(0).toArray(); if (top.exists(s_file)) file = top.rvalAt(s_file).toString(); if (top.exists(s_line)) line = top.rvalAt(s_line).toInt64(); } return std::make_pair(file, line); }
void BaseExecutionContext::handleError(const std::string &msg, int errnum, bool callUserHandler, ErrorThrowMode mode, const std::string &prefix) { SYNC_VM_REGS_SCOPED(); int newErrorState = ErrorRaised; switch (getErrorState()) { case ErrorRaised: case ErrorRaisedByUserHandler: return; case ExecutingUserHandler: newErrorState = ErrorRaisedByUserHandler; break; default: break; } ErrorStateHelper esh(this, newErrorState); ExtendedException ee(msg); recordLastError(ee, errnum); bool handled = false; if (callUserHandler) { handled = callUserErrorHandler(ee, errnum, false); } if (mode == AlwaysThrow || (mode == ThrowIfUnhandled && !handled)) { try { if (!Eval::Debugger::InterruptException(String(msg))) return; } catch (const Eval::DebuggerClientExitException &e) {} throw FatalErrorException(msg.c_str()); } if (!handled && (RuntimeOption::NoSilencer || (getErrorReportingLevel() & errnum) != 0)) { try { if (!Eval::Debugger::InterruptException(String(msg))) return; } catch (const Eval::DebuggerClientExitException &e) {} const char *file = NULL; int line = 0; if (RuntimeOption::InjectedStackTrace) { ArrayPtr bt = ee.getBackTrace(); if (!bt->empty()) { Array top = bt->rvalAt(0).toArray(); if (top.exists("file")) file = top.rvalAt("file").toString(); if (top.exists("line")) line = top.rvalAt("line"); } } Logger::Log(Logger::LogError, prefix.c_str(), ee, file, line); } }
SourceRootInfo::SourceRootInfo(Transport* transport) : m_sandboxCond(RuntimeOption::SandboxMode ? SandboxCondition::On : SandboxCondition::Off) { s_path.destroy(); s_phproot.destroy(); auto documentRoot = transport->getDocumentRoot(); if (!documentRoot.empty()) { m_user = s___builtin; m_sandbox = s_default; // The transport take precedence over the config file m_path = documentRoot; *s_path.getCheck() = documentRoot; return; } if (!sandboxOn()) return; auto host = transport->getHeader("Host"); Variant matches; Variant r = preg_match(String(RuntimeOption::SandboxPattern.c_str(), RuntimeOption::SandboxPattern.size(), CopyString), host, &matches); if (!same(r, 1)) { m_sandboxCond = SandboxCondition::Off; return; } if (RuntimeOption::SandboxFromCommonRoot) { auto sandboxName = tvCastToString(matches.toArray().rvalAt(1).tv()); createFromCommonRoot(sandboxName); } else { Array pair = StringUtil::Explode( tvCastToString(matches.toArray().rvalAt(1).tv()), "-", 2 ).toArray(); m_user = tvCastToString(pair.rvalAt(0).tv()); bool defaultSb = pair.size() == 1; if (defaultSb) { m_sandbox = s_default; } else { m_sandbox = tvCastToString(pair.rvalAt(1).tv()); } createFromUserConfig(); } *s_path.getCheck() = m_path.c_str(); }
bool ExecutionContext::callUserErrorHandler(const Exception &e, int64 errnum, bool swallowExceptions) { int errline = 0; String errfile; Array backtrace; const ExtendedException *ee = dynamic_cast<const ExtendedException*>(&e); if (ee) { ArrayPtr arr = ee->getBackTrace(); if (arr) { backtrace = *arr; Array top = backtrace.rvalAt(0); if (!top.isNull()) { errfile = top.rvalAt("file"); errline = top.rvalAt("line").toInt64(); } } } if (backtrace.isNull()) { backtrace = stackTraceToBackTrace(e.getStackTrace()); } bool retval = false; RequestData::Data *data = s_request_data->data; if (!data->systemExceptionHandlers.empty()) { // Avoid calling the user error handler recursively if (!data->insideUserHandler) { data->insideUserHandler = true; try { if (!same(f_call_user_func_array (data->systemExceptionHandlers.back(), CREATE_VECTOR6(errnum, String(e.getMessage()), errfile, errline, "", backtrace)), false)) { retval = true; } } catch (...) { data->insideUserHandler = false; if (!swallowExceptions) throw; } data->insideUserHandler = false; } } return retval; }
bool BaseExecutionContext::callUserErrorHandler(const Exception &e, int errnum, bool swallowExceptions) { switch (getErrorState()) { case ExecutingUserHandler: case ErrorRaisedByUserHandler: return false; default: break; } if (!m_userErrorHandlers.empty() && (m_userErrorHandlers.back().second & errnum) != 0) { int errline = 0; String errfile; Array backtrace; const ExtendedException *ee = dynamic_cast<const ExtendedException*>(&e); if (ee) { ArrayPtr arr = ee->getBackTrace(); if (arr) { backtrace = *arr; Array top = backtrace.rvalAt(0); if (!top.isNull()) { errfile = top.rvalAt("file"); errline = top.rvalAt("line").toInt64(); } } } if (backtrace.isNull()) { backtrace = stackTraceToBackTrace(e.getStackTrace()); } try { ErrorStateHelper esh(this, ExecutingUserHandler); if (!same(f_call_user_func_array (m_userErrorHandlers.back().first, CREATE_VECTOR6(errnum, String(e.getMessage()), errfile, errline, "", backtrace)), false)) { return true; } } catch (...) { if (!swallowExceptions) throw; } } return false; }
static std::string getSandboxHostFormat() { // Assume dev servers host name are in following format: // <host>.<cluster>.<domain>.com // and we need to change to the following to match sandbox format: // www.<sandbox>.<host>.<domain>.com String hostName = f_php_uname("n"); Array fields = f_split("\\.", hostName); if (fields.size() != 4) { return ""; } String host = fields.rvalAt(0).toString(); String domain = fields.rvalAt(1).toString() + "." + fields.rvalAt(2).toString(); String suffix = fields.rvalAt(3).toString(); string sandboxHost = "hphpd.debugger_tests." + host->toCPPString() + "." + domain->toCPPString() + "." + suffix->toCPPString(); return sandboxHost; }
////////////////////////////////////////////////////////////////////////////// // class ImagickDraw ALWAYS_INLINE static void getAffineMatrixElement( const Array& array, const String& key, double& ret) { auto const value = array.rvalAt(key).unboxed(); if (isNullType(value.type())) { IMAGICKDRAW_THROW( "AffineMatrix must contain keys: sx, rx, ry, sy, tx and ty"); } else { ret = cellToDouble(value.tv()); } }
bool f_is_callable(CVarRef v, bool syntax /* = false */, Variant name /* = null */) { if (v.isString()) { if (!name.isNull()) name = v; if (syntax) return true; string lowered = Util::toLower((const char *)v.toString()); size_t c = lowered.find("::"); if (c != 0 && c != string::npos && c+2 < lowered.size()) { string classname = lowered.substr(0, c); string methodname = lowered.substr(c+2); const ClassInfo *clsInfo = ClassInfo::FindClass(classname.c_str()); if (clsInfo && clsInfo->isDeclared()) { return clsInfo->hasMethod(methodname.c_str()); } return false; } return f_function_exists(v.toString()); } if (v.is(KindOfArray)) { Array arr = v.toArray(); if (arr.size() == 2 && arr.exists(0LL) && arr.exists(1LL)) { Variant v0 = arr.rvalAt(0LL); Variant v1 = arr.rvalAt(1LL); if (v0.is(KindOfObject)) { v0 = v0.toObject()->o_getClassName(); } if (v0.isString() && v1.isString()) { if (!name.isNull()) { name = v0.toString() + "::" + v1.toString(); } if (same(v0, "self") || same(v0, "parent")) { throw NotImplementedException("augmenting class scope info"); } const ClassInfo *clsInfo = ClassInfo::FindClass(v0.toString()); if (clsInfo && clsInfo->isDeclared()) { return clsInfo->hasMethod(v1.toString()); } return false; } } } if (!name.isNull()) { name = v.toString(); } return false; }
Resource createInstance(const char* php_func, const Resource& stream, const String& filter, CVarRef params) { auto class_name = m_registeredFilters.rvalAt(filter).asCStrRef(); Class* class_ = Unit::lookupClass(class_name.get()); Object obj = null_object; if (LIKELY(class_ != nullptr)) { ArrayInit ctor_args(3); ctor_args.set(stream); ctor_args.set(filter); ctor_args.set(params); obj = g_context->createObject(class_name.get(), ctor_args.toArray()); auto created = obj->o_invoke(s_onCreate, Array::Create()); /* - true: documented value for success * - null: undocumented default successful value * - false: documented value for failure */ if (!(created.isNull() || created.toBoolean())) { obj = null_object; } } else { raise_warning("%s: user-filter \"%s\" requires class \"%s\", but that " "class " "is not defined", php_func, filter->data(), class_name->data()); // Fall through, as to match Zend, the warning below should also be raised } if (obj.isNull()) { raise_warning("%s: unable to create or locate filter \"%s\"", php_func, filter->data()); return null_resource; } return Resource(NEWOBJ(StreamFilter)(obj)); }
SmartPtr<StreamFilter> createInstance(const char* php_func, SmartPtr<File> stream, const String& filter, const Variant& params) { auto class_name = m_registeredFilters.rvalAt(filter).asCStrRef(); Class* class_ = Unit::getClass(class_name.get(), true); Object obj = Object(); if (LIKELY(class_ != nullptr)) { PackedArrayInit ctor_args(3); ctor_args.append(Variant(stream)); ctor_args.append(filter); ctor_args.append(params); obj = g_context->createObject(class_name.get(), ctor_args.toArray()); auto created = obj->o_invoke(s_onCreate, Array::Create()); /* - true: documented value for success * - null: undocumented default successful value * - false: documented value for failure */ if (!(created.isNull() || created.toBoolean())) { obj.reset(); } } else { raise_warning("%s: user-filter \"%s\" requires class \"%s\", but that " "class " "is not defined", php_func, filter.data(), class_name.data()); // Fall through, as to match Zend, the warning below should also be raised } if (obj.isNull()) { raise_warning("%s: unable to create or locate filter \"%s\"", php_func, filter.data()); return nullptr; } return makeSmartPtr<StreamFilter>(obj, stream); }
req::ptr<File> HttpStreamWrapper::open(const String& filename, const String& mode, int options, const req::ptr<StreamContext>& context) { if (RuntimeOption::ServerHttpSafeMode && !is_cli_mode()) { return nullptr; } if (strncmp(filename.data(), "http://", sizeof("http://") - 1) && strncmp(filename.data(), "https://", sizeof("https://") - 1)) { return nullptr; } Array headers; String method = s_GET; String post_data = null_string; String proxy_host; String proxy_user; String proxy_pass; int proxy_port = -1; int max_redirs = 20; int timeout = -1; bool ignore_errors = false; if (context && !context->getOptions().isNull() && !context->getOptions()[s_http].isNull()) { Array opts = context->getOptions()[s_http].toArray(); if (opts.exists(s_method)) { method = opts[s_method].toString(); } if (opts.exists(s_header)) { Array lines; if (opts[s_header].isString()) { lines = StringUtil::Explode( opts[s_header].toString(), "\r\n").toArray(); } else if (opts[s_header].isArray()) { lines = opts[s_header]; } for (ArrayIter it(lines); it; ++it) { Array parts = StringUtil::Explode( it.second().toString(), ":", 2).toArray(); headers.set(parts.rvalAt(0), parts.rvalAt(1)); } } if (opts.exists(s_user_agent) && !headers.exists(s_User_Agent)) { headers.set(s_User_Agent, opts[s_user_agent]); } if (opts.exists(s_max_redirects)) { max_redirs = opts[s_max_redirects].toInt64(); } if (opts.exists(s_timeout)) { timeout = opts[s_timeout].toInt64(); } if (opts.exists(s_ignore_errors)) { ignore_errors = opts[s_ignore_errors].toBoolean(); } if (opts.exists(s_proxy)) { Variant host = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_HOST); Variant port = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_PORT); if (!same(host, false) && !same(port, false)) { proxy_host = host.toString(); proxy_port = port.toInt64(); Variant user = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_USER); Variant pass = f_parse_url(opts[s_proxy].toString(), k_PHP_URL_PASS); if (!same(user, false) && !same(pass, false)) { proxy_user = user.toString(); proxy_pass = pass.toString(); } } } post_data = opts[s_content].toString(); } if (!headers.exists(s_User_Agent)) { auto default_user_agent = ThreadInfo::s_threadInfo.getNoCheck() ->m_reqInjectionData.getUserAgent(); if (!default_user_agent.empty()) { headers.set(s_User_Agent, default_user_agent); } } auto file = req::make<UrlFile>(method.data(), headers, post_data, max_redirs, timeout, ignore_errors); file->setStreamContext(context); file->setProxy(proxy_host, proxy_port, proxy_user, proxy_pass); bool ret = file->open(filename, mode); if (!ret) { raise_warning("Failed to open %s (%s)", filename.data(), file->getLastError().c_str()); return nullptr; } return file; }
Variant binary_deserialize(int8_t thrift_typeID, PHPInputTransport& transport, const Array& fieldspec) { Variant ret; switch (thrift_typeID) { case T_STOP: case T_VOID: return init_null(); case T_STRUCT: { Variant val; if ((val = fieldspec.rvalAt(PHPTransport::s_class)).isNull()) { throw_tprotocolexception("no class type in spec", INVALID_DATA); skip_element(T_STRUCT, transport); return init_null(); } String structType = val.toString(); ret = createObject(structType); if (ret.isNull()) { // unable to create class entry skip_element(T_STRUCT, transport); return init_null(); } Variant spec = HHVM_FN(hphp_get_static_property)(structType, s_TSPEC, false); if (!spec.is(KindOfArray)) { char errbuf[128]; snprintf(errbuf, 128, "spec for %s is wrong type: %d\n", structType.data(), ret.getType()); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); return init_null(); } binary_deserialize_spec(ret.toObject(), transport, spec.toArray()); return ret; } break; case T_BOOL: { uint8_t c; transport.readBytes(&c, 1); return c != 0; } //case T_I08: // same numeric value as T_BYTE case T_BYTE: { uint8_t c; transport.readBytes(&c, 1); return Variant((int8_t)c); } case T_I16: { uint16_t c; transport.readBytes(&c, 2); return Variant((int16_t)ntohs(c)); } case T_I32: { uint32_t c; transport.readBytes(&c, 4); return Variant((int32_t)ntohl(c)); } case T_U64: case T_I64: { uint64_t c; transport.readBytes(&c, 8); return Variant((int64_t)ntohll(c)); } case T_DOUBLE: { union { uint64_t c; double d; } a; transport.readBytes(&(a.c), 8); a.c = ntohll(a.c); return a.d; } case T_FLOAT: { union { uint32_t c; float d; } a; transport.readBytes(&(a.c), 4); a.c = ntohl(a.c); return a.d; } //case T_UTF7: // aliases T_STRING case T_UTF8: case T_UTF16: case T_STRING: { uint32_t size = transport.readU32(); if (size && (size + 1)) { String s = String(size, ReserveString); char* strbuf = s.mutableData(); transport.readBytes(strbuf, size); s.setSize(size); return s; } else { return empty_string_variant(); } } case T_MAP: { // array of key -> value uint8_t types[2]; transport.readBytes(types, 2); uint32_t size = transport.readU32(); Array keyspec = fieldspec.rvalAt(PHPTransport::s_key, AccessFlags::Error_Key).toArray(); Array valspec = fieldspec.rvalAt(PHPTransport::s_val, AccessFlags::Error_Key).toArray(); String format = fieldspec.rvalAt(PHPTransport::s_format, AccessFlags::None).toString(); if (format.equal(PHPTransport::s_collection)) { ret = newobj<c_Map>(); for (uint32_t s = 0; s < size; ++s) { Variant key = binary_deserialize(types[0], transport, keyspec); Variant value = binary_deserialize(types[1], transport, valspec); collectionSet(ret.getObjectData(), key.asCell(), value.asCell()); } } else { ret = Array::Create(); for (uint32_t s = 0; s < size; ++s) { Variant key = binary_deserialize(types[0], transport, keyspec); Variant value = binary_deserialize(types[1], transport, valspec); ret.toArrRef().set(key, value); } } return ret; // return_value already populated } case T_LIST: { // array with autogenerated numeric keys int8_t type = transport.readI8(); uint32_t size = transport.readU32(); Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key); Array elemspec = elemvar.toArray(); String format = fieldspec.rvalAt(PHPTransport::s_format, AccessFlags::None).toString(); if (format.equal(PHPTransport::s_collection)) { auto const pvec = newobj<c_Vector>(); ret = pvec; for (uint32_t s = 0; s < size; ++s) { Variant value = binary_deserialize(type, transport, elemspec); pvec->t_add(value); } } else { PackedArrayInit pai(size); for (auto s = uint32_t{0}; s < size; ++s) { pai.append(binary_deserialize(type, transport, elemspec)); } ret = pai.toArray(); } return ret; } case T_SET: { // array of key -> TRUE uint8_t type; uint32_t size; transport.readBytes(&type, 1); transport.readBytes(&size, 4); size = ntohl(size); Variant elemvar = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key); Array elemspec = elemvar.toArray(); String format = fieldspec.rvalAt(PHPTransport::s_format, AccessFlags::None).toString(); if (format.equal(PHPTransport::s_collection)) { auto set_ret = makeSmartPtr<c_Set>(); for (uint32_t s = 0; s < size; ++s) { Variant key = binary_deserialize(type, transport, elemspec); if (key.isInteger()) { set_ret->t_add(key); } else { set_ret->t_add(key.toString()); } } ret = Variant(std::move(set_ret)); } else { ArrayInit init(size, ArrayInit::Mixed{}); for (uint32_t s = 0; s < size; ++s) { Variant key = binary_deserialize(type, transport, elemspec); if (key.isInteger()) { init.set(key, true); } else { init.setKeyUnconverted(key, true); } } ret = init.toArray(); } return ret; } }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); return init_null(); }
void binary_serialize(int8_t thrift_typeID, PHPOutputTransport& transport, const Variant& value, const Array& fieldspec) { // At this point the typeID (and field num, if applicable) should've already // been written to the output so all we need to do is write the payload. switch (thrift_typeID) { case T_STOP: case T_VOID: return; case T_STRUCT: { if (!value.is(KindOfObject)) { throw_tprotocolexception("Attempt to send non-object " "type as a T_STRUCT", INVALID_DATA); } binary_serialize_spec(value.toObject(), transport, HHVM_FN(hphp_get_static_property)(value.toObject()-> getClassName(), s_TSPEC, false).toArray()); } return; case T_BOOL: transport.writeI8(value.toBoolean() ? 1 : 0); return; case T_BYTE: transport.writeI8(value.toByte()); return; case T_I16: transport.writeI16(value.toInt16()); return; case T_I32: transport.writeI32(value.toInt32()); return; case T_I64: case T_U64: transport.writeI64(value.toInt64()); return; case T_DOUBLE: { union { int64_t c; double d; } a; a.d = value.toDouble(); transport.writeI64(a.c); } return; case T_FLOAT: { union { int32_t c; float d; } a; a.d = (float)value.toDouble(); transport.writeI32(a.c); } return; //case T_UTF7: case T_UTF8: case T_UTF16: case T_STRING: { String sv = value.toString(); transport.writeString(sv.data(), sv.size()); } return; case T_MAP: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_ktype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_vtype, AccessFlags::Error_Key).toByte(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_val, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_LIST: { Array ht = value.toArray(); Variant val; uint8_t valtype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toInt64(); transport.writeI8(valtype); Array valspec = fieldspec.rvalAt(PHPTransport::s_elem, AccessFlags::Error_Key).toArray(); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize(valtype, transport, key_ptr.second(), valspec); } } return; case T_SET: { Array ht = value.toArray(); uint8_t keytype = fieldspec.rvalAt(PHPTransport::s_etype, AccessFlags::Error_Key).toByte(); transport.writeI8(keytype); transport.writeI32(ht.size()); for (ArrayIter key_ptr = ht.begin(); !key_ptr.end(); ++key_ptr) { binary_serialize_hashtable_key(keytype, transport, key_ptr.first()); } } return; }; char errbuf[128]; sprintf(errbuf, "Unknown thrift typeID %d", thrift_typeID); throw_tprotocolexception(String(errbuf, CopyString), INVALID_DATA); }
bool f_is_callable(CVarRef v, bool syntax /* = false */, Variant name /* = null */) { if (v.isString()) { if (!name.isNull()) name = v; if (syntax) return true; string lowered = Util::toLower((const char *)v.toString()); size_t c = lowered.find("::"); if (c != 0 && c != string::npos && c+2 < lowered.size()) { string classname = lowered.substr(0, c); string methodname = lowered.substr(c+2); return f_call_user_func(2, "class_exists", Array::Create(String(classname))) && ClassInfo::hasAccess(classname, methodname, true, false); } return f_function_exists(v.toString()); } if (v.is(KindOfArray)) { Array arr = v.toArray(); if (arr.size() == 2 && arr.exists(0LL) && arr.exists(1LL)) { Variant v0 = arr.rvalAt(0LL); Variant v1 = arr.rvalAt(1LL); Object obj; bool staticCall = false; if (v0.is(KindOfObject)) { obj = v0.toObject(); v0 = obj->o_getClassName(); } else if (v0.isString()) { if (!f_call_user_func(2, "class_exists", Array::Create(v0))) { return false; } staticCall = true; } if (v1.isString()) { string lowered = Util::toLower((const char *)v1.toString()); size_t c = lowered.find("::"); if (c != 0 && c != string::npos && c+2 < lowered.size()) { string name1 = Util::toLower((const char *)v0.toString()); string name2 = lowered.substr(0, c); if (name1 == name2 || ClassInfo::isSubClass(name1, name2, false)) { staticCall = true; v0 = name2; v1 = lowered.substr(c+2); } } } if (v0.isString() && v1.isString()) { if (!name.isNull()) { name = v0.toString() + "::" + v1.toString(); } if (same(v0, "self") || same(v0, "parent")) { throw NotImplementedException("augmenting class scope info"); } return ClassInfo::hasAccess(v0, v1, staticCall, !obj.isNull()); } } } if (!name.isNull()) { name = v.toString(); } return false; }
bool TestExtApc::test_apc_cache_info() { Array ci = f_apc_cache_info(); VS(ci.rvalAt("start_time"), start_time()); return Count(true); }
bool f_is_callable(CVarRef v, bool syntax /* = false */, Variant name /* = null */) { if (v.isString()) { if (!name.isNull()) name = v; if (syntax) return true; String str = v.toString(); int c = str.find("::"); if (c != 0 && c != String::npos && c + 2 < str.size()) { String classname = str.substr(0, c); String methodname = str.substr(c + 2); return f_class_exists(classname) && ClassInfo::HasAccess(classname, methodname, true, false); } return f_function_exists(str); } if (v.is(KindOfArray)) { Array arr = v.toArray(); if (arr.size() == 2 && arr.exists(0LL) && arr.exists(1LL)) { Variant v0 = arr.rvalAt(0LL); Variant v1 = arr.rvalAt(1LL); Object obj; bool staticCall = false; if (v0.is(KindOfObject)) { obj = v0.toObject(); v0 = obj->o_getClassName(); } else if (v0.isString()) { if (!f_class_exists(v0.toString())) { return false; } staticCall = true; } if (v1.isString()) { String str = v1.toString(); int c = str.find("::"); if (c != 0 && c != String::npos && c + 2 < str.size()) { String name1 = v0.toString(); String name2 = str.substr(0, c); ASSERT(name1.get() && name2.get()); if (name1->isame(name2.get()) || ClassInfo::IsSubClass(name1, name2, false)) { staticCall = true; v0 = name2; v1 = str.substr(c + 2); } } } if (v0.isString() && v1.isString()) { if (!name.isNull()) { name = v0.toString() + "::" + v1.toString(); } if (same(v0, s_self) || same(v0, s_parent)) { throw NotImplementedException("augmenting class scope info"); } return ClassInfo::HasAccess(v0, v1, staticCall, !obj.isNull()); } } } if (!name.isNull()) { name = v.toString(); } return false; }
File* HttpStreamWrapper::open(const String& filename, const String& mode, int options, const Variant& context) { if (RuntimeOption::ServerHttpSafeMode) { return nullptr; } if (strncmp(filename.data(), "http://", sizeof("http://") - 1) && strncmp(filename.data(), "https://", sizeof("https://") - 1)) { return nullptr; } std::unique_ptr<UrlFile> file; StreamContext *ctx = !context.isResource() ? nullptr : context.toResource().getTyped<StreamContext>(); Array headers; String method = s_GET; String post_data = null_string; int max_redirs = 20; int timeout = -1; bool ignore_errors = false; if (ctx && !ctx->getOptions().isNull() && !ctx->getOptions()[s_http].isNull()) { Array opts = ctx->getOptions()[s_http].toArray(); if (opts.exists(s_method)) { method = opts[s_method].toString(); } if (opts.exists(s_header)) { Array lines; if (opts[s_header].isString()) { lines = StringUtil::Explode( opts[s_header].toString(), "\r\n").toArray(); } else if (opts[s_header].isArray()) { lines = opts[s_header]; } for (ArrayIter it(lines); it; ++it) { Array parts = StringUtil::Explode( it.second().toString(), ":").toArray(); headers.set(parts.rvalAt(0), parts.rvalAt(1)); } } if (opts.exists(s_user_agent) && !headers.exists(s_User_Agent)) { headers.set(s_User_Agent, opts[s_user_agent]); } if (opts.exists(s_max_redirects)) { max_redirs = opts[s_max_redirects].toInt64(); } if (opts.exists(s_timeout)) { timeout = opts[s_timeout].toInt64(); } if (opts.exists(s_ignore_errors)) { ignore_errors = opts[s_ignore_errors].toBoolean(); } post_data = opts[s_content].toString(); } if (!headers.exists(s_User_Agent)) { auto default_user_agent = ThreadInfo::s_threadInfo.getNoCheck() ->m_reqInjectionData.getUserAgent(); if (!default_user_agent.empty()) { headers.set(s_User_Agent, default_user_agent); } } file = std::unique_ptr<UrlFile>(newres<UrlFile>(method.data(), headers, post_data, max_redirs, timeout, ignore_errors)); bool ret = file->open(filename, mode); if (!ret) { raise_warning("Failed to open %s (%s)", filename.data(), file->getLastError().c_str()); return nullptr; } return file.release(); }
// This function takes an array of arrays, each of which is of the // form array($dbh, ...). The only thing that matters in the inner // arrays is the first element being a MySQL instance. It then // procedes to block for up to 'timeout' seconds, waiting for the // first actionable descriptor(s), which it then returns in the form // of the original arrays passed in. The intention is the caller // would include other information they care about in the tail of the // array so they can decide how to act on the // potentially-now-queryable descriptors. // // This function is a poor shadow of how the async library can be // used; for more complex cases, we'd use libevent and share our event // loop with other IO operations such as memcache ops, thrift calls, // etc. That said, this function is reasonably efficient for most use // cases. Variant f_mysql_async_wait_actionable(CVarRef items, double timeout) { size_t count = items.toArray().size(); if (count == 0 || timeout < 0) { return Array::Create(); } struct pollfd* fds = (struct pollfd*)calloc(count, sizeof(struct pollfd)); SCOPE_EXIT { free(fds); }; // Walk our input, determine what kind of poll() operation is // necessary for the descriptor in question, and put an entry into // fds. int nfds = 0; for (ArrayIter iter(items.toArray()); iter; ++iter) { Array entry = iter.second().toArray(); if (entry.size() < 1) { raise_warning("element %d did not have at least one entry", nfds); return Array::Create(); } MySQL* mySQL = entry.rvalAt(0).toResource().getTyped<MySQL>(); MYSQL* conn = mySQL->get(); if (conn->async_op_status == ASYNC_OP_UNSET) { raise_warning("runtime/ext_mysql: no pending async operation in " "progress"); return Array::Create(); } pollfd* fd = &fds[nfds++]; fd->fd = mysql_get_file_descriptor(conn); if (conn->net.async_blocking_state == NET_NONBLOCKING_READ) { fd->events = POLLIN; } else { fd->events = POLLOUT; } fd->revents = 0; } // The poll itself; either the timeout is hit or one or more of the // input fd's is ready. int timeout_millis = static_cast<long>(timeout * 1000); int res = poll(fds, nfds, timeout_millis); if (res == -1) { raise_warning("unable to poll [%d]: %s", errno, folly::errnoStr(errno).c_str()); return Array::Create(); } // Now just find the ones that are ready, and copy the corresponding // arrays from our input array into our return value. Array ret = Array::Create(); nfds = 0; for (ArrayIter iter(items.toArray()); iter; ++iter) { Array entry = iter.second().toArray(); if (entry.size() < 1) { raise_warning("element %d did not have at least one entry", nfds); return Array::Create(); } MySQL* mySQL = entry.rvalAt(0).toResource().getTyped<MySQL>(); MYSQL* conn = mySQL->get(); pollfd* fd = &fds[nfds++]; if (fd->fd != mysql_get_file_descriptor(conn)) { raise_warning("poll returned events out of order wtf"); continue; } if (fd->revents != 0) { ret.append(iter.second()); } } return ret; }