Пример #1
0
Variant f_constant(CStrRef name) {
  if (!name.get()) return null;
  const char *data = name.data();
  int len = name.length();
  char *colon;
  if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') {
    // class constant
    int classNameLen = colon - data;
    char *constantName = colon + 2;
    String className(data, classNameLen, CopyString);

    // translate "self" or "parent"
    if (className == "self") {
      String this_class = hhvm
        ? g_vmContext->getContextClassName()
        : FrameInjection::GetClassName(true);
      if (this_class.empty()) {
        throw FatalErrorException("Cannot access self:: "
                                  "when no class scope is active");
      } else {
        className = this_class;
      }
    } else if (className == "parent") {
      String parent_class = hhvm
        ? g_vmContext->getParentContextClassName()
        : FrameInjection::GetParentClassName(true);
      if (parent_class.empty()) {
        throw FatalErrorException("Cannot access parent");
      } else {
        className = parent_class;
      }
    }
    // taking care of volatile class
    if (class_exists(className)) {
      return get_class_constant(className, constantName, false);
    } else {
      return null;
    }
  } else {
    if (hhvm) {
      TypedValue* cns = g_vmContext->getCns(name.get());
      if (cns == NULL) {
        if (AutoloadHandler::s_instance->autoloadConstant(name)) {
          cns = g_vmContext->getCns(name.get());
        }
      }
      if (cns) return tvAsVariant(cns);
      return null;
    } else {
      const ClassInfo::ConstantInfo *cinfo = ClassInfo::FindConstant(name);
      // system/uniquely defined scalar constant (must be valid)
      if (cinfo) return cinfo->getValue();
      if (!((Globals*)get_global_variables())->defined(name)) {
        AutoloadHandler::s_instance->autoloadConstant(name);
      }
      // dynamic/redeclared constant
      return ((Globals*)get_global_variables())->getConstant(name.data());
    }
  }
}
Пример #2
0
void XDebugProfiler::writeProfilingResults() {
  // If we're appending to the file, start a new section
  if (m_profilingOpts & k_XDEBUG_PROFILE_APPEND) {
    fprintf(m_profilingFile, "\n==== NEW PROFILING FILE ======================="
                             "=======================\n");
  }

  // Grab $_SERVER['SCRIPT_NAME'] so we can match xdebug %s filename format
  // option
  Array server = get_global_variables()->asArrayData()->get(s_SERVER).toArray();
  const char* scriptname = server[s_SCRIPT_NAME].toString().data();

  // Print the header and body
  fprintf(m_profilingFile, "version: 1\ncreator: xdebug %s\n", XDEBUG_VERSION);
  fprintf(m_profilingFile, "cmd: %s\npart: 1\npositions: line\n\n", scriptname);
  fprintf(m_profilingFile, "events: Time\n\n");
  if (m_frameBufferSize > 0 && writeProfilingFrame(0) < 0) {
    fprintf(stderr, "Error when writing xdebug profiling file %s. Frame buffer "
                    "invalid.", m_profilingFilename.data());
  }

  // Cleanup
  m_profilingEnabled = false;
  fclose(m_profilingFile);
}
Пример #3
0
void DummySandbox::run() {
  while (!m_stopped) {
    try {
      char *argv[] = {"", NULL};
      execute_command_line_begin(1, argv, 0);

      DECLARE_THREAD_INFO;
      FRAME_INJECTION_FLAGS(empty_string, _, FrameInjection::PseudoMain);

      DSandboxInfo sandbox = m_proxy->getSandbox();
      string msg;
      if (m_inited) {
        SystemGlobals *g = (SystemGlobals *)get_global_variables();
        SourceRootInfo sri(sandbox.m_user, sandbox.m_name);
        if (sandbox.m_path.empty()) {
          sandbox.m_path = sri.path();
        }
        if (!sri.sandboxOn()) {
          msg = "Invalid sandbox was specified. "
            "PHP files may not be loaded properly.\n";
          // force HPHP_SANDBOX_ID to be set, so we can still talk to client
          g->GV(_SERVER).set("HPHP_SANDBOX_ID", sandbox.id());
        } else {
          sri.setServerVariables(g->GV(_SERVER));
        }

        std::string doc = getStartupDoc(sandbox);
        bool error; string errorMsg;
        bool ret = hphp_invoke(g_context.get(), doc, false, null_array, null,
                               "", "", "", error, errorMsg);
        if (!ret || error) {
          msg += "Unable to pre-load " + doc;
          if (!errorMsg.empty()) {
            msg += ": " + errorMsg;
          }
        }
      }

      m_inited = true;
      Debugger::RegisterSandbox(sandbox);
      Debugger::InterruptSessionStarted(NULL, msg.c_str());

      // Blocking until Ctrl-C is issued by end user and DebuggerProxy cannot
      // find a real sandbox thread to handle it.
      {
        Lock lock(this);
        while (!m_stopped && m_signum != CmdSignal::SignalBreak) {
          wait(1);
        }
        m_signum = CmdSignal::SignalNone;
      }
    } catch (const DebuggerException &e) {}
    execute_command_line_end(0, false, NULL);
  }
}
Пример #4
0
string& SourceRootInfo::initPhpRoot() {
  SystemGlobals *g = (SystemGlobals*)get_global_variables();
  Variant &server = g->GV(_SERVER);
  Variant v = server.rvalAt("PHP_ROOT");
  if (v.isString()) {
    *s_phproot.getCheck() = string(v.asCStrRef().data()) + string("/");
  } else {
    // Our best guess at the source root.
    *s_phproot.getCheck() = GetCurrentSourceRoot();
  }
  return *s_phproot.getCheck();
}
string& SourceRootInfo::initPhpRoot() {
  GlobalVariables *g = get_global_variables();
  CVarRef server = g->get(s_SERVER);
  CVarRef v = server.rvalAt(s_PHP_ROOT);
  if (v.isString()) {
    *s_phproot.getCheck() = string(v.asCStrRef().data()) + string("/");
  } else {
    // Our best guess at the source root.
    *s_phproot.getCheck() = GetCurrentSourceRoot();
  }
  return *s_phproot.getCheck();
}
Пример #6
0
bool XDebugServer::isNeeded() {
  if (!XDEBUG_GLOBAL(RemoteEnable) ||
      XDEBUG_GLOBAL(RemoteMode) == "jit") {
    return false;
  } else if (XDEBUG_GLOBAL(RemoteAutostart)) {
    return true;
  } else {
    // Check $_COOKIE[XDEBUG_SESSION]
    const ArrayData* globals = get_global_variables()->asArrayData();
    Array cookie = globals->get(s_COOKIE).toArray();
    return !cookie[s_SESSION].isNull();
  }
}
Пример #7
0
bool UrlFile::open(CStrRef url, CStrRef mode) {
  const char* modestr = mode.c_str();
  if (strchr(modestr, '+') || strchr(modestr, 'a') || strchr(modestr, 'w')) {
    std::string msg = "cannot open a url stream for write/append operation: ";
    msg += url.c_str();
    m_error = msg;
    return false;
  }
  HttpClient http(m_timeout, m_maxRedirect);
  m_response.reset();

  HeaderMap *pHeaders = nullptr;
  HeaderMap requestHeaders;
  if (!m_headers.empty()) {
    pHeaders = &requestHeaders;
    for (ArrayIter iter(m_headers); iter; ++iter) {
      requestHeaders[string(iter.first().toString().data())].
        push_back(iter.second().toString().data());
    }
  }

  int code;
  vector<String> responseHeaders;
  if (m_get) {
    code = http.get(url.c_str(), m_response, pHeaders, &responseHeaders);
  } else {
    code = http.post(url.c_str(), m_postData.data(), m_postData.size(),
                     m_response, pHeaders, &responseHeaders);
  }

  SystemGlobals *g = (SystemGlobals*)get_global_variables();
  Variant &r = g->GV(http_response_header);
  r = Array::Create();
  for (unsigned int i = 0; i < responseHeaders.size(); i++) {
    r.append(responseHeaders[i]);
  }
  m_responseHeaders = r;

  if (code == 200) {
    m_name = (std::string) url;
    m_data = const_cast<char*>(m_response.data());
    m_len = m_response.size();
    return true;
  } else {
    m_error = http.getLastError().c_str();
    return false;
  }
}
Пример #8
0
bool UrlFile::open(CStrRef url, CStrRef mode) {
  if (strchr(mode, '+') || strchr(mode, 'a') || strchr(mode, 'w')) {
    string msg("cannot open a url stream for write/append operation: ");
    msg += url.c_str();
    raise_warning(msg.c_str());
    return false;
  }
  HttpClient http(m_timeout, m_maxRedirect);
  StringBuffer response;

  HeaderMap *pHeaders = NULL;
  HeaderMap requestHeaders;
  if (!m_headers.empty()) {
    pHeaders = &requestHeaders;
    for (ArrayIter iter(m_headers); iter; ++iter) {
      requestHeaders[string(iter.first().toString().data())].
        push_back(iter.second().toString().data());
    }
  }

  int code;
  vector<String> responseHeaders;
  if (m_get) {
    code = http.get(url.c_str(), response, pHeaders, &responseHeaders);
  } else {
    code = http.post(url.c_str(), m_postData.data(), m_postData.size(),
                     response, pHeaders, &responseHeaders);
  }

  SystemGlobals *g = (SystemGlobals*)get_global_variables();
  Variant &r = g->gv_http_response_header;
  r = Array::Create();
  for (unsigned int i = 0; i < responseHeaders.size(); i++) {
    r.append(responseHeaders[i]);
  }

  if (code == 200) {
    int len = m_len;
    m_name = url;
    m_data = response.detach(len);
    m_len = len;
    m_malloced = true;
    return true;
  } else {
    return false;
  }
}
Пример #9
0
void XDebugServer::onRequestInit() {
  if (!XDEBUG_GLOBAL(RemoteEnable)) {
    return;
  }

  // Need to turn on debugging regardless of the remote mode in order to
  // capture exceptions/errors
  if (!DebugHookHandler::attach<XDebugHookHandler>()) {
    raise_warning("Could not attach xdebug remote debugger to the current "
                  "thread. A debugger is already attached.");
    return;
  }

  // Grab $_GET, $_COOKIE, and the transport
  const ArrayData* globals = get_global_variables()->asArrayData();
  Array get = globals->get(s_GET).toArray();
  Array cookie = globals->get(s_COOKIE).toArray();
  Transport* transport = g_context->getTransport();

  // Need to check $_GET[XDEBUG_SESSION_STOP]. If set, delete the session
  // cookie
  const Variant sess_stop_var = get[s_SESSION_STOP];
  if (!sess_stop_var.isNull()) {
    cookie.set(s_SESSION, init_null());
    if (transport != nullptr) {
      transport->setCookie(s_SESSION, empty_string());
    }
  }

  // Need to check $_GET[XDEBUG_SESSION_START]. If set, store the session
  // cookie with $_GET[XDEBUG_SESSION_START] as the value
  const Variant sess_start_var = get[s_SESSION_START];
  if (sess_start_var.isString()) {
    String sess_start = sess_start_var.toString();
    cookie.set(s_SESSION,  sess_start);
    if (transport != nullptr) {
      int64_t expire = XDEBUG_GLOBAL(RemoteCookieExpireTime);
      if (expire > 0) {
        timespec ts;
        Timer::GetRealtimeTime(ts);
        expire += ts.tv_sec;
      }
      transport->setCookie(s_SESSION, sess_start, expire);
    }
  }
}
Пример #10
0
void XDebugServer::onRequestInit() {
  if (!XDEBUG_GLOBAL(RemoteEnable)) {
    return;
  }

  // TODO(#4489053) Enable this when debugger internals have been refactored
  // Need to turn on debugging regardless of the remote mode in order to
  // capture exceptions/errors
  // ThreadInfo *ti = ThreadInfo::s_threadInfo.getNoCheck();
  // ti->m_reqInjectionData.setDebugger(true);

  // Grab $_GET, $_COOKIE, and the transport
  const ArrayData* globals = get_global_variables()->asArrayData();
  Array get = globals->get(s_GET).toArray();
  Array cookie = globals->get(s_COOKIE).toArray();
  Transport* transport = g_context->getTransport();

  // Need to check $_GET[XDEBUG_SESSION_STOP]. If set, delete the session
  // cookie
  const Variant sess_stop_var = get[s_SESSION_STOP];
  if (!sess_stop_var.isNull()) {
    cookie.set(s_SESSION, init_null());
    if (transport != nullptr) {
      transport->setCookie(s_SESSION, empty_string());
    }
  }

  // Need to check $_GET[XDEBUG_SESSION_START]. If set, store the session
  // cookie with $_GET[XDEBUG_SESSION_START] as the value
  const Variant sess_start_var = get[s_SESSION_START];
  if (sess_start_var.isString()) {
    String sess_start = sess_start_var.toString();
    cookie.set(s_SESSION,  sess_start);
    if (transport != nullptr) {
      transport->setCookie(s_SESSION,
                           sess_start,
                           XDEBUG_GLOBAL(RemoteCookieExpireTime));
    }
  }
}
Пример #11
0
Variant invoke_file(CStrRef path, bool once /* = false */,
                    LVariableTable* variables /* = NULL */,
                    const char *currentDir /* = NULL */) {
  String cmd = canonicalize_path(path, "", 0);
  if (path == "string") {
    echo("Hello, world!");
    return true;
  }
  if (cmd == "pageletserver") {
    SystemGlobals *g = (SystemGlobals*)get_global_variables();

    echo("pagelet postparam: ");
    echo(g->GV(HTTP_RAW_POST_DATA));
    echo("pagelet getparam: ");
    echo(g->GV(_GET)["getparam"]);
    echo("pagelet header: ");
    echo(g->GV(_SERVER)["HTTP_MYHEADER"]);
    f_header("ResponseHeader: okay");

    sleep(1); // give status check time to happen
    return true;
  }
  return false;
}
Пример #12
0
Array f_getopt(CStrRef options, CVarRef longopts /* = null_variant */) {
  opt_struct *opts, *orig_opts;
  int len = parse_opts(options.data(), options.size(), &opts);

  if (!longopts.isNull()) {
    Array arropts = longopts.toArray();
    int count = arropts.size();

    /* the first <len> slots are filled by the one short ops
     * we now extend our array and jump to the new added structs */
    opts = (opt_struct *)realloc(opts, sizeof(opt_struct) * (len + count + 1));
    orig_opts = opts;
    opts += len;

    memset(opts, 0, count * sizeof(opt_struct));

    for (ArrayIter iter(arropts); iter; ++iter) {
      String entry = iter.second().toString();

      opts->need_param = 0;
      opts->opt_name = strdup(entry.data());
      len = strlen(opts->opt_name);
      if ((len > 0) && (opts->opt_name[len - 1] == ':')) {
        opts->need_param++;
        opts->opt_name[len - 1] = '\0';
        if ((len > 1) && (opts->opt_name[len - 2] == ':')) {
          opts->need_param++;
          opts->opt_name[len - 2] = '\0';
        }
      }
      opts->opt_char = 0;
      opts++;
    }
  } else {
    opts = (opt_struct*) realloc(opts, sizeof(opt_struct) * (len + 1));
    orig_opts = opts;
    opts += len;
  }

  /* php_getopt want to identify the last param */
  opts->opt_char   = '-';
  opts->need_param = 0;
  opts->opt_name   = NULL;

  static const StaticString s_argv("argv");
  GlobalVariables *g = get_global_variables();
  Array vargv = g->get(s_argv).toArray();
  int argc = vargv.size();
  char **argv = (char **)malloc((argc+1) * sizeof(char*));
  vector<String> holders;
  int index = 0;
  for (ArrayIter iter(vargv); iter; ++iter) {
    String arg = iter.second().toString();
    holders.push_back(arg);
    argv[index++] = (char*)arg.data();
  }
  argv[index] = NULL;

  Array ret = Array::Create();

  /* after our pointer arithmetic jump back to the first element */
  opts = orig_opts;

  int o;
  char *php_optarg = NULL;
  int php_optind = 1;

  Variant val;
  int optchr = 0;
  int dash = 0; /* have already seen the - */
  char opt[2] = { '\0' };
  char *optname;
  int optname_len = 0;
  int php_optidx;
  while ((o = php_getopt(argc, argv, opts, &php_optarg, &php_optind, 0, 1,
                         optchr, dash, php_optidx))
         != -1) {
    /* Skip unknown arguments. */
    if (o == '?') {
      continue;
    }

    /* Prepare the option character and the argument string. */
    if (o == 0) {
      optname = opts[php_optidx].opt_name;
    } else {
      if (o == 1) {
        o = '-';
      }
      opt[0] = o;
      optname = opt;
    }

    if (php_optarg != NULL) {
      /* keep the arg as binary, since the encoding is not known */
      val = String(php_optarg, CopyString);
    } else {
      val = false;
    }

    /* Add this option / argument pair to the result hash. */
    optname_len = strlen(optname);
    if (!(optname_len > 1 && optname[0] == '0') &&
        is_numeric_string(optname, optname_len, NULL, NULL, 0) ==
        KindOfInt64) {
      /* numeric string */
      int optname_int = atoi(optname);
      if (ret.exists(optname_int)) {
        Variant &e = ret.lvalAt(optname_int);
        if (!e.isArray()) {
          ret.set(optname_int, CREATE_VECTOR2(e, val));
        } else {
          e.append(val);
        }
      } else {
        ret.set(optname_int, val);
      }
    } else {
      /* other strings */
      String key(optname, strlen(optname), CopyString);
      if (ret.exists(key)) {
        Variant &e = ret.lvalAt(key);
        if (!e.isArray()) {
          ret.set(key, CREATE_VECTOR2(e, val));
        } else {
          e.append(val);
        }
      } else {
        ret.set(key, val);
      }
    }

    php_optarg = NULL;
  }

  free_longopts(orig_opts);
  free(orig_opts);
  free(argv);
  return ret;
}
Пример #13
0
void DummySandbox::run() {
  TRACE(2, "DummySandbox::run\n");
  ThreadInfo *ti = ThreadInfo::s_threadInfo.getNoCheck();
  Debugger::RegisterThread();
  while (!m_stopped) {
    try {
      CLISession hphpSession;

      DSandboxInfo sandbox = m_proxy->getSandbox();
      string msg;
      if (sandbox.valid()) {
        GlobalVariables *g = get_global_variables();
        SourceRootInfo sri(sandbox.m_user, sandbox.m_name);
        if (sandbox.m_path.empty()) {
          sandbox.m_path = sri.path();
        }
        if (!sri.sandboxOn()) {
          msg = "Invalid sandbox was specified. "
            "PHP files may not be loaded properly.\n";
        } else {
          sri.setServerVariables(g->getRef(s__SERVER));
        }
        Debugger::RegisterSandbox(sandbox);
        g_context->setSandboxId(sandbox.id());

        std::string doc = getStartupDoc(sandbox);
        if (!doc.empty()) {
          char cwd[PATH_MAX];
          getcwd(cwd, sizeof(cwd));
          Logger::Info("Start loading startup doc '%s', pwd = '%s'",
                       doc.c_str(), cwd);
          bool error; string errorMsg;
          bool ret = hphp_invoke(g_context.getNoCheck(), doc, false, null_array,
                                 uninit_null(), "", "", error, errorMsg, true,
                                 false, true);
          if (!ret || error) {
            msg += "Unable to pre-load " + doc;
            if (!errorMsg.empty()) {
              msg += ": " + errorMsg;
            }
          }
          Logger::Info("Startup doc " + doc + " loaded");
        }
      } else {
        g_context->setSandboxId(m_proxy->getDummyInfo().id());
      }

      ti->m_reqInjectionData.setDebugger(true);
      {
        DebuggerDummyEnv dde;
        // This is really the entire point of having the dummy sandbox. This
        // fires the initial session started interrupt to the client after
        // it first attaches.
        Debugger::InterruptSessionStarted(nullptr, msg.c_str());
      }

      // Blocking until Ctrl-C is issued by end user and DebuggerProxy cannot
      // find a real sandbox thread to handle it.
      {
        Lock lock(this);
        while (!m_stopped && m_signum != CmdSignal::SignalBreak) {
          wait(1);
        }
        if (m_stopped) {
          // stopped by worker thread
          break;
        }
        m_signum = CmdSignal::SignalNone;
      }
    } catch (const DebuggerClientExitException &e) {
      // stopped by the dummy sandbox thread itself
      break;
    } catch (const DebuggerException &e) {
    }
  }
}
Пример #14
0
// Helper used to create an absolute filename using the passed
// directory and xdebug-specific format string
static String format_filename(folly::StringPiece dir,
                              folly::StringPiece formatFile,
                              bool addSuffix) {
  // Create a string buffer and append the directory name
  auto const formatlen = formatFile.size();
  StringBuffer buf(formatlen * 2); // Slightly larger than formatlen
  if (!dir.empty()) {
    buf.append(dir);
    buf.append('/');
  }

  // Append the filename
  auto globals = get_global_variables()->asArrayData();
  for (int pos = 0; pos < formatlen; pos++) {
    auto c = formatFile[pos];
    if (c != '%' || pos + 1 == formatlen) {
      buf.append(c);
      continue;
    }

    c = formatFile[++pos];
    switch (c) {
      // crc32 of current working directory
      case 'c': {
        auto const crc32 = HHVM_FN(crc32)(g_context->getCwd());
        buf.append(crc32);
        break;
      }
      // process id
      case 'p':
        buf.append(getpid());
        break;
      // Random number
      case 'r':
        buf.printf("%lx", (long)HHVM_FN(rand)());
        break;
      // Script name
      case 's': {
        auto server = globals->get(s_SERVER).toArray();
        if (server.exists(s_SCRIPT_NAME) && server[s_SCRIPT_NAME].isString()) {
          const String scriptname(server[s_SCRIPT_NAME].toString(), CopyString);
          replace_special_chars(scriptname.get());
          buf.append(scriptname);
        }
        break;
      }
      // Timestamp (seconds)
      case 't': {
        auto const sec = (int64_t)time(nullptr);
        if (sec != -1) {
          buf.append(sec);
        }
        break;
      }
      // Timestamp (microseconds)
      case 'u': {
        struct timeval tv;
        if (gettimeofday(&tv, 0) != -1) {
          buf.printf("%ld_%ld", long(tv.tv_sec), long(tv.tv_usec));
        }
        break;
      }
      // $_SERVER['HTTP_HOST']
      case 'H': {
        Array server = globals->get(s_SERVER).toArray();
        if (server.exists(s_HTTP_HOST) && server[s_HTTP_HOST].isString()) {
          const String hostname(server[s_HTTP_HOST].toString(), CopyString);
          replace_special_chars(hostname.get());
          buf.append(hostname);
        }
        break;
      }
      // $_SERVER['REQUEST_URI']
      case 'R': {
        auto server = globals->get(s_SERVER).toArray();
        if (globals->exists(s_REQUEST_URI)) {
          const String requri(server[s_REQUEST_URI].toString(), CopyString);
          replace_special_chars(requri.get());
          buf.append(requri);
        }
        break;
      }
      // $_SERVER['UNIQUE_ID']
      case 'U': {
        auto server = globals->get(s_SERVER).toArray();
        if (server.exists(s_UNIQUE_ID) && server[s_UNIQUE_ID].isString()) {
          const String uniqueid(server[s_UNIQUE_ID].toString(), CopyString);
          replace_special_chars(uniqueid.get());
          buf.append(uniqueid);
        }
        break;
      }
      // session id
      case 'S': {
        // First we grab the session name from the ini settings, then the id
        // from the cookies
        String session_name;
        if (IniSetting::Get(s_SESSION_NAME, session_name)) {
          auto cookies = globals->get(s_COOKIE).toArray();
          if (cookies.exists(session_name) &&
              cookies[session_name].isString()) {
            const String sessionstr(cookies[session_name].toString(),
                                    CopyString);
            replace_special_chars(sessionstr.get());
            buf.append(sessionstr);
          }
          break;
        }
      }
      // Literal
      case '%':
        buf.append('%');
        break;
      default:
        buf.append('%');
        buf.append(c);
        break;
    }
  }

  // Optionally add .xt file extension
  if (addSuffix) {
    buf.append(".xt");
  }
  return buf.copy();
}
Пример #15
0
void init_global_variables() {
  ThreadInfo::s_threadInfo->m_globals = get_global_variables();
  GlobalVariables::initialize();
}
Пример #16
0
void DummySandbox::run() {
  ThreadInfo *ti = ThreadInfo::s_threadInfo.getNoCheck();
  Debugger::RegisterThread();
  ti->m_reqInjectionData.dummySandbox = true;
  while (!m_stopped) {
    try {
      CLISession hphpSession;
      FUNCTION_INJECTION_FS("_", FrameInjection::PseudoMain);

      DSandboxInfo sandbox = m_proxy->getSandbox();
      string msg;
      if (sandbox.valid()) {
        SystemGlobals *g = (SystemGlobals *)get_global_variables();
        SourceRootInfo sri(sandbox.m_user, sandbox.m_name);
        if (sandbox.m_path.empty()) {
          sandbox.m_path = sri.path();
        }
        if (!sri.sandboxOn()) {
          msg = "Invalid sandbox was specified. "
            "PHP files may not be loaded properly.\n";
        } else {
          sri.setServerVariables(g->GV(_SERVER));
        }
        Debugger::RegisterSandbox(sandbox);
        g_context->setSandboxId(sandbox.id());

        Logger::Info("Start loading startup doc");
        std::string doc = getStartupDoc(sandbox);
        bool error; string errorMsg;
        bool ret = hphp_invoke(g_context.getNoCheck(), doc, false, null_array,
                               null, "", "", error, errorMsg, true, false,
                               true);
        if (!ret || error) {
          msg += "Unable to pre-load " + doc;
          if (!errorMsg.empty()) {
            msg += ": " + errorMsg;
          }
        }
        Logger::Info("Startup doc " + doc + " loaded");
      } else {
        g_context->setSandboxId(m_proxy->getDummyInfo().id());
      }

      ti->m_reqInjectionData.debugger = true;
      {
        DebuggerDummyEnv dde;
        Debugger::InterruptSessionStarted(NULL, msg.c_str());
      }

      // Blocking until Ctrl-C is issued by end user and DebuggerProxy cannot
      // find a real sandbox thread to handle it.
      {
        Lock lock(this);
        while (!m_stopped && m_signum != CmdSignal::SignalBreak) {
          wait(1);
        }
        if (m_stopped) {
          // stopped by worker thread
          break;
        }
        m_signum = CmdSignal::SignalNone;
      }
    } catch (const DebuggerClientExitException &e) {
      // stopped by the dummy sandbox thread itself
      break;
    } catch (const DebuggerException &e) {
    }
  }
}
Globals*        get_globals()        { return get_global_variables(); }
Пример #18
0
bool XDebugServer::initDbgp() {
  // Initialize the status and reason
  switch (m_mode) {
    case Mode::REQ:
      setStatus(Status::Starting, Reason::Ok);
      break;
    case Mode::JIT:
      setStatus(Status::Break, Reason::Error);
      break;
  }
  // Create the response
  auto response = xdebug_xml_node_init("init");
  addXmlns(*response);

  // Add the engine info
  auto child = xdebug_xml_node_init("engine");
  xdebug_xml_add_attribute(child, "version", XDEBUG_VERSION);
  xdebug_xml_add_text(child, XDEBUG_NAME, 0);
  xdebug_xml_add_child(response, child);

  // Add the author
  child = xdebug_xml_node_init("author");
  xdebug_xml_add_text(child, XDEBUG_AUTHOR, 0);
  xdebug_xml_add_child(response, child);

  // Add the url
  child = xdebug_xml_node_init("url");
  xdebug_xml_add_text(child, XDEBUG_URL, 0);
  xdebug_xml_add_child(response, child);

  // Add the copyright
  child = xdebug_xml_node_init("copyright");
  xdebug_xml_add_text(child, XDEBUG_COPYRIGHT, 0);
  xdebug_xml_add_child(response, child);

  // Grab the absolute path of the script filename
  auto globals = get_global_variables()->asArrayData();
  Variant scriptname_var = globals->get(s_SERVER).toArray()[s_SCRIPT_FILENAME];
  assert(scriptname_var.isString());
  auto scriptname = scriptname_var.toString().get()->mutableData();
  auto fileuri = XDebugUtils::pathToUrl(scriptname);

  // Add attributes to the root init node
  xdebug_xml_add_attribute_ex(response, "fileuri", fileuri, 0, 1);
  xdebug_xml_add_attribute(response, "language", "PHP");
  xdebug_xml_add_attribute(response, "protocol_version", DBGP_VERSION);
  xdebug_xml_add_attribute(response, "appid", getpid());

  // Add the DBGP_COOKIE environment variable
  const String dbgp_cookie = g_context->getenv(s_DBGP_COOKIE);
  if (!dbgp_cookie.empty()) {
    xdebug_xml_add_attribute(response, "session", dbgp_cookie.data());
  }

  // Add the idekey
  if (XDEBUG_GLOBAL(IdeKey).size() > 0) {
    xdebug_xml_add_attribute(response, "idekey", XDEBUG_GLOBAL(IdeKey).c_str());
  }

  // Sent the response
  sendMessage(*response);
  xdebug_xml_node_dtor(response);

  // Wait for a response from the client
  return doCommandLoop();
}
Пример #19
0
void init_global_variables() {
  GlobalVariables *g = get_global_variables();
  ThreadInfo::s_threadInfo->m_globals = g;
  g->initialize();
}
Пример #20
0
XDebugServer::XDebugServer(Mode mode) : m_mode(mode) {
  // Attempt to open optional log file
  if (XDEBUG_GLOBAL(RemoteLog).size() > 0) {
    m_logFile = fopen(XDEBUG_GLOBAL(RemoteLog).c_str(), "a");
    if (m_logFile == nullptr) {
      raise_warning("XDebug could not open the remote debug file '%s'.",
                    XDEBUG_GLOBAL(RemoteLog).c_str());
    }

    log("Log opened at");
    XDebugUtils::fprintTimestamp(m_logFile);
    log("\n");
    logFlush();
  }

  // Grab the hostname and port to connect to
  const char* hostname = XDEBUG_GLOBAL(RemoteHost).c_str();
  int port = XDEBUG_GLOBAL(RemotePort);
  if (XDEBUG_GLOBAL(RemoteConnectBack)) {
    const ArrayData* globals = get_global_variables()->asArrayData();
    Array server = globals->get(s_SERVER).toArray();
    log("I: Checking remote connect back address.\n");

    // Grab $_SERVER[HTTP_X_FORWARDED_FOR] then $_SERVER[REMOTE_ADDR]
    bool host_found = true;
    if (server[s_HTTP_X_FORWARDED_FOR].isString()) {
      hostname = server[s_HTTP_X_FORWARDED_FOR].toString().data();
    } else if (server[s_REMOTE_ADDR].isString()) {
      hostname = server[s_REMOTE_ADDR].toString().data();
    } else {
      host_found = false;
    }

    // Did we find a host?
    if (host_found) {
      log("I: Remote address found, connecting to %s:%d.\n", hostname, port);
    } else {
      log("W: Remote address not found, connecting to configured address/port: "
          "%s:%d. :-|\n", hostname, port);
    }
  } else {
    log("I: Connecting to configured address/port: %s:%d.\n", hostname, port);
  }

  // Create the socket
  m_socket = createSocket(hostname, port);
  if (m_socket == -1) {
    log("E: Could not connect to client. :-(\n");
    goto failure;
  } else if (m_socket == -2) {
    log("E: Time-out connecting to client. :-(\n");
    goto failure;
  }

  // Get the requested handler
  log("I: Connected to client. :-)\n");
  if (XDEBUG_GLOBAL(RemoteHandler) != "dbgp") {
    log("E: The remote debug handler '%s' is not supported. :-(\n",
        XDEBUG_GLOBAL(RemoteHandler).c_str());
    goto failure;
  }

  // php5 xdebug has an error case here, but initializing the dbgp handler never
  // actually fails
  initDbgp();
  return;

// Failure cleanup. A goto is used to prevent duplication
failure:
  destroySocket();
  closeLog();
  // Allows the guarantee that any instance of an xdebug server is valid
  throw Exception("XDebug Server construction failed");
}
Пример #21
0
void XDebugServer::initDbgp() {
  // Initialize the status and reason
  switch (m_mode) {
    case Mode::REQ:
      setStatus(Status::STARTING, Reason::OK);
      break;
    case Mode::JIT:
      setStatus(Status::BREAK, Reason::ERROR);
      break;
  }
  // Create the response
  xdebug_xml_node* response = xdebug_xml_node_init("init");
  addXmnls(*response);

  // Add the engine info
  xdebug_xml_node* child = xdebug_xml_node_init("engine");
  xdebug_xml_add_attribute(child, "version", XDEBUG_VERSION);
  xdebug_xml_add_text(child, XDEBUG_NAME, 0);
  xdebug_xml_add_child(response, child);

  // Add the author
  child = xdebug_xml_node_init("author");
  xdebug_xml_add_text(child, XDEBUG_AUTHOR, 0);
  xdebug_xml_add_child(response, child);

  // Add the url
  child = xdebug_xml_node_init("url");
  xdebug_xml_add_text(child, XDEBUG_URL, 0);
  xdebug_xml_add_child(response, child);

  // Add the copyright
  child = xdebug_xml_node_init("copyright");
  xdebug_xml_add_text(child, XDEBUG_COPYRIGHT, 0);
  xdebug_xml_add_child(response, child);

  // Grab the absolute path of the script filename
  const ArrayData* globals = get_global_variables()->asArrayData();
  Variant scriptname_var = globals->get(s_SERVER).toArray()[s_SCRIPT_FILENAME];
  assert(scriptname_var.isString());
  char* scriptname = scriptname_var.toString().get()->mutableData();
  char* fileuri = XDebugUtils::pathToUrl(scriptname);

  // Grab the app id (pid)
  // TODO(#4489053) Specification mentions the parent app id as well, xdebug
  //                doesn't include it.
  char* appid = xdebug_sprintf("%d", getpid());

  // Add attributes to the root init node
  xdebug_xml_add_attribute_ex(response, "fileuri", fileuri, 0, 1);
  xdebug_xml_add_attribute_ex(response, "language", "PHP", 0, 0);
  xdebug_xml_add_attribute_ex(response, "protocol_version", DBGP_VERSION, 0, 0);
  xdebug_xml_add_attribute_ex(response, "appid", appid, 0, 1);

  // Add the DBGP_COOKIE environment variable
  char* dbgp_cookie = getenv("DBGP_COOKIE");
  if (dbgp_cookie != nullptr) {
    xdebug_xml_add_attribute_ex(response, "session", dbgp_cookie, 0, 0);
  }

  // Add the idekey
  if (XDEBUG_GLOBAL(IdeKey).size() > 0) {
    // TODO(#4489053) Change this when xml api is changed
    char* idekey = const_cast<char*>(XDEBUG_GLOBAL(IdeKey).c_str());
    xdebug_xml_add_attribute_ex(response, "idekey", idekey, 0, 0);
  }

  // Sent the response
  sendMessage(*response);
  xdebug_xml_node_dtor(response);

  // Wait for a response from the client
  doCommandLoop();
}
SystemGlobals*  get_system_globals() { return get_global_variables(); }
Пример #23
0
bool f_defined(CStrRef name, bool autoload /* = true */) {
  if (!name.get()) return false;
  const char *data = name.data();
  int len = name.length();
  char *colon;
  if ((colon = (char*)memchr(data, ':', len)) && colon[1] == ':') {
    // class constant
    int classNameLen = colon - data;
    char *constantName = colon + 2;
    String className(data, classNameLen, CopyString);

    // translate "self" or "parent"
    if (className == "self") {
      String this_class = hhvm
                          ? g_vmContext->getContextClassName()
                          : FrameInjection::GetClassName(true);
      if (this_class.empty()) {
        throw FatalErrorException("Cannot access self:: "
          "when no class scope is active");
      } else {
        className = this_class;
      }
    } else if (className == "parent") {
      String parent_class = hhvm
                            ? g_vmContext->getParentContextClassName()
                            : FrameInjection::GetParentClassName(true);
      if (parent_class.empty()) {
        throw FatalErrorException("Cannot access parent");
      } else {
        className = parent_class;
      }
    }
    if (class_exists(className)) { // taking care of volatile class
      const ClassInfo *info;
      for (String parentClass = className;
           !parentClass.empty();
           parentClass = info->getParentClass()) {
        info = ClassInfo::FindClass(parentClass);
        if (!info) {
          assert(false);
        }
        if (info->hasConstant(constantName)) return true;
      }
      return false;
    } else {
      return false;
    }
  } else {
    // system/uniquely defined scalar constant
    if (ClassInfo::FindConstant(name)) return true;
    if (hhvm ?
        g_vmContext->defined(name) :
        ((Globals*)get_global_variables())->defined(name)) {
      return true;
    }
    if (!autoload || !AutoloadHandler::s_instance->autoloadConstant(name)) {
      return false;
    }
    if (hhvm) return g_vmContext->defined(name);
    if (ClassInfo::FindConstant(name)) return true;
    return ((Globals*)get_global_variables())->defined(name);
  }
}
Пример #24
0
DebuggerProxyPtr Debugger::GetProxy() {
  SystemGlobals *g = (SystemGlobals*)get_global_variables();
  String id = g->GV(_SERVER)["HPHP_SANDBOX_ID"];
  return s_debugger.findProxy(id.data());
}
Пример #25
0
Array php_globals_as_array() {
  return Array(get_global_variables()->asArrayData());
}
Пример #26
0
/**
 * PHP has "EGPCS" processing order of these global variables, and this
 * order is important in preparing $_REQUEST that needs to know which to
 * overwrite what when name happens to be the same.
 */
void HttpProtocol::PrepareSystemVariables(Transport *transport,
                                          const RequestURI &r,
                                          const SourceRootInfo &sri) {
  SystemGlobals *g = (SystemGlobals*)get_global_variables();
  const VirtualHost *vhost = VirtualHost::GetCurrent();

  // reset global symbols to nulls or empty arrays
  pm_php$globals$symbols_php();

  Variant &server = g->GV(_SERVER);
  server.set("REQUEST_START_TIME", time(NULL));

  // $_ENV
  process_env_variables(g->GV(_ENV));
  g->GV(_ENV).set("HPHP", 1);
  g->GV(_ENV).set("HPHP_SERVER", 1);
#ifdef HOTPROFILER
  g->GV(_ENV).set("HPHP_HOTPROFILER", 1);
#endif

  Variant &request = g->GV(_REQUEST);

  // $_GET and $_REQUEST
  if (!r.queryString().empty()) {
    DecodeParameters(g->GV(_GET), r.queryString().data(),
                     r.queryString().size());
    CopyParams(request, g->GV(_GET));
  }

  string contentType = transport->getHeader("Content-Type");
  string contentLength = transport->getHeader("Content-Length");
  // $_POST and $_REQUEST
  if (transport->getMethod() == Transport::POST) {
    bool needDelete = false;
    int size = 0;
    const void *data = transport->getPostData(size);
    if (data && size) {
      ASSERT(((char*)data)[size] == 0); // we need a NULL terminated string
      string boundary;
      int content_length = atoi(contentLength.c_str());
      bool rfc1867Post = IsRfc1867(contentType, boundary);
      string files;
      if (rfc1867Post) {
        if (content_length > VirtualHost::GetMaxPostSize()) {
          // $_POST and $_FILES are empty
          Logger::Warning("POST Content-Length of %d bytes exceeds "
                          "the limit of %lld bytes",
                          content_length, VirtualHost::GetMaxPostSize());
          needDelete = read_all_post_data(transport, data, size);
        } else {
          if (transport->hasMorePostData()) {
            needDelete = true;
            data = Util::buffer_duplicate(data, size);
          }
          DecodeRfc1867(transport, g->GV(_POST), g->GV(_FILES),
                        content_length, data, size, boundary);
        }
        ASSERT(!transport->getFiles(files));
      } else {
        needDelete = read_all_post_data(transport, data, size);

        bool decodeData = strncasecmp(contentType.c_str(),
                                       DEFAULT_POST_CONTENT_TYPE,
                                       sizeof(DEFAULT_POST_CONTENT_TYPE)-1) == 0;
        // Always decode data for now. (macvicar)
        decodeData = true;

        if (decodeData) {
          DecodeParameters(g->GV(_POST), (const char*)data, size, true);
        }

        bool ret = transport->getFiles(files);
        if (ret) {
          g->GV(_FILES) = f_unserialize(files);
        }
      }
      CopyParams(request, g->GV(_POST));
      if (needDelete) {
        if (RuntimeOption::AlwaysPopulateRawPostData) {
          g->GV(HTTP_RAW_POST_DATA) = String((char*)data, size, AttachString);
        } else {
          free((void *)data);
        }
      } else {
        // For literal we disregard RuntimeOption::AlwaysPopulateRawPostData
        g->GV(HTTP_RAW_POST_DATA) = String((char*)data, size, AttachLiteral);
      }
    }
  }

  // $_COOKIE
  string cookie_data = transport->getHeader("Cookie");
  if (!cookie_data.empty()) {
    StringBuffer sb;
    sb.append(cookie_data);
    DecodeCookies(g->GV(_COOKIE), (char*)sb.data());
    CopyParams(request, g->GV(_COOKIE));
  }

  // $_SERVER

  // HTTP_ headers -- we don't exclude headers we handle elsewhere (e.g.,
  // Content-Type, Authorization), since the CGI "spec" merely says the server
  // "may" exclude them; this is not what APE does, but it's harmless.
  HeaderMap headers;
  transport->getHeaders(headers);
  for (HeaderMap::const_iterator iter = headers.begin();
       iter != headers.end(); ++iter) {
    const vector<string> &values = iter->second;
    for (unsigned int i = 0; i < values.size(); i++) {
      String key = "HTTP_";
      key += StringUtil::ToUpper(iter->first).replace("-", "_");
      server.set(key, String(values[i]));
    }
  }
  string host = transport->getHeader("Host");
  String hostName(VirtualHost::GetCurrent()->serverName(host));
  string hostHeader(host);
  if (hostHeader.empty()) {
    server.set("HTTP_HOST", hostName);
    StackTraceNoHeap::AddExtraLogging("Server", hostName.data());
  } else {
    StackTraceNoHeap::AddExtraLogging("Server", hostHeader.c_str());
  }
  if (hostName.empty() || RuntimeOption::ForceServerNameToHeader) {
    hostName = hostHeader;
    // _SERVER['SERVER_NAME'] shouldn't contain the port number
    int colonPos = hostName.find(':');
    if (colonPos != String::npos) {
      hostName = hostName.substr(0, colonPos);
    }
  }

  // APE sets CONTENT_TYPE and CONTENT_LENGTH without HTTP_
  if (!contentType.empty()) {
    server.set("CONTENT_TYPE", String(contentType));
  }
  if (!contentLength.empty()) {
    server.set("CONTENT_LENGTH", String(contentLength));
  }

  // APE processes Authorization: Basic into PHP_AUTH_USER and PHP_AUTH_PW
  string authorization = transport->getHeader("Authorization");
  if (!authorization.empty()) {
    if (strncmp(authorization.c_str(), "Basic ", 6) == 0) {
      // it's safe to pass this as a string literal since authorization
      // outlives decodedAuth; this saves us a superfluous copy.
      String decodedAuth =
        StringUtil::Base64Decode(String(authorization.c_str() + 6));
      int colonPos = decodedAuth.find(':');
      if (colonPos != String::npos) {
        server.set("PHP_AUTH_USER", decodedAuth.substr(0, colonPos));
        server.set("PHP_AUTH_PW", decodedAuth.substr(colonPos + 1));
      }
    }
  }

  server.set("REQUEST_URI", String(transport->getUrl(), CopyString));
  server.set("SCRIPT_URL", r.originalURL());
  String prefix(transport->isSSL() ? "https://" : "http://");
  String port_suffix("");

  // Need to append port
  if (!transport->isSSL() && RuntimeOption::ServerPort != 80) {
    port_suffix = ":" + RuntimeOption::ServerPort;
  }
  server.set("SCRIPT_URI", String(prefix +
                                  (hostHeader.empty() ?
                                    hostName + port_suffix : hostHeader)
                                  + r.originalURL()));

  if (r.rewritten()) {
    // when URL is rewritten, PHP decided to put original URL as SCRIPT_NAME
    String name = r.originalURL();
    if (!r.pathInfo().empty()) {
      int pos = name.find(r.pathInfo());
      if (pos >= 0) {
        name = name.substr(0, pos);
      }
    }
    if (r.defaultDoc()) {
      if (!name.empty() && name[name.length() - 1] != '/') {
        name += "/";
      }
      name += String(RuntimeOption::DefaultDocument);
    }
    server.set("SCRIPT_NAME", name);
  } else {
    server.set("SCRIPT_NAME", r.resolvedURL());
  }
  if (!r.rewritten() && r.pathInfo().empty()) {
    server.set("PHP_SELF", r.resolvedURL());
  } else {
    // when URL is rewritten, or pathinfo is not empty, use original URL
    server.set("PHP_SELF", r.originalURL());
  }

  server.set("SCRIPT_FILENAME", r.absolutePath());
  if (r.pathInfo().empty()) {
    server.set("PATH_TRANSLATED", r.absolutePath());
  } else {
    server.set("PATH_TRANSLATED",
               String(vhost->getDocumentRoot() + r.pathInfo().data()));
    server.set("PATH_INFO", r.pathInfo());
  }

  server.set("argv", r.queryString());
  server.set("argc", 0);
  server.set("GATEWAY_INTERFACE", "CGI/1.1");
  server.set("SERVER_ADDR", String(RuntimeOption::ServerPrimaryIP));
  server.set("SERVER_NAME", hostName);
  server.set("SERVER_PORT", RuntimeOption::ServerPort);
  server.set("SERVER_SOFTWARE", "HPHP");
  server.set("SERVER_PROTOCOL", "HTTP/" + transport->getHTTPVersion());
  server.set("SERVER_ADMIN", "");
  server.set("SERVER_SIGNATURE", "");
  switch (transport->getMethod()) {
  case Transport::GET:  server.set("REQUEST_METHOD", "GET");  break;
  case Transport::HEAD: server.set("REQUEST_METHOD", "HEAD"); break;
  case Transport::POST:
    if (transport->getExtendedMethod() == NULL) {
      server.set("REQUEST_METHOD", "POST");
    } else {
      server.set("REQUEST_METHOD", transport->getExtendedMethod());
    }
    break;
  default:              server.set("REQUEST_METHOD", "");     break;
  }
  server.set("HTTPS", transport->isSSL() ? "1" : "");
  server.set("REQUEST_TIME", time(NULL));
  server.set("QUERY_STRING", r.queryString());

  server.set("REMOTE_ADDR", String(transport->getRemoteHost(), CopyString));
  server.set("REMOTE_HOST", ""); // I don't think we need to nslookup
  server.set("REMOTE_PORT", 0);  // TODO: quite useless

  server.set("DOCUMENT_ROOT", String(vhost->getDocumentRoot()));

  for (map<string, string>::const_iterator iter =
         RuntimeOption::ServerVariables.begin();
       iter != RuntimeOption::ServerVariables.end(); ++iter) {
      server.set(String(iter->first), String(iter->second));
  }
  const map<string, string> &vServerVars = vhost->getServerVars();
  for (map<string, string>::const_iterator iter =
         vServerVars.begin();
       iter != vServerVars.end(); ++iter) {
    server.set(String(iter->first), String(iter->second));
  }
  sri.setServerVariables(server);

  const char *threadType = transport->getThreadTypeName();
  server.set("THREAD_TYPE", threadType);
  StackTraceNoHeap::AddExtraLogging("ThreadType", threadType);

#ifdef TAINTED
  taint_array_variant(g->GV(_GET), "$_GET");
  taint_array_variant(g->GV(_POST), "$_POST");
  taint_array_variant(g->GV(_SERVER), "$_SERVER");
  taint_array_variant(g->GV(_COOKIE), "$_COOKIE");
#endif
}
Пример #27
0
bool RPCRequestHandler::executePHPFunction(Transport *transport,
                                           SourceRootInfo &sourceRootInfo) {
  // reset timeout counter
  ThreadInfo::s_threadInfo->m_reqInjectionData.started = time(0);

  string rpcFunc = transport->getCommand();
  {
    ServerStatsHelper ssh("input");
    RequestURI reqURI(rpcFunc);
    HttpProtocol::PrepareSystemVariables(transport, reqURI, sourceRootInfo);
    SystemGlobals *g = (SystemGlobals*)get_global_variables();
    g->GV(_ENV).set(s_HPHP_RPC, 1);
  }

  bool isFile = rpcFunc.rfind('.') != string::npos;
  string rpcFile;
  bool error = false;

  Array params;
  string sparams = transport->getParam("params");
  if (!sparams.empty()) {
    Variant jparams = f_json_decode(String(sparams), true);
    if (jparams.isArray()) {
      params = jparams.toArray();
    } else {
      error = true;
    }
  } else {
    vector<string> sparams;
    transport->getArrayParam("p", sparams);
    if (!sparams.empty()) {
      for (unsigned int i = 0; i < sparams.size(); i++) {
        Variant jparams = f_json_decode(String(sparams[i]), true);
        if (same(jparams, false)) {
          error = true;
          break;
        }
        params.append(jparams);
      }
    } else {
      // single string parameter, used by xbox to avoid any en/decoding
      int size;
      const void *data = transport->getPostData(size);
      if (data && size) {
        params.append(String((char*)data, size, AttachLiteral));
      }
    }
  }

  if (transport->getIntParam("reset") == 1) {
    m_reset = true;
  }
  int output = transport->getIntParam("output");

  int code;
  if (!error) {
    Variant funcRet;
    string errorMsg = "Internal Server Error";
    string reqInitFunc, reqInitDoc;
    reqInitDoc = transport->getHeader("ReqInitDoc");
    if (reqInitDoc.empty() && m_serverInfo) {
      reqInitFunc = m_serverInfo->getReqInitFunc();
      reqInitDoc = m_serverInfo->getReqInitDoc();
    }

    if (!reqInitDoc.empty()) {
      reqInitDoc = (std::string)canonicalize_path(reqInitDoc, "", 0);
    }
    if (!reqInitDoc.empty()) {
      reqInitDoc = getSourceFilename(reqInitDoc, sourceRootInfo);
    }

    bool runOnce = false;
    bool ret = true;
    if (isFile) {
      rpcFile = rpcFunc;
      rpcFunc.clear();
    } else {
      rpcFile = transport->getParam("include");
      if (rpcFile.empty()) {
        rpcFile = transport->getParam("include_once");
        runOnce = true;
      }
    }
    if (!rpcFile.empty()) {
      // invoking a file through rpc
      bool forbidden = false;
      if (!RuntimeOption::ForbiddenFileExtensions.empty()) {
        const char *ext = rpcFile.c_str() + rpcFile.rfind('.') + 1;
        if (RuntimeOption::ForbiddenFileExtensions.find(ext) !=
            RuntimeOption::ForbiddenFileExtensions.end()) {
          forbidden = true;
        }
      }
      if (!forbidden) {
        rpcFile = (std::string) canonicalize_path(rpcFile, "", 0);
        rpcFile = getSourceFilename(rpcFile, sourceRootInfo);
        ret = hphp_invoke(m_context, rpcFile, false, Array(), uninit_null(),
                          reqInitFunc, reqInitDoc, error, errorMsg, runOnce);
      }
      // no need to do the initialization for a second time
      reqInitFunc.clear();
      reqInitDoc.clear();
    }
    if (ret && !rpcFunc.empty()) {
      ret = hphp_invoke(m_context, rpcFunc, true, params, ref(funcRet),
                        reqInitFunc, reqInitDoc, error, errorMsg);
    }
    if (ret) {
      bool serializeFailed = false;
      String response;
      switch (output) {
        case 0: {
          assert(m_returnEncodeType == Json ||
                 m_returnEncodeType == Serialize);
          try {
            response = (m_returnEncodeType == Json) ? f_json_encode(funcRet)
                                                    : f_serialize(funcRet);
          } catch (...) {
            serializeFailed = true;
          }
          break;
        }
        case 1: response = m_context->obDetachContents(); break;
        case 2:
          response =
            f_json_encode(CREATE_MAP2(s_output, m_context->obDetachContents(),
                                      s_return, f_json_encode(funcRet)));
          break;
        case 3: response = f_serialize(funcRet); break;
      }
      if (serializeFailed) {
        code = 500;
        transport->sendString(
            "Serialization of the return value failed", 500);
        m_reset = true;
      } else {
        transport->sendRaw((void*)response.data(), response.size());
        code = transport->getResponseCode();
      }
    } else if (error) {
      code = 500;
      transport->sendString(errorMsg, 500);
      m_reset = true;
    } else {
      code = 404;
      transport->sendString("Not Found", 404);
    }
  } else {
    code = 400;
    transport->sendString("Bad Request", 400);
  }

  params.reset();
  sourceRootInfo.clear();

  transport->onSendEnd();
  ServerStats::LogPage(isFile ? rpcFile : rpcFunc, code);

  m_context->onShutdownPostSend();
  m_context->obClean(); // in case postsend/cleanup output something
  m_context->restoreSession();
  return !error;
}