diff --git a/scripts/conduit/api.php b/scripts/conduit/api.php index 2844c2f393..e2da82ce6e 100644 --- a/scripts/conduit/api.php +++ b/scripts/conduit/api.php @@ -85,7 +85,7 @@ $response = id(new ConduitAPIResponse()) ->setResult($result) ->setErrorCode($error_code) ->setErrorInfo($error_info); -echo $response->toJSON(), "\n"; +echo json_encode($response->toDictionary()), "\n"; // TODO -- how get $connection_id from SSH? $connection_id = null; diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index fb58757510..77037eed33 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -55,6 +55,7 @@ phutil_register_library_map(array( 'AphrontIsolatedDatabaseConnection' => 'storage/connection/isolated', 'AphrontIsolatedDatabaseConnectionTestCase' => 'storage/connection/isolated/__tests__', 'AphrontIsolatedHTTPSink' => 'aphront/sink/test', + 'AphrontJSONResponse' => 'aphront/response/json', 'AphrontJavelinView' => 'view/javelin-view', 'AphrontKeyboardShortcutsAvailableView' => 'view/widget/keyboardshortcuts', 'AphrontListFilterView' => 'view/layout/listfilter', @@ -880,6 +881,7 @@ phutil_register_library_map(array( 'AphrontIsolatedDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontIsolatedDatabaseConnectionTestCase' => 'PhabricatorTestCase', 'AphrontIsolatedHTTPSink' => 'AphrontHTTPSink', + 'AphrontJSONResponse' => 'AphrontResponse', 'AphrontJavelinView' => 'AphrontView', 'AphrontKeyboardShortcutsAvailableView' => 'AphrontView', 'AphrontListFilterView' => 'AphrontView', diff --git a/src/aphront/response/ajax/AphrontAjaxResponse.php b/src/aphront/response/ajax/AphrontAjaxResponse.php index b64d053f17..a22cbc6eeb 100644 --- a/src/aphront/response/ajax/AphrontAjaxResponse.php +++ b/src/aphront/response/ajax/AphrontAjaxResponse.php @@ -1,7 +1,7 @@ renderAjaxResponse( + $object = $response->buildAjaxResponse( $this->content, $this->error); + + return $this->encodeJSONForHTTPResponse( + $object, + $use_javelin_shield = true); } public function getHeaders() { diff --git a/src/aphront/response/base/AphrontResponse.php b/src/aphront/response/base/AphrontResponse.php index c4b4ce8b31..6c32b7f744 100644 --- a/src/aphront/response/base/AphrontResponse.php +++ b/src/aphront/response/base/AphrontResponse.php @@ -70,6 +70,37 @@ abstract class AphrontResponse { return $this; } + protected function encodeJSONForHTTPResponse( + array $object, + $use_javelin_shield) { + + $response = json_encode($object); + + // Prevent content sniffing attacks by encoding "<" and ">", so browsers + // won't try to execute the document as HTML even if they ignore + // Content-Type and X-Content-Type-Options. See T865. + $response = str_replace( + array('<', '>'), + array('\u003c', '\u003e'), + $response); + + // Add a shield to prevent "JSON Hijacking" attacks where an attacker + // requests a JSON response using a normal