Пример #1
0
 public static function getLog()
 {
     if (!self::$log) {
         $path = PhabricatorEnv::getEnvConfig('log.access.path');
         $format = PhabricatorEnv::getEnvConfig('log.access.format');
         $format = nonempty($format, "[%D]\t%p\t%h\t%r\t%u\t%C\t%m\t%U\t%R\t%c\t%T");
         // NOTE: Path may be null. We still create the log, it just won't write
         // anywhere.
         $log = id(new PhutilDeferredLog($path, $format))->setFailQuietly(true)->setData(array('D' => date('r'), 'h' => php_uname('n'), 'p' => getmypid(), 'e' => time()));
         self::$log = $log;
     }
     return self::$log;
 }
Пример #2
0
 public static function getLog()
 {
     if (!self::$log) {
         $path = PhabricatorEnv::getEnvConfig('log.access.path');
         $format = PhabricatorEnv::getEnvConfig('log.access.format');
         $format = nonempty($format, "[%D]\t%p\t%h\t%r\t%u\t%C\t%m\t%U\t%R\t%c\t%T");
         if (!$path) {
             return null;
         }
         $log = new PhutilDeferredLog($path, $format);
         $log->setData(array('D' => date('r'), 'h' => php_uname('n'), 'p' => getmypid(), 'e' => time()));
         self::$log = $log;
     }
     return self::$log;
 }
 public function processRequest()
 {
     $time_start = microtime(true);
     $request = $this->getRequest();
     $method = $this->method;
     $api_request = null;
     $log = new PhabricatorConduitMethodCallLog();
     $log->setMethod($method);
     $metadata = array();
     try {
         $params = $this->decodeConduitParams($request, $method);
         $metadata = idx($params, '__conduit__', array());
         unset($params['__conduit__']);
         $call = new ConduitCall($method, $params);
         $result = null;
         // TODO: Straighten out the auth pathway here. We shouldn't be creating
         // a ConduitAPIRequest at this level, but some of the auth code expects
         // it. Landing a halfway version of this to unblock T945.
         $api_request = new ConduitAPIRequest($params);
         $allow_unguarded_writes = false;
         $auth_error = null;
         $conduit_username = '******';
         if ($call->shouldRequireAuthentication()) {
             $metadata['scope'] = $call->getRequiredScope();
             $auth_error = $this->authenticateUser($api_request, $metadata);
             // If we've explicitly authenticated the user here and either done
             // CSRF validation or are using a non-web authentication mechanism.
             $allow_unguarded_writes = true;
             if (isset($metadata['actAsUser'])) {
                 $this->actAsUser($api_request, $metadata['actAsUser']);
             }
             if ($auth_error === null) {
                 $conduit_user = $api_request->getUser();
                 if ($conduit_user && $conduit_user->getPHID()) {
                     $conduit_username = $conduit_user->getUsername();
                 }
                 $call->setUser($api_request->getUser());
             }
         }
         $access_log = PhabricatorAccessLog::getLog();
         if ($access_log) {
             $access_log->setData(array('u' => $conduit_username, 'm' => $method));
         }
         if ($call->shouldAllowUnguardedWrites()) {
             $allow_unguarded_writes = true;
         }
         if ($auth_error === null) {
             if ($allow_unguarded_writes) {
                 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
             }
             try {
                 $result = $call->execute();
                 $error_code = null;
                 $error_info = null;
             } catch (ConduitException $ex) {
                 $result = null;
                 $error_code = $ex->getMessage();
                 if ($ex->getErrorDescription()) {
                     $error_info = $ex->getErrorDescription();
                 } else {
                     $error_info = $call->getErrorDescription($error_code);
                 }
             }
             if ($allow_unguarded_writes) {
                 unset($unguarded);
             }
         } else {
             list($error_code, $error_info) = $auth_error;
         }
     } catch (Exception $ex) {
         phlog($ex);
         $result = null;
         $error_code = 'ERR-CONDUIT-CORE';
         $error_info = $ex->getMessage();
     }
     $time_end = microtime(true);
     $connection_id = null;
     if (idx($metadata, 'connectionID')) {
         $connection_id = $metadata['connectionID'];
     } else {
         if ($method == 'conduit.connect' && $result) {
             $connection_id = idx($result, 'connectionID');
         }
     }
     $log->setConnectionID($connection_id);
     $log->setError((string) $error_code);
     $log->setDuration(1000000 * ($time_end - $time_start));
     // TODO: This is a hack, but the insert is comparatively expensive and
     // we only really care about having these logs for real CLI clients, if
     // even that.
     if (empty($metadata['authToken'])) {
         $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
         $log->save();
         unset($unguarded);
     }
     $response = id(new ConduitAPIResponse())->setResult($result)->setErrorCode($error_code)->setErrorInfo($error_info);
     switch ($request->getStr('output')) {
         case 'human':
             return $this->buildHumanReadableResponse($method, $api_request, $response->toDictionary());
         case 'json':
         default:
             return id(new AphrontJSONResponse())->setAddJSONShield(false)->setContent($response->toDictionary());
     }
 }
Пример #4
0
 // This needs to be done before we create the log, because
 // PhabricatorAccessLog::getLog() calls date()
 $tz = PhabricatorEnv::getEnvConfig('phabricator.timezone');
 if ($tz) {
     date_default_timezone_set($tz);
 }
 // Append any paths to $PATH if we need to.
 $paths = PhabricatorEnv::getEnvConfig('environment.append-paths');
 if (!empty($paths)) {
     $current_env_path = getenv('PATH');
     $new_env_paths = implode(':', $paths);
     putenv('PATH=' . $current_env_path . ':' . $new_env_paths);
 }
 // This is the earliest we can get away with this, we need env config first.
 PhabricatorAccessLog::init();
 $access_log = PhabricatorAccessLog::getLog();
 if ($access_log) {
     $access_log->setData(array('R' => idx($_SERVER, 'HTTP_REFERER', '-'), 'r' => idx($_SERVER, 'REMOTE_ADDR', '-'), 'M' => idx($_SERVER, 'REQUEST_METHOD', '-')));
 }
 DarkConsoleXHProfPluginAPI::hookProfiler();
 PhutilErrorHandler::initialize();
 PhutilErrorHandler::setErrorListener(array('DarkConsoleErrorLogPluginAPI', 'handleErrors'));
 foreach (PhabricatorEnv::getEnvConfig('load-libraries') as $library) {
     phutil_load_library($library);
 }
 if (PhabricatorEnv::getEnvConfig('phabricator.setup')) {
     try {
         PhabricatorSetup::runSetup();
     } catch (Exception $ex) {
         echo "EXCEPTION!\n";
         echo $ex;
 public function processRequest()
 {
     $time_start = microtime(true);
     $request = $this->getRequest();
     $method = $this->method;
     $api_request = null;
     $method_implementation = null;
     $log = new PhabricatorConduitMethodCallLog();
     $log->setMethod($method);
     $metadata = array();
     $multimeter = MultimeterControl::getInstance();
     if ($multimeter) {
         $multimeter->setEventContext('api.' . $method);
     }
     try {
         list($metadata, $params) = $this->decodeConduitParams($request, $method);
         $call = new ConduitCall($method, $params);
         $method_implementation = $call->getMethodImplementation();
         $result = null;
         // TODO: The relationship between ConduitAPIRequest and ConduitCall is a
         // little odd here and could probably be improved. Specifically, the
         // APIRequest is a sub-object of the Call, which does not parallel the
         // role of AphrontRequest (which is an indepenent object).
         // In particular, the setUser() and getUser() existing independently on
         // the Call and APIRequest is very awkward.
         $api_request = $call->getAPIRequest();
         $allow_unguarded_writes = false;
         $auth_error = null;
         $conduit_username = '******';
         if ($call->shouldRequireAuthentication()) {
             $metadata['scope'] = $call->getRequiredScope();
             $auth_error = $this->authenticateUser($api_request, $metadata);
             // If we've explicitly authenticated the user here and either done
             // CSRF validation or are using a non-web authentication mechanism.
             $allow_unguarded_writes = true;
             if ($auth_error === null) {
                 $conduit_user = $api_request->getUser();
                 if ($conduit_user && $conduit_user->getPHID()) {
                     $conduit_username = $conduit_user->getUsername();
                 }
                 $call->setUser($api_request->getUser());
             }
         }
         $access_log = PhabricatorAccessLog::getLog();
         if ($access_log) {
             $access_log->setData(array('u' => $conduit_username, 'm' => $method));
         }
         if ($call->shouldAllowUnguardedWrites()) {
             $allow_unguarded_writes = true;
         }
         if ($auth_error === null) {
             if ($allow_unguarded_writes) {
                 $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
             }
             try {
                 $result = $call->execute();
                 $error_code = null;
                 $error_info = null;
             } catch (ConduitException $ex) {
                 $result = null;
                 $error_code = $ex->getMessage();
                 if ($ex->getErrorDescription()) {
                     $error_info = $ex->getErrorDescription();
                 } else {
                     $error_info = $call->getErrorDescription($error_code);
                 }
             }
             if ($allow_unguarded_writes) {
                 unset($unguarded);
             }
         } else {
             list($error_code, $error_info) = $auth_error;
         }
     } catch (Exception $ex) {
         if (!$ex instanceof ConduitMethodNotFoundException) {
             phlog($ex);
         }
         $result = null;
         $error_code = $ex instanceof ConduitException ? 'ERR-CONDUIT-CALL' : 'ERR-CONDUIT-CORE';
         $error_info = $ex->getMessage();
     }
     $time_end = microtime(true);
     $connection_id = null;
     if (idx($metadata, 'connectionID')) {
         $connection_id = $metadata['connectionID'];
     } else {
         if ($method == 'conduit.connect' && $result) {
             $connection_id = idx($result, 'connectionID');
         }
     }
     $log->setCallerPHID(isset($conduit_user) ? $conduit_user->getPHID() : null)->setConnectionID($connection_id)->setError((string) $error_code)->setDuration(1000000 * ($time_end - $time_start));
     $unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
     $log->save();
     unset($unguarded);
     $response = id(new ConduitAPIResponse())->setResult($result)->setErrorCode($error_code)->setErrorInfo($error_info);
     switch ($request->getStr('output')) {
         case 'human':
             return $this->buildHumanReadableResponse($method, $api_request, $response->toDictionary(), $method_implementation);
         case 'json':
         default:
             return id(new AphrontJSONResponse())->setAddJSONShield(false)->setContent($response->toDictionary());
     }
 }
 /**
  * @phutil-external-symbol class PhabricatorStartup
  */
 public static function runHTTPRequest(AphrontHTTPSink $sink)
 {
     $multimeter = MultimeterControl::newInstance();
     $multimeter->setEventContext('<http-init>');
     $multimeter->setEventViewer('<none>');
     // Build a no-op write guard for the setup phase. We'll replace this with a
     // real write guard later on, but we need to survive setup and build a
     // request object first.
     $write_guard = new AphrontWriteGuard('id');
     PhabricatorEnv::initializeWebEnvironment();
     $multimeter->setSampleRate(PhabricatorEnv::getEnvConfig('debug.sample-rate'));
     $debug_time_limit = PhabricatorEnv::getEnvConfig('debug.time-limit');
     if ($debug_time_limit) {
         PhabricatorStartup::setDebugTimeLimit($debug_time_limit);
     }
     // This is the earliest we can get away with this, we need env config first.
     PhabricatorAccessLog::init();
     $access_log = PhabricatorAccessLog::getLog();
     PhabricatorStartup::setAccessLog($access_log);
     $access_log->setData(array('R' => AphrontRequest::getHTTPHeader('Referer', '-'), 'r' => idx($_SERVER, 'REMOTE_ADDR', '-'), 'M' => idx($_SERVER, 'REQUEST_METHOD', '-')));
     DarkConsoleXHProfPluginAPI::hookProfiler();
     DarkConsoleErrorLogPluginAPI::registerErrorHandler();
     $response = PhabricatorSetupCheck::willProcessRequest();
     if ($response) {
         PhabricatorStartup::endOutputCapture();
         $sink->writeResponse($response);
         return;
     }
     $host = AphrontRequest::getHTTPHeader('Host');
     $path = $_REQUEST['__path__'];
     switch ($host) {
         default:
             $config_key = 'aphront.default-application-configuration-class';
             $application = PhabricatorEnv::newObjectFromConfig($config_key);
             break;
     }
     $application->setHost($host);
     $application->setPath($path);
     $application->willBuildRequest();
     $request = $application->buildRequest();
     // Now that we have a request, convert the write guard into one which
     // actually checks CSRF tokens.
     $write_guard->dispose();
     $write_guard = new AphrontWriteGuard(array($request, 'validateCSRF'));
     // Build the server URI implied by the request headers. If an administrator
     // has not configured "phabricator.base-uri" yet, we'll use this to generate
     // links.
     $request_protocol = $request->isHTTPS() ? 'https' : 'http';
     $request_base_uri = "{$request_protocol}://{$host}/";
     PhabricatorEnv::setRequestBaseURI($request_base_uri);
     $access_log->setData(array('U' => (string) $request->getRequestURI()->getPath()));
     $processing_exception = null;
     try {
         $response = $application->processRequest($request, $access_log, $sink, $multimeter);
         $response_code = $response->getHTTPResponseCode();
     } catch (Exception $ex) {
         $processing_exception = $ex;
         $response_code = 500;
     }
     $write_guard->dispose();
     $access_log->setData(array('c' => $response_code, 'T' => PhabricatorStartup::getMicrosecondsSinceStart()));
     $multimeter->newEvent(MultimeterEvent::TYPE_REQUEST_TIME, $multimeter->getEventContext(), PhabricatorStartup::getMicrosecondsSinceStart());
     $access_log->write();
     $multimeter->saveEvents();
     DarkConsoleXHProfPluginAPI::saveProfilerSample($access_log);
     // Add points to the rate limits for this request.
     if (isset($_SERVER['REMOTE_ADDR'])) {
         $user_ip = $_SERVER['REMOTE_ADDR'];
         // The base score for a request allows users to make 30 requests per
         // minute.
         $score = 1000 / 30;
         // If the user was logged in, let them make more requests.
         if ($request->getUser() && $request->getUser()->getPHID()) {
             $score = $score / 5;
         }
         PhabricatorStartup::addRateLimitScore($user_ip, $score);
     }
     if ($processing_exception) {
         throw $processing_exception;
     }
 }