package com.eactive.testmaster.client.service; import com.eactive.testmaster.client.dto.ApiRequestDTO; import com.eactive.testmaster.client.dto.ApiRequestKeyValueDTO; import io.netty.util.CharsetUtil; import java.nio.charset.Charset; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; public class RequestCharsetUtils { private static final Pattern CHARSET_PATTERN = Pattern.compile("charset\\s*=\\s*([^;\\s]+)", Pattern.CASE_INSENSITIVE); private static final String CONTENT_TYPE_HEADER = "Content-Type"; private static final Charset DEFAULT_CHARSET = determineDefaultCharset(); /** * Determines the default charset based on system properties * Falls back to UTF-8 if system encoding is not available or invalid */ private static Charset determineDefaultCharset() { try { String systemEncoding = System.getProperty("file.encoding"); if (StringUtils.isNotBlank(systemEncoding)) { return Charset.forName(systemEncoding); } } catch (IllegalArgumentException | SecurityException e) { // Log warning about fallback to UTF-8 } return CharsetUtil.UTF_8; } /** * Extracts charset from request headers with fallback to system default charset * @param apiRequest The API request containing headers * @return The detected charset or system default charset */ public static Charset extractRequestCharset(ApiRequestDTO apiRequest) { if (apiRequest == null || apiRequest.getHeaders() == null) { return DEFAULT_CHARSET; } return apiRequest.getHeaders().stream() .filter(ApiRequestKeyValueDTO::isEnabled) .filter(header -> CONTENT_TYPE_HEADER.equalsIgnoreCase(header.getKey())) .findFirst() .map(RequestCharsetUtils::parseCharsetFromContentType) .orElse(DEFAULT_CHARSET); } /** * Parses charset from Content-Type header value * @param contentTypeHeader The Content-Type header DTO * @return The detected charset or system default charset */ private static Charset parseCharsetFromContentType(ApiRequestKeyValueDTO contentTypeHeader) { String contentType = contentTypeHeader.getValue(); if (StringUtils.isBlank(contentType)) { return DEFAULT_CHARSET; } Matcher matcher = CHARSET_PATTERN.matcher(contentType); if (matcher.find()) { String charsetName = matcher.group(1).trim(); try { return Charset.forName(charsetName); } catch (IllegalArgumentException e) { // Log warning about unsupported charset return DEFAULT_CHARSET; } } // Handle common content types without explicit charset if (contentType.contains("application/json")) { return CharsetUtil.UTF_8; // JSON should always use UTF-8 per RFC 8259 } return DEFAULT_CHARSET; } }