/** * REST API: WP_REST_Request class * * @package WordPress * @subpackage REST_API * @since 4.4.0 */ /** * Core class used to implement a REST request object. * * Contains data from the request, to be passed to the callback. * * Note: This implements ArrayAccess, and acts as an array of parameters when * used in that manner. It does not use ArrayObject (as we cannot rely on SPL), * so be aware it may have non-array behaviour in some cases. * * Note: When using features provided by ArrayAccess, be aware that WordPress deliberately * does not distinguish between arguments of the same name for different request methods. * For instance, in a request with `GET id=1` and `POST id=2`, `$request['id']` will equal * 2 (`POST`) not 1 (`GET`). For more precision between request methods, use * WP_REST_Request::get_body_params(), WP_REST_Request::get_url_params(), etc. * * @since 4.4.0 * * @see ArrayAccess */ class WP_REST_Request implements ArrayAccess { /** * HTTP method. * * @since 4.4.0 * @var string */ protected $method = ''; /** * Parameters passed to the request. * * These typically come from the `$_GET`, `$_POST` and `$_FILES` * superglobals when being created from the global scope. * * @since 4.4.0 * @var array Contains GET, POST and FILES keys mapping to arrays of data. */ protected $params; /** * HTTP headers for the request. * * @since 4.4.0 * @var array Map of key to value. Key is always lowercase, as per HTTP specification. */ protected $headers = array(); /** * Body data. * * @since 4.4.0 * @var string Binary data from the request. */ protected $body = null; /** * Route matched for the request. * * @since 4.4.0 * @var string */ protected $route; /** * Attributes (options) for the route that was matched. * * This is the options array used when the route was registered, typically * containing the callback as well as the valid methods for the route. * * @since 4.4.0 * @var array Attributes for the request. */ protected $attributes = array(); /** * Used to determine if the JSON data has been parsed yet. * * Allows lazy-parsing of JSON data where possible. * * @since 4.4.0 * @var bool */ protected $parsed_json = false; /** * Used to determine if the body data has been parsed yet. * * @since 4.4.0 * @var bool */ protected $parsed_body = false; /** * Constructor. * * @since 4.4.0 * * @param string $method Optional. Request method. Default empty. * @param string $route Optional. Request route. Default empty. * @param array $attributes Optional. Request attributes. Default empty array. */ public function __construct( $method = '', $route = '', $attributes = array() ) { $this->params = array( 'URL' => array(), 'GET' => array(), 'POST' => array(), 'FILES' => array(), // See parse_json_params. 'JSON' => null, 'defaults' => array(), ); $this->set_method( $method ); $this->set_route( $route ); $this->set_attributes( $attributes ); } /** * Retrieves the HTTP method for the request. * * @since 4.4.0 * * @return string HTTP method. */ public function get_method() { return $this->method; } /** * Sets HTTP method for the request. * * @since 4.4.0 * * @param string $method HTTP method. */ public function set_method( $method ) { $this->method = strtoupper( $method ); } /** * Retrieves all headers from the request. * * @since 4.4.0 * * @return array Map of key to value. Key is always lowercase, as per HTTP specification. */ public function get_headers() { return $this->headers; } /** * Canonicalizes the header name. * * Ensures that header names are always treated the same regardless of * source. Header names are always case insensitive. * * Note that we treat `-` (dashes) and `_` (underscores) as the same * character, as per header parsing rules in both Apache and nginx. * * @link https://stackoverflow.com/q/18185366 * @link https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#missing-disappearing-http-headers * @link https://nginx.org/en/docs/http/ngx_http_core_module.html#underscores_in_headers * * @since 4.4.0 * @static * * @param string $key Header name. * @return string Canonicalized name. */ public static function canonicalize_header_name( $key ) { $key = strtolower( $key ); $key = str_replace( '-', '_', $key ); return $key; } /** * Retrieves the given header from the request. * * If the header has multiple values, they will be concatenated with a comma * as per the HTTP specification. Be aware that some non-compliant headers * (notably cookie headers) cannot be joined this way. * * @since 4.4.0 * * @param string $key Header name, will be canonicalized to lowercase. * @return string|null String value if set, null otherwise. */ public function get_header( $key ) { $key = $this->canonicalize_header_name( $key ); if ( ! isset( $this->headers[ $key ] ) ) { return null; } return implode( ',', $this->headers[ $key ] ); } /** * Retrieves header values from the request. * * @since 4.4.0 * * @param string $key Header name, will be canonicalized to lowercase. * @return array|null List of string values if set, null otherwise. */ public function get_header_as_array( $key ) { $key = $this->canonicalize_header_name( $key ); if ( ! isset( $this->headers[ $key ] ) ) { return null; } return $this->headers[ $key ]; } /** * Sets the header on request. * * @since 4.4.0 * * @param string $key Header name. * @param string $value Header value, or list of values. */ public function set_header( $key, $value ) { $key = $this->canonicalize_header_name( $key ); $value = (array) $value; $this->headers[ $key ] = $value; } /** * Appends a header value for the given header. * * @since 4.4.0 * * @param string $key Header name. * @param string $value Header value, or list of values. */ public function add_header( $key, $value ) { $key = $this->canonicalize_header_name( $key ); $value = (array) $value; if ( ! isset( $this->headers[ $key ] ) ) { $this->headers[ $key ] = array(); } $this->headers[ $key ] = array_merge( $this->headers[ $key ], $value ); } /** * Removes all values for a header. * * @since 4.4.0 * * @param string $key Header name. */ public function remove_header( $key ) { $key = $this->canonicalize_header_name( $key ); unset( $this->headers[ $key ] ); } /** * Sets headers on the request. * * @since 4.4.0 * * @param array $headers Map of header name to value. * @param bool $override If true, replace the request's headers. Otherwise, merge with existing. */ public function set_headers( $headers, $override = true ) { if ( true === $override ) { $this->headers = array(); } foreach ( $headers as $key => $value ) { $this->set_header( $key, $value ); } } /** * Retrieves the content-type of the request. * * @since 4.4.0 * * @return array Map containing 'value' and 'parameters' keys. */ public function get_content_type() { $value = $this->get_header( 'content-type' ); if ( empty( $value ) ) { return null; } $parameters = ''; if ( strpos( $value, ';' ) ) { list( $value, $parameters ) = explode( ';', $value, 2 ); } $value = strtolower( $value ); if ( strpos( $value, '/' ) === false ) { return null; } // Parse type and subtype out. list( $type, $subtype ) = explode( '/', $value, 2 ); $data = compact( 'value', 'type', 'subtype', 'parameters' ); $data = array_map( 'trim', $data ); return $data; } /** * Retrieves the parameter priority order. * * Used when checking parameters in get_param(). * * @since 4.4.0 * * @return array List of types to check, in order of priority. */ protected function get_parameter_order() { $order = array(); $content_type = $this->get_content_type(); if ( $content_type['value'] === 'application/json' ) { $order[] = 'JSON'; } $this->parse_json_params(); // Ensure we parse the body data. $body = $this->get_body(); if ( 'POST' !== $this->method && ! empty( $body ) ) { $this->parse_body_params(); } $accepts_body_data = array( 'POST', 'PUT', 'PATCH', 'DELETE' ); if ( in_array( $this->method, $accepts_body_data ) ) { $order[] = 'POST'; } $order[] = 'GET'; $order[] = 'URL'; $order[] = 'defaults'; /** * Filters the parameter order. * * The order affects which parameters are checked when using get_param() and family. * This acts similarly to PHP's `request_order` setting. * * @since 4.4.0 * * @param array $order { * An array of types to check, in order of priority. * * @param string $type The type to check. * } * @param WP_REST_Request $this The request object. */ return apply_filters( 'rest_request_parameter_order', $order, $this ); } /** * Retrieves a parameter from the request. * * @since 4.4.0 * * @param string $key Parameter name. * @return mixed|null Value if set, null otherwise. */ public function get_param( $key ) { $order = $this->get_parameter_order(); foreach ( $order as $type ) { // Determine if we have the parameter for this type. if ( isset( $this->params[ $type ][ $key ] ) ) { return $this->params[ $type ][ $key ]; } } return null; } /** * Sets a parameter on the request. * * @since 4.4.0 * * @param string $key Parameter name. * @param mixed $value Parameter value. */ public function set_param( $key, $value ) { $order = $this->get_parameter_order(); $this->params[ $order[0] ][ $key ] = $value; } /** * Retrieves merged parameters from the request. * * The equivalent of get_param(), but returns all parameters for the request. * Handles merging all the available values into a single array. * * @since 4.4.0 * * @return array Map of key to value. */ public function get_params() { $order = $this->get_parameter_order(); $order = array_reverse( $order, true ); $params = array(); foreach ( $order as $type ) { // array_merge / the "+" operator will mess up // numeric keys, so instead do a manual foreach. foreach ( (array) $this->params[ $type ] as $key => $value ) { $params[ $key ] = $value; } } return $params; } /** * Retrieves parameters from the route itself. * * These are parsed from the URL using the regex. * * @since 4.4.0 * * @return array Parameter map of key to value. */ public function get_url_params() { return $this->params['URL']; } /** * Sets parameters from the route. * * Typically, this is set after parsing the URL. * * @since 4.4.0 * * @param array $params Parameter map of key to value. */ public function set_url_params( $params ) { $this->params['URL'] = $params; } /** * Retrieves parameters from the query string. * * These are the parameters you'd typically find in `$_GET`. * * @since 4.4.0 * * @return array Parameter map of key to value */ public function get_query_params() { return $this->params['GET']; } /** * Sets parameters from the query string. * * Typically, this is set from `$_GET`. * * @since 4.4.0 * * @param array $params Parameter map of key to value. */ public function set_query_params( $params ) { $this->params['GET'] = $params; } /** * Retrieves parameters from the body. * * These are the parameters you'd typically find in `$_POST`. * * @since 4.4.0 * * @return array Parameter map of key to value. */ public function get_body_params() { return $this->params['POST']; } /** * Sets parameters from the body. * * Typically, this is set from `$_POST`. * * @since 4.4.0 * * @param array $params Parameter map of key to value. */ public function set_body_params( $params ) { $this->params['POST'] = $params; } /** * Retrieves multipart file parameters from the body. * * These are the parameters you'd typically find in `$_FILES`. * * @since 4.4.0 * * @return array Parameter map of key to value */ public function get_file_params() { return $this->params['FILES']; } /** * Sets multipart file parameters from the body. * * Typically, this is set from `$_FILES`. * * @since 4.4.0 * * @param array $params Parameter map of key to value. */ public function set_file_params( $params ) { $this->params['FILES'] = $params; } /** * Retrieves the default parameters. * * These are the parameters set in the route registration. * * @since 4.4.0 * * @return array Parameter map of key to value */ public function get_default_params() { return $this->params['defaults']; } /** * Sets default parameters. * * These are the parameters set in the route registration. * * @since 4.4.0 * * @param array $params Parameter map of key to value. */ public function set_default_params( $params ) { $this->params['defaults'] = $params; } /** * Retrieves the request body content. * * @since 4.4.0 * * @return string Binary data from the request body. */ public function get_body() { return $this->body; } /** * Sets body content. * * @since 4.4.0 * * @param string $data Binary data from the request body. */ public function set_body( $data ) { $this->body = $data; // Enable lazy parsing. $this->parsed_json = false; $this->parsed_body = false; $this->params['JSON'] = null; } /** * Retrieves the parameters from a JSON-formatted body. * * @since 4.4.0 * * @return array Parameter map of key to value. */ public function get_json_params() { // Ensure the parameters have been parsed out. $this->parse_json_params(); return $this->params['JSON']; } /** * Parses the JSON parameters. * * Avoids parsing the JSON data until we need to access it. * * @since 4.4.0 * @since 4.7.0 Returns error instance if value cannot be decoded. * @return true|WP_Error True if the JSON data was passed or no JSON data was provided, WP_Error if invalid JSON was passed. */ protected function parse_json_params() { if ( $this->parsed_json ) { return true; } $this->parsed_json = true; // Check that we actually got JSON. $content_type = $this->get_content_type(); if ( empty( $content_type ) || 'application/json' !== $content_type['value'] ) { return true; } $body = $this->get_body(); if ( empty( $body ) ) { return true; } $params = json_decode( $body, true ); /* * Check for a parsing error. * * Note that due to WP's JSON compatibility functions, json_last_error * might not be defined: https://core.trac.wordpress.org/ticket/27799 */ if ( null === $params && ( ! function_exists( 'json_last_error' ) || JSON_ERROR_NONE !== json_last_error() ) ) { // Ensure subsequent calls receive error instance. $this->parsed_json = false; $error_data = array( 'status' => WP_Http::BAD_REQUEST, ); if ( function_exists( 'json_last_error' ) ) { $error_data['json_error_code'] = json_last_error(); $error_data['json_error_message'] = json_last_error_msg(); } return new WP_Error( 'rest_invalid_json', __( 'Invalid JSON body passed.' ), $error_data ); } $this->params['JSON'] = $params; return true; } /** * Parses the request body parameters. * * Parses out URL-encoded bodies for request methods that aren't supported * natively by PHP. In PHP 5.x, only POST has these parsed automatically. * * @since 4.4.0 */ protected function parse_body_params() { if ( $this->parsed_body ) { return; } $this->parsed_body = true; /* * Check that we got URL-encoded. Treat a missing content-type as * URL-encoded for maximum compatibility. */ $content_type = $this->get_content_type(); if ( ! empty( $content_type ) && 'application/x-www-form-urlencoded' !== $content_type['value'] ) { return; } parse_str( $this->get_body(), $params ); /* * Amazingly, parse_str follows magic quote rules. Sigh. * * NOTE: Do not refactor to use `wp_unslash`. */ if ( get_magic_quotes_gpc() ) { $params = stripslashes_deep( $params ); } /* * Add to the POST parameters stored internally. If a user has already * set these manually (via `set_body_params`), don't override them. */ $this->params['POST'] = array_merge( $params, $this->params['POST'] ); } /** * Retrieves the route that matched the request. * * @since 4.4.0 * * @return string Route matching regex. */ public function get_route() { return $this->route; } /** * Sets the route that matched the request. * * @since 4.4.0 * * @param string $route Route matching regex. */ public function set_route( $route ) { $this->route = $route; } /** * Retrieves the attributes for the request. * * These are the options for the route that was matched. * * @since 4.4.0 * * @return array Attributes for the request. */ public function get_attributes() { return $this->attributes; } /** * Sets the attributes for the request. * * @since 4.4.0 * * @param array $attributes Attributes for the request. */ public function set_attributes( $attributes ) { $this->attributes = $attributes; } /** * Sanitizes (where possible) the params on the request. * * This is primarily based off the sanitize_callback param on each registered * argument. * * @since 4.4.0 * * @return true|WP_Error True if parameters were sanitized, WP_Error if an error occurred during sanitization. */ public function sanitize_params() { $attributes = $this->get_attributes(); // No arguments set, skip sanitizing. if ( empty( $attributes['args'] ) ) { return true; } $order = $this->get_parameter_order(); $invalid_params = array(); foreach ( $order as $type ) { if ( empty( $this->params[ $type ] ) ) { continue; } foreach ( $this->params[ $type ] as $key => $value ) { if ( ! isset( $attributes['args'][ $key ] ) ) { continue; } $param_args = $attributes['args'][ $key ]; // If the arg has a type but no sanitize_callback attribute, default to rest_parse_request_arg. if ( ! array_key_exists( 'sanitize_callback', $param_args ) && ! empty( $param_args['type'] ) ) { $param_args['sanitize_callback'] = 'rest_parse_request_arg'; } // If there's still no sanitize_callback, nothing to do here. if ( empty( $param_args['sanitize_callback'] ) ) { continue; } $sanitized_value = call_user_func( $param_args['sanitize_callback'], $value, $this, $key ); if ( is_wp_error( $sanitized_value ) ) { $invalid_params[ $key ] = $sanitized_value->get_error_message(); } else { $this->params[ $type ][ $key ] = $sanitized_value; } } } if ( $invalid_params ) { return new WP_Error( 'rest_invalid_param', sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, 'params' => $invalid_params ) ); } return true; } /** * Checks whether this request is valid according to its attributes. * * @since 4.4.0 * * @return bool|WP_Error True if there are no parameters to validate or if all pass validation, * WP_Error if required parameters are missing. */ public function has_valid_params() { // If JSON data was passed, check for errors. $json_error = $this->parse_json_params(); if ( is_wp_error( $json_error ) ) { return $json_error; } $attributes = $this->get_attributes(); $required = array(); // No arguments set, skip validation. if ( empty( $attributes['args'] ) ) { return true; } foreach ( $attributes['args'] as $key => $arg ) { $param = $this->get_param( $key ); if ( isset( $arg['required'] ) && true === $arg['required'] && null === $param ) { $required[] = $key; } } if ( ! empty( $required ) ) { return new WP_Error( 'rest_missing_callback_param', sprintf( __( 'Missing parameter(s): %s' ), implode( ', ', $required ) ), array( 'status' => 400, 'params' => $required ) ); } /* * Check the validation callbacks for each registered arg. * * This is done after required checking as required checking is cheaper. */ $invalid_params = array(); foreach ( $attributes['args'] as $key => $arg ) { $param = $this->get_param( $key ); if ( null !== $param && ! empty( $arg['validate_callback'] ) ) { $valid_check = call_user_func( $arg['validate_callback'], $param, $this, $key ); if ( false === $valid_check ) { $invalid_params[ $key ] = __( 'Invalid parameter.' ); } if ( is_wp_error( $valid_check ) ) { $invalid_params[ $key ] = $valid_check->get_error_message(); } } } if ( $invalid_params ) { return new WP_Error( 'rest_invalid_param', sprintf( __( 'Invalid parameter(s): %s' ), implode( ', ', array_keys( $invalid_params ) ) ), array( 'status' => 400, 'params' => $invalid_params ) ); } return true; } /** * Checks if a parameter is set. * * @since 4.4.0 * * @param string $offset Parameter name. * @return bool Whether the parameter is set. */ public function offsetExists( $offset ) { $order = $this->get_parameter_order(); foreach ( $order as $type ) { if ( isset( $this->params[ $type ][ $offset ] ) ) { return true; } } return false; } /** * Retrieves a parameter from the request. * * @since 4.4.0 * * @param string $offset Parameter name. * @return mixed|null Value if set, null otherwise. */ public function offsetGet( $offset ) { return $this->get_param( $offset ); } /** * Sets a parameter on the request. * * @since 4.4.0 * * @param string $offset Parameter name. * @param mixed $value Parameter value. */ public function offsetSet( $offset, $value ) { $this->set_param( $offset, $value ); } /** * Removes a parameter from the request. * * @since 4.4.0 * * @param string $offset Parameter name. */ public function offsetUnset( $offset ) { $order = $this->get_parameter_order(); // Remove the offset from every group. foreach ( $order as $type ) { unset( $this->params[ $type ][ $offset ] ); } } /** * Retrieves a WP_REST_Request object from a full URL. * * @static * @since 4.5.0 * * @param string $url URL with protocol, domain, path and query args. * @return WP_REST_Request|false WP_REST_Request object on success, false on failure. */ public static function from_url( $url ) { $bits = parse_url( $url ); $query_params = array(); if ( ! empty( $bits['query'] ) ) { wp_parse_str( $bits['query'], $query_params ); } $api_root = rest_url(); if ( get_option( 'permalink_structure' ) && 0 === strpos( $url, $api_root ) ) { // Pretty permalinks on, and URL is under the API root. $api_url_part = substr( $url, strlen( untrailingslashit( $api_root ) ) ); $route = parse_url( $api_url_part, PHP_URL_PATH ); } elseif ( ! empty( $query_params['rest_route'] ) ) { // ?rest_route=... set directly $route = $query_params['rest_route']; unset( $query_params['rest_route'] ); } $request = false; if ( ! empty( $route ) ) { $request = new WP_REST_Request( 'GET', $route ); $request->set_query_params( $query_params ); } /** * Filters the request generated from a URL. * * @since 4.5.0 * * @param WP_REST_Request|false $request Generated request object, or false if URL * could not be parsed. * @param string $url URL the request was generated from. */ return apply_filters( 'rest_request_from_url', $request, $url ); } } L’auteure | Chloé Dubreuil

L’auteure

C’est à la toute fin des années 90 que mon premier livre a été publié. D’errances géographiques en balancements professionnels, j’ai suivi auparavant un drôle de parcours, me cherchant longtemps, avant de comprendre que j’aimais me laisser absorber tout entière par les histoires qui prenaient corps en mon imaginaire.
L’acte d’écrire est pour moi une mise en abîme et c’est véritablement cela qui m’inspire. Ce défi auquel je me confronte chaque jour, cette imposture que j’accole à mes personnages, cette fuite en avant, hors d’une réalité ordinaire.

Et puis il y a le fait de maîtriser pleinement une mise en scène, de se projeter dans d’autres univers, d’expérimenter une multiplicité d’aventures dans l’idée qu’elles prendront au cœur d’éventuels lecteurs.

En me perdant dans les entrelacs de l’écriture, j’ai vraiment le sentiment d’exister. Et l’essentiel est là, je crois: construire mon présent au fil de mes écrits…
Maintenant, pour celles et ceux qui souhaiteraient en connaître un peu plus à mon propos, il est un questionnaire auquel je me suis amusée à répondre; celui de Proust.
Ainsi donc:

Ma vertu préférée: la discrétion
La qualité que je préfère chez un homme: force de caractère… et sensibilité
La qualité que je préfère chez une femme: la persévérance, la franchise
Mon principal défaut: l’impatience
Mon occupation préférée: lire, voyager
Mon rêve de bonheur: ne plus être dans la peur de l’Autre
Quel serait mon plus grand malheur: de ne pas avoir donné de sens à ma vie
Ce que je voudrais être: un battement d’ailes, imperceptible
Le lieu où je désirerais vivre: une campagne dans la ville
La couleur que je préfère: le bleu profond
La fleur que j’aimerais être: un lys
L’oiseau que je préfère: l’aigle royal
Mes auteurs favoris en prose: j’en ai beaucoup et comme je suis très éclectique en matière de lecture… Mais les deux écrivains qui m’ont révélée à la littérature sont Kafka et Sartre
Mon poète favori: incontestablement Baudelaire
Mon héros de fiction: Hamlet… ou Arsène Lupin
Mon héroïne de fiction: une de ces femmes fortes et libres qui se dévoilent de temps à autre en littérature
Ce que je déteste par-dessus tout: la bêtise… ou l’hypocrisie, mon cœur balance
Mon mot favori: peccamineux
Ma plus grande fortune: l’obstination
Le don de la nature que je voudrais avoir: le don d’ubiquité
Ma mort: un rêve sans fin
Ma devise: qui ne tente rien n’a rien

 

Vous pouvez retrouver l’intégralité des chroniques/critiques suivantes dans la rubrique des livres correspondant. Mais en avant-goût, à propos de mes textes, il a été dit :

« Tout le talent de Chloé Dubreuil […] est d’avoir « calé » sa narration et son style sur le rythme et l’ambiance de l’histoire. Un style d’un grand classicisme, parfois volontairement un peu austère, un vocabulaire émaillé de mots et d’expressions anciennes (sans que cela tourne jamais au procédé) : c’est un plaisir de lire un texte d’une telle qualité littéraire. »
Le tourne page (Le faiseur de diables)

« J’ai vraiment aimé cette histoire. Elle m’a tenue en haleine jusqu’à la fin. Impossible pour moi de refermer ce livre avant de savoir. De plus, j’ai plongé avec délice dans le monde de ce peintre particulier. J’ai adoré. »
Promenades culturelles (Le faiseur de diables)

« J’aime beaucoup les dystopies et je peux vous assurer que celle-ci ne laisse pas indifférent ! Âmes sensibles s’abstenir ! Je ne regrette qu’une chose : en avoir déjà fini la lecture ! »
Promenades culturelles (Les limbes d’Icare)

« Un livre que je recommande absolument. Alliant le travail d’un chercheur aux talents d’un littéraire, Chloé Dubreuil répond par un tour de force qui ne manquera pas de déstabiliser plus d’un lecteur. »
Mélanie Courtemanche-Dancause, collaboratrice à L’Incorrect (Moi, Eva Braun)

« J’adore le style d’écriture de l’auteur qui m’emporte avec délices dans l’histoire. […] Un petit bijou d’histoire ! »
Le boudoir du livre (L’Insoumise)

« Très belle découverte pour ce roman ! […] Chloé DUBREUIL décrit tellement bien cette époque. On se rend compte qu’il y a un énorme travail  fourni et ce n’est qu’un bonheur à lire. […] J’ai beaucoup aimé suivre Maeve, c’est une femme très attachante. […] l’auteure rend fluide le récit et les évènements. Il y a aussi du suspens jusqu’à la fin ! Et j’ai adoré la fin, c’est ce que j’attendais.
Hellobook (L’Insoumise)

« Gros coup de cœur pour ce livre. […] Une lecture fascinante, très instructive, très troublante… Au point que le lecteur a l’impression de lire le journal intime d’Eva Braun écrit de sa main.
L
e boudoir des livres (Moi, Eva Braun)

« J’ai aimé la façon dont Chloé Dubreuil nous présente les choses. Se mettre dans la peau d’Eva Braun n’a pas dû être évident. Je suis toujours friande des autobiographies romancées qui nous font entrer ainsi dans la vie de ces personnalités beaucoup plus facilement qu’un livre d’Histoire. Et, bien que le personnage soit rebutant au premier abord, j’ai dévoré ce roman ! »
Promenades culturelles (Moi, Eva Braun…)

« Je suis profondément admirative de l’écriture de Chloé Dubreuil. […] Sa plume est alerte, on a toujours envie de savoir ce qu’il y aura sur l’autre page. En voyant l’heure tourner, je me disais à chaque fois : « Encore un peu ! », redoutant le moment où il faudrait laisser Maeve vaquer à ses occupations pour retourner moi-même à mon quotidien. »
Promenades culturelles (L’Insoumise)

« Un livre étonnant, où la guerre est indirectement présente, lointaine. Où la réalité du régime nazi s’estompe derrière un quotidien privé souvent banal. Où, comme l’écrit François Delpla : « Pour rendre justice à ce travail littéraire, la critique devra surmonter un réflexe pavlovien, qui depuis 1945 incite à réprouver, en tout effort pour comprendre les nazis, une tentative d’humaniser le mal ».
Guerres et conflits (Moi, Eva Braun…)

« Outre le choix narratif, le style en lui-même apporte aussi un éclairage certain sur la psychologie d’Eva Braun. Soignée, léchée, frisant l’artificialité, avec parfois des pas de côté, comme des sautes d’humeur, l’écriture est le reflet parfait de cette femme impossible à déchiffrer… »
Le club du roman historique (Moi, Eva Braun…)

« J’ai lu ce livre sans m’arrêter, ou à peine. On peut dire que Chloé Dubreuil sait ménager le suspense. On souffre avec la famille adoptive, avec Zahra. On veut savoir nous aussi, coûte que coûte. Je ne m’attendais pas du tout à ce dénouement, qui m’a laissé un sentiment de malaise car, sans rien dévoiler, on peut dire qu’il est peu conventionnel (ouf, heureusement !), que ce soit dans la vie réelle ou dans les habitudes que nous avons lorsque nous lisons un roman de ce type. »
Promenades culturelles (Tue-moi)

« Attention Pépite ! Et je vous assure que je pèse mes mots ! J’ai été littéralement happée par le vortex stylistique de Chloé Dubreuil qui n’a pas son pareil pour nous faire vivre des épisodes historiques ou pseudo-historiques. Âmes sensibles, vous allez vous endurcir ! Sur certains points, le monde médiéval est âpre. […] Mais pour compenser toute cette violence, on a aussi de beaux moments. L’instant où Asseline « devient femme » est d’une splendeur ! Bref, on tourne les pages fébrilement, on a hâte de savoir ce qui va se passer… L’atmosphère ésotérique vous prend et ne vous lâche plus ! […] Et ce final ! Éblouissant ! […] Bon, je pense que vous l’aurez compris, j’ai adoré ce texte qui ne ressemble à aucun autre.  »
Promenades culturelles (L’Esprit du Graal)

« Un roman assez grandiose qui fait voyager entre terre Sainte et Occitanie dans une quête fantasy un peu à la « Damné », très sympathique avec des thèmes chouettes ! » (L’Esprit du Graal)

« Passionnant. […] L’écriture est si fluide que l’on se régale de tourner les pages. […] Elle a su fondre les événements historiques dans son texte, tant et si bien que, sans la précision au début de l’ouvrage, nous ne reconnaîtrions pas les personnages réels des fictifs. Et c’est toujours le point d’achoppement, à mon sens, déterminant la réussite… »
Blog de lydia (Fortunae)

« … Chloé Dubreuil a fait un immense travail de recherche pour écrire Fortunae. […] La minutie des détails est fantastique. A l’aide d’un vocabulaire riche, presque technique, Chloé Dubreuil s’est attachée à reconstituer un univers qui projette le lecteur deux mille ans en arrière… »
Akarinthi.com (Fortunae)

‘… La particularité de Yéshoua est de conjuguer avec naturel le simple et le sacré, un sacré d’ascèse, tellurique, un sacré du grain et du sarment, de désert et de sel, d’eau vive et de mer Morte…’
magazine Points de vue (Yéshoua – Au nom du Fils)

‘… Lorsque l’on en entame la lecture, on ne lâche plus le texte. Un véritable petit bijou et je ne mâche pas mes mots…’
Les agents litteraires (Yéshoua Au nom du Fils)

‘…Yéshoua, au nom du Fils ne séduira peut-être pas les croyants en quête d’une certaine orthodoxie. Mais, reposant sur des recherches solides, il offre un regard neuf et profond sur la genèse de cette grande religion dont plusieurs milliards de personnes se revendiquent encore en 2012…’
Roman-historique.fr (Yéshoua Au nom du Fils)

‘… Pas de leçon dans ces nouvelles, mais une belle écriture analytique et souple pour un état des lieux de la douleur et de l’espérance…’
Livre et Lire (Le sourire de l’iguane)

‘…Un mystère alchimique, le secret des Tarots dits de Mantegna, et un retour romanesque aux sources de l’humanisme…’
Livre et Lire (Le temps d’Uranie)

« … Une belle précision stylistique. […]
Une montée en puissance de l’émotion… »
Le Figaro Lyon (Le goût des choses)

« … Une progression inéluctable… »
Le Progrès (Le goût des choses)

« … Une plume qui manie la prose avec justesse, pudeur et singularité… »
Arenciel (Le goût des choses)

« … Un air de Carpe Diem flotte dans ces pages […] Vous risquez d’être étonnés par vos découvertes…’
La Factory.com (Le goût des choses)

‘Un récit qui fait penser à ceux d’Emmanuel Bove, avec cette torpeur poisseuse et opaque qui les caractérise. »
Livre et Lire (Le goût des choses)