/** * 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 ); } } Le faiseur de diables | Chloé Dubreuil

Le faiseur de diables

Extrait audio

An de grâce 1506.

Une série de crimes sordides dans la ville de l’illustre Jérôme Bosch et bien des peurs ressortent. Arent Saeghers, bras droit du bailli, est chargé d’enquêter, mais en s’exposant aux démons et merveilles qui flagellent le monde des hommes à travers les tableaux du peintre, ce lieutenant à la trouble personnalité risque fort de s’exposer à des périls plus intimes, et fatals, qu’il ne l’aurait cru.

À mi-chemin du roman noir et du polar historique, Le faiseur de diables nous plonge avec délectation dans un XVIe siècle humaniste et pourtant empreint de superstitions, au plus près d’un des grands artistes de cette époque et des rouages de son imaginaire.

 

Chroniques, critiques autour du livre…

Interview sur le blog Histoire et fiction

La couverture de votre roman est un détail du tableau Le jugement dernier de Jérôme Bosch. Dans quelle mesure cette œuvre a-t-elle influencé le sujet du roman ? Pourquoi l’avoir choisie ?

Ce n’est pas tant Le jugement dernier qui a inspiré l’intrigue de mon roman que l’univers particulièrement fantasmagorique du peintre. Maintenant, vous me direz, pourquoi ce tableau plutôt qu’un autre de Jérôme Bosch ? Le jugement dernier est une notion à laquelle fait référence mon personnage principal par deux fois dans le roman. Elle a du sens pour lui, et reflète les considérations qu’il porte sur le monde et ses semblables. Le choix de ce tableau en couverture n’est donc pas anecdotique.

Le Faiseur de diable se déroule au temps des primitifs flamands. Cette période est souvent associée à un âge d’or artistique pour les Pays-Bas. Pourtant, vous choisissez d’évoquer des crimes sordides dans une ambiance très sombre. Comment expliquer un tel contraste ?

La peinture des primitifs flamands a une forte connotation religieuse – regardez les Van Eyck – quand elle ne porte pas sur la vie sociale comme les tableaux de Brueghel l’Ancien. Nous sommes aux débuts de la Renaissance, aux prémices de la Réforme protestante. Le Nouveau monde vient d’être découvert, l’Église se déchire, les Pays-Bas de même, partagés entre ceux qui soutiennent le Saint Empire romain germanique et ceux qui regardent du côté de la France. La guerre civile est encore dans tous les esprits. C’est dans une société en plein bouleversement, encore fort éprise de superstition médiévale, une société pleine de peurs et de questionnements, que s’inscrit mon roman.

L’œuvre de Jérôme Bosch est unique : elle nous plonge avec férocité et sublimité dans les travers de l’Homme. Elle est un miroir tendu à nos vices et perversions, tout en essayant de nous montrer, symboliquement, le chemin à suivre pour nous en extraire. Bref, la peinture de Bosch se prête tout à fait au genre noir. Le Faiseur de diables n’avait plus qu’à se couler dans le moule de cette époque qui aspirait à un renouveau culturel, politique, et moral, sans pour autant parvenir à se débarrasser des terreurs du passé.

Qui est votre personnage principal, Arent Saeghers ? Est-il inspiré d’un personnage réel ?

Aucunement. Arent Saghers est un personnage comme je les aime : qui se tient sur le fil de la déraison, plein de force et pétri de fragilités. Ambigu, tourmenté. Un personnage des plus humains en sorte…

Au début du XVIe siècle, à quoi ressemblait la vie quotidienne à Bois-le-Duc, la ville natale de Bosch, loin de la Cour de Bruxelles ?

C’était une cité de moyenne envergure, inféodée au commerce, et à ses richesses. Les bourgeois et clercs avaient force de loi. Bois-le-Duc était une ville florissante, la population vivait plutôt bien.

Quelle place ont les recherches historiques dans votre travail d’écriture ? Quelles libertés vous êtes-vous accordées par rapport aux faits connus ?

J’aime que mes lecteurs puissent avoir confiance en ce qu’ils lisent. Je suis donc très attachée à raconter la grande histoire à travers la petite, à user de figures historiques en personnages secondaires. Les éléments relatifs au cadre de vie, à l’entour politique et social, ne sont pas fictionnels. Je passe toujours du temps en bibliothèque et sur internet avant de commencer à écrire mes romans historiques. Au cours de l’écriture elle-même, je vérifie constamment les détails. Mais je garde ma pleine liberté pour ce qui est de l’intrigue et de mes protagonistes principaux. J’ai besoin de laisser mon imagination vagabonder, composer selon ses envies. Je répète souvent à mes étudiants que la liberté est la qualité première de la fiction. Je ne pourrais continuer à écrire sans elle.

En quoi Le Faiseur de diable se distingue-t-il de vos autres romans « médiévaux » ? Allez-vous continuer à écrire sur cette période ?

Mes autres romans historiques ne sont pas des polars, romans noirs, mais plutôt de grandes fresques aventureuses – j’adore ce genre.  Actuellement, je travaille sur des « mémoires » de Gilles de Rais, l’un des plus fameux compagnons de Jeanne d’Arc et, accessoirement, le premier « tueur en série » de l’Histoire française. Un roman écrit au « je », comme je l’ai déjà fait pour Yeshoua et Eva Braun. Voilà un défi comme je les aime.

 

www.letournepage.com/livre/le-faiseur-de-diables/:

« Le faiseur de diables. Joli titre, n’est-ce pas ?

Un titre qui m’a fait de l’œil, posé sur la couverture juste au dessus d’un célèbre tableau de Jérôme Bosch, Le jugement dernier.

Jheronimus Bosch – attention, pas le héros récurrent des romans de Michael Connelly, mais bien le formidable peintre hollandais du XV° siècle ! – est un des personnages principaux du court roman de Chloé Dubreuil.

Un récit que le pitch situe à mi-chemin du roman noir et du polar historique, mais que je qualifierais plus précisément de roman néogothique.

Une histoire terriblement sombre – au propre comme au figuré, car les ambiances automnales et les éclairages à la bougie prédominent – où les crimes horribles se succèdent, au sein de la communauté de Bois-le-Duc.

Chargé de l’enquête, Arent Saeghers navigue entre les intrigues politiques et les influences religieuses, aidé par Agostino, le jeune apprenti de maître Bosch qu’il lui a confié.

Tout n’est que faux-semblant dans cette histoire, à commencer par la personnalité d’Arent Saeghers et celle d’Agostino (mais je n’en dirais pas plus, car ceci constitue le cœur même de l’intrigue).

Tout le talent de Chloé Dubreuil – une auteure pleine d’expérience qui a déjà publié plus d’une dizaine de romans, aux toiles de fond majoritairement historiques – 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.

Jusqu’à sa conclusion, la pénombre qui règne sur le roman perdurera : Le faiseur de diables n’est pas un roman d’espoir; mais avec un titre pareil, vous pouviez vous en douter… »

 

Promenades culturelles:
« Je trouve toujours original de s’inspirer d’un peintre, d’un tableau pour en écrire un roman. D’autant plus lorsqu’il s’agit d’un policier. Ajoutons à cela la contrainte de l’Histoire… Voilà bien des obstacles auxquels s’est attelée Chloé Dubreuil. Nous partons dans le monde de Jérôme Bosch, un peintre un peu à part qui m’a toujours fascinée. Nous sommes en 1506, à Hertogenbosch (Bois-le-Duc). Des crimes ont lieu. Arent Saeghers, le bras droit du bailli, va mener l’enquête. Mais attention, les démons veillent…

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é.

Je suis admirative ! En effet, Chloé Dubreuil arrive toujours à se renouveler, quel que soit le sujet. De la biographie au roman noir, c’est toujours un vrai plaisir de la lire. »

 

EXTRAIT

 

Au commencement

Où le crime nous invite à une ronde macabre

 

Hertogenbosch,[1] duché de Brabant, Pays-Bas bourguignons

2 novembre 1506

Les morts rôdent, c’est leur nuit. Une vraie nuit de cavale qui ne demeurera pas sans victime. D’ailleurs, au-dessus de la ville et de ses remparts, la lune elle-même se fait complice : obscène, d’une blancheur spectrale. Son reflet bondit d’un canal à l’autre, guette, attend.

La lune attend que le doigt de Dieu se pose sur le col du Diable. Là, dans le cimetière Sainte-Gertrude. Près, tout près d’une stèle gravée au nom de dame Ioule, « de bon renom, épouse d’affection de Maerten Andriessen », et d’un homme accolé à sa tombe lequel, en cette heure indue, et sans qu’il ne s’en rende compte, a été suivi. Sans doute avait-il l’esprit absorbé par sa visite au cimetière si longtemps repoussée… Quoi qu’il en fût, il ne pouvait mieux choisir, sans même le vouloir, le lieu de son trépas. Dans le relief tourmenté des allées bordées d’arbres dépenaillés se dresse la cohorte des sépultures. Moussues, livides elles aussi.

Pourquoi s’attarde-t-il ? Serait-ce ses regrets qui le retiennent ?

De l’autre côté du mur du cimetière, une cloche ébranle son battant. La mi nuit s’exalte et pourtant une impression de solitude et d’abandon, poignante, émane de l’endroit.

Le son de cloche expire.

Tapi derrière un puits étouffé par le lierre, tu retiens ton souffle – comme si quelque chose en toi se calquait à l’inertie de ta proie. Puis cette dernière s’extrait enfin de son apathie. Le froid, humide en cette saison, s’est insinué dans les veines de ta victime. Sa paume se détache avec peine de la pierre tombale sur laquelle elle était posée. Tranchant sur le gant noir, une chevalière en or, au chaton octogonal, s’aperçoit un instant entre deux éclats de lune.

L’individu, dont on discerne à présent l’échine cagneuse, se redresse avec difficulté, grimace en sentant ses genoux se rebeller contre la posture qu’il avait adoptée. Agacé, il relève derrière sa nuque la fourrure en lynx de son manteau, d’un brun aussi foncé que la toque à bords relevés qui couvre son crâne, dégarni, et sous lequel transparaît un visage au front bas et rugueux. Il a la mise soignée d’un échevin. Serait-ce là un riche marchand ? Un maître artisan ? Peu importe. L’homme, en ce cimetière, vit ses derniers instants. Ses ultimes instants de vivant que l’éternité se hâtera de damner.

 Dans son dos, les ténèbres se trouent d’un mouvement rapide : l’ombre que tu formes vient de jaillir. Au loin, un chien se met à hurler ; tu n’en tiens pas compte, comme si ce hurlement se condensait en toi depuis longtemps…

Plus au nord des sépulcres, à l’endroit où le linceul des indigents se désagrège dans leur fosse – laissant s’échapper les gaz dus à la décomposition des cadavres qui s’enflamment aussitôt au contact de l’air -, une flammèche jaunâtre, suivie d’une deuxième, vermillon, tourbillonne tout à coup dans l’air. D’autres naissent, rouges, jaunes, bleu pâle ; feux follets dansant leur ronde folle pour accompagner l’échevin au seuil de son enfer.

Celui-ci n’a pas le temps de s’effrayer de ces esprits de feu, il a perçu une respiration dans son dos. Lente, mesurée, avant qu’elle ne se condense en une expiration échevelée. Il se retourne brusquement, dicté par son instinct, le sentiment, soudain, d’un péril imminent. À ses pieds, l’esconce où brûle un lumignon n’éclaire qu’une large houppelande traînant au sol. La capuche qui lui fait face masque les traits de son agresseur. 

Écarquille les yeux, vil pécheur ! Mammon[2] et sa horde de monstres escortent le porteur de lame. Tu ne les vois pas, mais lui si car il est celui qui châtie en leur nom.

La bouche de l’homme s’arrondit sur l’esquisse d’une question qui reste coincée dans sa gorge : à la peur qui l’a saisi fait maintenant place la douleur lui trouant le cœur. Dans un ultime réflexe de défense, sa main crochète le revers de ta houppelande, puis le lâche.

Ta dague a fait son œuvre. Un coup d’estoc du haut vers le bas. Net, précis. Fiévreux, haineux.

Au loin, le chien s’arrête de hurler. À la verticale des tombes, l’astre nocturne tire sa révérence, absorbé par un taillis de nuages. Les feux follets poursuivent leur ronde macabre. Ton ombre assassine a frappé. On voit ta main couturée d’une pâle cicatrice enfouir quelque chose dans le gosier de ta victime. Une manière de râle – jouissance ? désespérance ? – fuse des tréfonds de ta capuche avant que tu ne traces en lettres de sang, l’index tressautant soudain nerveusement, deux mots sur la pierre de granit : « exempla contraria ».[3] Cela fait, tu te recroquevilles un instant sur toi-même, presses ton poing contre ta tempe, semblant vouloir retenir en toi une force obscure. De ces forces qui peuvent vous emplir, qui sont telle une peau tendue par-dessus d’autres sentiments, plus douloureux. Te dépliant ensuite de nouveau, tu t’esquives. Fuis, hagard. L’on perçoit alors un murmure frôler tes lèvres :

– Si peu de lys parmi les épines. Si peu de lys… Si peu de lys… Si peu…

L’antienne rebondit d’une ruelle à l’autre, exilant ta raison sur des rives que

[1] Bois-le-Duc, chef-lieu actuel de la province du Brabant-Septentrional aux Pays-Bas.

[2] Puissance démoniaque régnant sur la cupidité (prêt à usure, vol, ruse).

[3] « Exemple à ne pas suivre ».

 

2 réflexions au sujet de “Le faiseur de diables”

  1. Anna Maria Corda says:

    Bonjour, j’aimerais savoir si votre dernier Roman, Le faiseur de diables sera disponible en ebook.

    Merci d’avance,

    Anna Maria

  2. Chloe Dubreuil says:

    Bonjour Anna Maria. 🙂 Non malheureusement, mon roman ne sera pas disponible en ebook; mon éditeur n’est pas suffisamment « connu » pour cela. Peut-être dans quelques années… J’espère que vous aurez néanmoins envie de le lire en format papier. Merci à vous, en tout cas, pour votre intérêt.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Required fields are marked *