Example #1
0
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();
}
Example #3
0
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());
}
Example #4
0
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();
}
Example #7
0
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);
  }
}
Example #9
0
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();
}
Example #10
0
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;
}
Example #12
0
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;
}
Example #13
0
//////////////////////////////////////////////////////////////////////////////
// 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());
  }
}
Example #14
0
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;
}
Example #15
0
  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);
  }
Example #17
0
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;
}
Example #18
0
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();
}
Example #19
0
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);
}
Example #20
0
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;
}
Example #21
0
bool TestExtApc::test_apc_cache_info() {
  Array ci = f_apc_cache_info();
  VS(ci.rvalAt("start_time"), start_time());
  return Count(true);
}
Example #22
0
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;
}
Example #23
0
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();
}
Example #24
0
// 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;
}