esc_html__( 'URL is required.', 'advanced-rest-api-devtools' ) ) ); } $allowed_methods = array( 'GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'OPTIONS', 'HEAD' ); $method = strtoupper( $method ); if ( ! in_array( $method, $allowed_methods, true ) ) { wp_send_json_error( array( 'message' => esc_html__( 'Invalid HTTP method.', 'advanced-rest-api-devtools' ) ) ); } // Replace variables. $active_vars = Aradt_Utils::get_active_variables(); $url = Aradt_Utils::replace_variables( $url, array(), array(), $active_vars ); $body = Aradt_Utils::replace_variables( $body, array(), array(), $active_vars ); if ( is_array( $headers ) ) { $headers = Aradt_Utils::replace_variables_in_headers( $headers, array(), array(), $active_vars ); } else { $headers = array(); } // Pre-request script: simple variable assignments. if ( ! empty( $pre_script ) ) { $script_vars = self::execute_pre_script( $pre_script ); if ( ! empty( $script_vars ) ) { $url = Aradt_Utils::replace_variables( $url, $script_vars ); $body = Aradt_Utils::replace_variables( $body, $script_vars ); $headers = Aradt_Utils::replace_variables_in_headers( $headers, $script_vars ); } } // Build full URL — if relative, make absolute to site REST URL. if ( ! str_starts_with( $url, 'http' ) ) { $rest_url = rest_url(); $url = rtrim( $rest_url, '/' ) . '/' . ltrim( $url, '/' ); } // Auth headers. $headers = self::apply_auth( $headers, $auth, $auth_value ); // Build request args. $request_args = array( 'method' => $method, 'headers' => $headers, 'timeout' => 30, 'sslverify' => false, // Loopback — safe for local dev. ); if ( ! empty( $body ) && in_array( $method, array( 'POST', 'PUT', 'PATCH' ), true ) ) { $request_args['body'] = $body; } // Add cookie auth if selected. if ( 'cookie' === $auth ) { $request_args['cookies'] = $_COOKIE; // Also add nonce header for WP REST cookie auth. $request_args['headers']['X-WP-Nonce'] = wp_create_nonce( 'wp_rest' ); } // Profile: start timing. $start_time = microtime( true ); // Send request. $response = wp_remote_request( $url, $request_args ); $end_time = microtime( true ); $total_time = round( ( $end_time - $start_time ) * 1000, 2 ); if ( is_wp_error( $response ) ) { wp_send_json_error( array( 'message' => $response->get_error_message(), 'time_ms' => $total_time, ) ); } $response_code = wp_remote_retrieve_response_code( $response ); $response_message = wp_remote_retrieve_response_message( $response ); $response_headers = wp_remote_retrieve_headers( $response )->getAll(); $response_body = wp_remote_retrieve_body( $response ); // Run assertions. $assertion_results = array(); if ( ! empty( $assertions ) ) { $assertion_results = Aradt_Utils::run_assertions( $assertions, $response_code, $response_body, $response_headers ); } // Try to pretty-format JSON body. $json_body = json_decode( $response_body, true ); $is_json = ( json_last_error() === JSON_ERROR_NONE ); $result = array( 'status' => $response_code, 'status_text' => $response_message, 'headers' => $response_headers, 'body' => $is_json ? $json_body : $response_body, 'body_raw' => $response_body, 'is_json' => $is_json, 'time_ms' => $total_time, 'size_bytes' => strlen( $response_body ), 'assertions' => $assertion_results, ); // Save to history. self::save_to_history( array( 'method' => $method, 'url' => $url, 'headers' => $headers, 'body' => $body, 'auth_type' => $auth, 'status' => $response_code, 'time_ms' => $total_time, 'timestamp' => current_time( 'mysql' ), ) ); wp_send_json_success( $result ); } /** * Execute pre-request script (simple variable assignments). * * Supports: pm.variables.set("key", "value") and pm.variables.set("key", Date.now()) * * @param string $script Pre-request script text. * @return array Variables extracted. */ private static function execute_pre_script( $script ) { $vars = array(); $lines = explode( "\n", $script ); foreach ( $lines as $line ) { $line = trim( $line ); if ( empty( $line ) || str_starts_with( $line, '//' ) ) { continue; } // pm.variables.set("key", "value") if ( preg_match( '/pm\.variables\.set\(\s*["\'](\w+)["\']\s*,\s*["\'](.+?)["\']\s*\)/', $line, $matches ) ) { $vars[ $matches[1] ] = $matches[2]; } // pm.variables.set("key", Date.now()) elseif ( preg_match( '/pm\.variables\.set\(\s*["\'](\w+)["\']\s*,\s*Date\.now\(\)\s*\)/', $line, $matches ) ) { $vars[ $matches[1] ] = (string) time(); } // pm.variables.set("key", Math.random()) elseif ( preg_match( '/pm\.variables\.set\(\s*["\'](\w+)["\']\s*,\s*Math\.random\(\)\s*\)/', $line, $matches ) ) { $vars[ $matches[1] ] = (string) wp_rand( 0, 999999 ); } } return $vars; } /** * Apply authentication to headers. * * @param array $headers Existing headers. * @param string $auth_type Auth type. * @param string $auth_value Auth value (token, user:pass, etc.). * @return array Modified headers. */ private static function apply_auth( $headers, $auth_type, $auth_value ) { switch ( $auth_type ) { case 'bearer': $headers['Authorization'] = 'Bearer ' . $auth_value; break; case 'basic': $headers['Authorization'] = 'Basic ' . base64_encode( $auth_value ); break; case 'app_password': // App passwords use Basic auth format: username:app_password. $headers['Authorization'] = 'Basic ' . base64_encode( $auth_value ); break; case 'cookie': // Handled in request args directly. break; case 'custom': if ( ! empty( $auth_value ) ) { $headers['Authorization'] = $auth_value; } break; } return $headers; } /** * Save a request to history (transient-based, capped). * * @param array $entry History entry data. */ private static function save_to_history( $entry ) { $settings = get_option( 'aradt_settings', array() ); $limit = isset( $settings['history_limit'] ) ? (int) $settings['history_limit'] : 100; $history = get_transient( 'aradt_request_history' ); if ( ! is_array( $history ) ) { $history = array(); } // Prepend new entry. array_unshift( $history, $entry ); // Cap the size. if ( count( $history ) > $limit ) { $history = array_slice( $history, 0, $limit ); } // Use a long transient (30 days) — effectively persistent but auto-cleans. set_transient( 'aradt_request_history', $history, 30 * DAY_IN_SECONDS ); } /** * AJAX: Get request history. */ public static function ajax_get_history() { check_ajax_referer( 'aradt_nonce', 'nonce' ); Aradt_Utils::verify_ajax_request(); $history = get_transient( 'aradt_request_history' ); if ( ! is_array( $history ) ) { $history = array(); } wp_send_json_success( array( 'history' => $history ) ); } /** * AJAX: Clear request history. */ public static function ajax_clear_history() { check_ajax_referer( 'aradt_nonce', 'nonce' ); Aradt_Utils::verify_ajax_request(); delete_transient( 'aradt_request_history' ); wp_send_json_success( array( 'message' => esc_html__( 'History cleared.', 'advanced-rest-api-devtools' ) ) ); } /** * AJAX: Generate code snippet. */ public static function ajax_generate_code() { check_ajax_referer( 'aradt_nonce', 'nonce' ); Aradt_Utils::verify_ajax_request(); $method = isset( $_POST['method'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['method'] ) ) : 'GET'; $url = isset( $_POST['url'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['url'] ) ) : ''; $headers = isset( $_POST['headers'] ) ? Aradt_Utils::sanitize_recursive( Aradt_Utils::safe_json_decode( sanitize_textarea_field( wp_unslash( (string) $_POST['headers'] ) ) ) ) : array(); $body = isset( $_POST['body'] ) ? sanitize_textarea_field( wp_unslash( (string) $_POST['body'] ) ) : ''; $format = isset( $_POST['format'] ) ? sanitize_key( wp_unslash( (string) $_POST['format'] ) ) : 'curl'; if ( ! is_array( $headers ) ) { $headers = array(); } $code = Aradt_Utils::generate_code( $method, $url, $headers, $body, $format ); wp_send_json_success( array( 'code' => $code ) ); } }