@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
at upstream/main 171 lines 3.7 kB view raw
1<?php 2 3final class AphrontUnhandledExceptionResponse 4 extends AphrontStandaloneHTMLResponse { 5 6 private $exception; 7 private $showStackTraces; 8 9 public function setShowStackTraces($show_stack_traces) { 10 $this->showStackTraces = $show_stack_traces; 11 return $this; 12 } 13 14 public function getShowStackTraces() { 15 return $this->showStackTraces; 16 } 17 18 public function setException($exception) { 19 // NOTE: We accept an Exception or a Throwable. 20 21 // Log the exception unless it's specifically a silent malformed request 22 // exception. 23 24 $should_log = true; 25 if ($exception instanceof AphrontMalformedRequestException) { 26 if ($exception->getIsUnlogged()) { 27 $should_log = false; 28 } 29 } 30 31 if ($should_log) { 32 phlog($exception); 33 } 34 35 $this->exception = $exception; 36 return $this; 37 } 38 39 public function getHTTPResponseCode() { 40 return 500; 41 } 42 43 protected function getResources() { 44 return array( 45 'css/application/config/config-template.css', 46 'css/application/config/unhandled-exception.css', 47 ); 48 } 49 50 protected function getResponseTitle() { 51 $ex = $this->exception; 52 53 if ($ex instanceof AphrontMalformedRequestException) { 54 return $ex->getTitle(); 55 } else { 56 return pht('Unhandled Exception'); 57 } 58 } 59 60 protected function getResponseBodyClass() { 61 return 'unhandled-exception'; 62 } 63 64 private function getExceptionList() { 65 return $this->expandException($this->exception); 66 } 67 68 private function expandException($root) { 69 if ($root instanceof PhutilAggregateException) { 70 $list = array(); 71 72 $list[] = $root; 73 74 foreach ($root->getExceptions() as $ex) { 75 foreach ($this->expandException($ex) as $child) { 76 $list[] = $child; 77 } 78 } 79 80 return $list; 81 } 82 83 return array($root); 84 } 85 86 protected function getResponseBody() { 87 $body = array(); 88 89 foreach ($this->getExceptionList() as $ex) { 90 $body[] = $this->newHTMLMessage($ex); 91 } 92 93 return $body; 94 } 95 96 private function newHTMLMessage($ex) { 97 if ($ex instanceof AphrontMalformedRequestException) { 98 $title = $ex->getTitle(); 99 } else { 100 $title = get_class($ex); 101 } 102 103 $body = $ex->getMessage(); 104 $body = phutil_escape_html_newlines($body); 105 106 $classes = array(); 107 $classes[] = 'unhandled-exception-detail'; 108 109 $stack = null; 110 if ($this->getShowStackTraces()) { 111 try { 112 $stack = id(new AphrontStackTraceView()) 113 ->setTrace($ex->getTrace()); 114 115 $stack = hsprintf('%s', $stack); 116 117 $stack = phutil_tag( 118 'div', 119 array( 120 'class' => 'unhandled-exception-stack', 121 ), 122 $stack); 123 124 $classes[] = 'unhandled-exception-with-stack'; 125 } catch (Exception $trace_exception) { 126 $stack = null; 127 } catch (Throwable $trace_exception) { 128 $stack = null; 129 } 130 } 131 132 return phutil_tag( 133 'div', 134 array( 135 'class' => implode(' ', $classes), 136 ), 137 array( 138 phutil_tag( 139 'h1', 140 array( 141 'class' => 'unhandled-exception-title', 142 ), 143 $title), 144 phutil_tag( 145 'div', 146 array( 147 'class' => 'unhandled-exception-body', 148 ), 149 $body), 150 $stack, 151 )); 152 } 153 154 protected function buildPlainTextResponseString() { 155 $messages = array(); 156 157 foreach ($this->getExceptionList() as $exception) { 158 $messages[] = $this->newPlainTextMessage($exception); 159 } 160 161 return implode("\n\n", $messages); 162 } 163 164 private function newPlainTextMessage($exception) { 165 return pht( 166 '%s: %s', 167 get_class($exception), 168 $exception->getMessage()); 169 } 170 171}