2025년 12월 3일 수요일

redis 역산 - 임시

 import java.time.Instant;

import java.time.LocalDateTime;

import java.time.ZoneId;


public class RedisExpiryCalculator {


    // 처음에 설정한 전체 만료 시간 (7일 = 604,800 초)

    private static final long INITIAL_EXPIRATION_SECONDS = 60 * 60 * 24 * 7; 

    // 초를 밀리초로 변환하는 상수

    private static final long MILLIS_PER_SECOND = 1000L;


    /**

     * Redis TTL 값(초 단위)을 이용하여 데이터가 입력된 시점의 타임스탬프(밀리초)를 계산합니다.

     * * @param currentTTLSeconds getExpire() 메서드가 반환한 현재 남은 TTL (초 단위, long)

     * @return 데이터가 입력된 시점의 UTC 에폭 타임스탬프 (밀리초 단위, long)

     */

    public static long calculateSetTimeMillis(long currentTTLSeconds) {

        // 1. 현재 시간 (시스템 시간)을 밀리초 단위로 가져옵니다.

        long currentTimeMillis = System.currentTimeMillis();


        // 2. 경과된 시간 (초) 계산: (전체 만료 시간) - (현재 남은 TTL)

        long elapsedTimeSeconds = INITIAL_EXPIRATION_SECONDS - currentTTLSeconds;


        // 3. 경과된 시간 (밀리초)로 변환합니다.

        long elapsedTimeMillis = elapsedTimeSeconds * MILLIS_PER_SECOND;


        // 4. 데이터 입력 시점을 계산합니다: (현재 시간) - (경과된 시간)

        long setTimeMillis = currentTimeMillis - elapsedTimeMillis;

        

        // *참고: -1 또는 -2 (키 없음/만료 없음) 같은 특수 값 처리는 Redis 클라이언트 로직에서 필요합니다. 

        // 이 계산 로직은 0보다 큰 TTL 값에 대해서만 유효합니다.


        return setTimeMillis;

    }

    

    // 테스트용 main 메서드

    public static void main(String[] args) {

        // 예시: 현재 TTL이 5일(5 * 24 * 3600 = 432000 초) 남았다고 가정

        long ttlRemaining = 5 * 24 * 3600; 


        long setTime = calculateSetTimeMillis(ttlRemaining);

        

        System.out.println("--- Redis 데이터 입력 시점 계산 결과 ---");

        System.out.println("1. 처음에 설정된 만료 시간: " + INITIAL_EXPIRATION_SECONDS + " 초 (7일)");

        System.out.println("2. 현재 남은 TTL: " + ttlRemaining + " 초 (예시 값)");

        

        // 계산 결과를 사람이 읽을 수 있는 형태로 변환 (시스템 기본 시간대 사용)

        LocalDateTime setDateTime = Instant.ofEpochMilli(setTime)

                                           .atZone(ZoneId.systemDefault())

                                           .toLocalDateTime();


        System.out.println("3. 데이터 입력 시점 (Epoch Millis): " + setTime);

        System.out.println("4. 데이터 입력 시점 (Local Time): " + setDateTime);

    }

}


2025년 11월 17일 월요일

임시

 https://m.ssfshop.com/BEANPOLE-KIDS/GM0025092210943/good

165 - 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0024120587487/good

165 - 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025071840286/good

165 - 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025092210944/good

165 - 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025071058352/good

160 - 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025092210943/good

160 - 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025090468159/good

160-1개  165-1개 


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025081128907/good

140-1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025012463520/good

140-1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025102398867/good

F 사이즈 1개


https://m.ssfshop.com/BEANPOLE-KIDS/GM0025092560744/good

130-1개

2025년 10월 29일 수요일

stackoverflow 나올만한 url 예시

 ### StackOverflowError 재현용 요청

GET http://localhost:8080/test?input=eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(eval(1)))))))))))))))))))))) HTTP/1.1



### HDIV 정규식 StackOverflow 재현 요청
GET http://localhost:8080/test?input=%25%36%35%25%37%36%25%36%31%25%36%43%28%65%76%61%6C%28%31%29%29%28%65%76%61%6C%28%31%29%29%28%65%76%61%6C%28%31%29%29%28%65%76%61%6C%28%31%29%29%28%65%76%61%6C%28%31%29%29%28%65%76%61%6C%28%31%29%29 HTTP/1.1


# 대상 URL과 1000단계의 'next.next...'를 포함하는 데이터 문자열을 생성합니다.

TARGET_URL="http://localhost:8080/hdiv-test/recursive" # Spring Controller의 URL
DEPTH=1000
DATA_PREFIX="data"
DATA_STRING="${DATA_PREFIX}.name=RootValue"

for i in $(seq 1 $DEPTH); do
    DATA_PREFIX="${DATA_PREFIX}.next"
    DATA_STRING="${DATA_STRING}&${DATA_PREFIX}.name=Level${i}"
done

# 생성된 데이터를 포함하여 cURL 요청 실행
curl -X POST "$TARGET_URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "$DATA_STRING"




#!/bin/bash

# 테스트 설정
TARGET_URL="http://localhost:8080/hdiv-test/recursive" # Spring Controller의 URL
# StackOverflowError를 유발하기 위해 최소 1000 이상을 권장합니다.
DEPTH=1500 
OUTPUT_FILE="hdiv_test_data.txt"

# 데이터 문자열 생성 로직
DATA_PREFIX="data"
DATA_STRING="${DATA_PREFIX}.name=RootValue"

for i in $(seq 1 $DEPTH); do
    DATA_PREFIX="${DATA_PREFIX}.next"
    # URL 인코딩된 파라미터를 위해 '&' 대신 개행 문자를 사용합니다. (나중에 cURL에서 처리)
    # 실제로는 cURL의 --data 옵션이 파일 전체를 요청 본문으로 사용하므로, 
    # '&' 문자를 사용하여 파라미터를 연결하는 것이 가장 일반적입니다.
    DATA_STRING="${DATA_STRING}&${DATA_PREFIX}.name=Level${i}"
done

# 생성된 문자열을 파일에 저장
echo "$DATA_STRING" > "$OUTPUT_FILE"

echo "✅ 테스트 데이터가 '$OUTPUT_FILE' 파일에 저장되었습니다. 파라미터 개수: $(($DEPTH + 1))"
echo "---"

# 2. cURL 명령어로 파일 내용 전송 (Git Bash)
# @ 기호를 사용하여 파일 내용을 POST 요청의 본문으로 전송합니다.
curl -X POST "$TARGET_URL" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data "@$OUTPUT_FILE"

echo "---"
echo "테스트 요청이 완료되었습니다. 서버 로그를 확인하세요."


2025년 3월 20일 목요일

csv load 2.5

class CsvProcessor:
    def __init__(self, file_name, dict_fields):
        self.file_name = file_name
        self.dict_fields = dict_fields.split(",")  # 필드명은 쉼표로 분리
        self.data_list = []

    def process_csv(self):
        try:
            # 파일을 열고 처리
            csv_file = open(self.file_name, "r")
            for line in csv_file:
                columns = line.strip().split(",")
                entry = {self.dict_fields[i]: columns[i] for i in range(len(self.dict_fields))}
                self.data_list.append(entry)
            csv_file.close()
        except Exception as e:
            # 새로운 Exception 발생 (원래의 Exception 포함)
            raise RuntimeError("Failed to process the CSV file (%s): %s" % (self.file_name, str(e)))

    def print_data(self):
        for entry in self.data_list:
            print(entry)

# 사용 예시
file_name = "./resources/data.csv"  # CSV 파일 경로
dict_fields = "no,display,amount"

try:
    processor = CsvProcessor(file_name, dict_fields)
    processor.process_csv()
    processor.print_data()
except RuntimeError as e:
    print("Caught RuntimeError: %s" % str(e))

csv 파일 처리

import random  # 랜덤 선택을 위한 모듈

class CsvProcessor:
    def __init__(self, file_name, dict_fields):
        self.file_name = file_name
        self.dict_fields = dict_fields.split(",")  # 필드명은 쉼표로 분리
        self.data_list = []

    def process_csv(self):
        try:
            with open(self.file_name, "r") as csv_file:
                for line in csv_file:
                    # 각 줄을 쉼표로 분리하여 열 데이터 추출
                    columns = line.strip().split(",")
                    # dict_fields를 기준으로 딕셔너리 생성
                    entry = {self.dict_fields[i]: columns[i] for i in range(len(self.dict_fields))}
                    # 숫자 변환 가능하면 정수로 변환
                    for key in entry:
                        if entry[key].isdigit():
                            entry[key] = int(entry[key])
                    self.data_list.append(entry)
        except Exception as e:
            print(f"Error while processing the file: {e}")

    def get_random_entry(self):
        # data_list에서 랜덤으로 하나의 딕셔너리를 반환
        if not self.data_list:
            print("Data list is empty. Please process the CSV file first.")
            return None
        return random.choice(self.data_list)

# 사용 예시
file_name = "./resources/data.csv"  # CSV 파일 경로
dict_fields = "no,display,amount"   # dict 항목명

processor = CsvProcessor(file_name, dict_fields)
processor.process_csv()

# 랜덤 딕셔너리 가져오기
random_entry = processor.get_random_entry()
print(random_entry)

2025년 3월 14일 금요일

Grinder jython 2


class RequestBuilder:
    def __init__(self, grinder_request, logger):
        self.grinder_request = grinder_request
        self.logger = logger
        self.base_url = ""
        self.request_url = ""
        self.port = 80
        self.parameters = {}
        self.cookies = {}

    def set_base_url(self, base_url):
        self.base_url = base_url
        return self

    def set_request_url(self, request_url):
        self.request_url = request_url
        return self

    def set_port(self, port):
        self.port = port
        return self

    def set_parameters(self, params):
        self.parameters.update(params)
        return self

    def set_cookies(self, cookies):
        self.cookies.update(cookies)
        return self

    def build_full_url(self, overrides={}):
        # 호출 시 덮어쓸 속성 가져오기
        active_port = overrides.get("port", self.port)
        active_parameters = overrides.get("parameters", self.parameters)
        param_string = "&".join([f"{k}={v}" for k, v in active_parameters.items()])
        return f"{self.base_url}:{active_port}{self.request_url}?{param_string}"

    def execute_get(self, overrides={}):
        # 동적으로 속성을 덮어쓴 URL 생성
        full_url = self.build_full_url(overrides)
        self.logger.info(f"GET 요청 URL: {full_url}")

        # GET 요청 실행
        response = self.grinder_request.GET(full_url)
        self.logger.info(f"GET 응답: {response.text}")
        return response


from net.grinder.script.Grinder import grinder
from net.grinder.plugin.http import HTTPRequest
from common_module import RequestBuilder

# nGrinder의 HTTP Request 객체 생성
http_request = HTTPRequest()

# Logger 객체 생성
logger = grinder.logger

# RequestBuilder 인스턴스 생성
builder = RequestBuilder(http_request, logger)
builder.set_base_url("http://example.com") \
       .set_request_url("/api/test") \
       .set_port(8080) \
       .set_parameters({"key1": "value1", "key2": "value2"}) \
       .set_cookies({"SESSION": "abc123"})

# 기본 속성으로 GET 요청 실행
get_response = builder.execute_get()
print(f"GET Response: {get_response.text}")

# 덮어쓰기 속성으로 GET 요청 실행
overrides = {
    "port": 9090,
    "parameters": {"key3": "value3", "key4": "value4"}
}
get_response_with_overrides = builder.execute_get(overrides)
print(f"GET Response with Overrides: {get_response_with_overrides.text}")

grinder jython


class RequestBuilder:
    def __init__(self, grinder_request, logger):
        self.grinder_request = grinder_request  # nGrinder의 HTTPRequest 객체
        self.logger = logger  # nGrinder의 Logger 객체
        self.base_url = ""
        self.request_url = ""
        self.port = 80
        self.parameters = {}
        self.cookies = {}

    def set_base_url(self, base_url):
        self.base_url = base_url
        return self

    def set_request_url(self, request_url):
        self.request_url = request_url
        return self

    def set_port(self, port):
        self.port = port
        return self

    def set_parameters(self, params):
        self.parameters.update(params)
        return self

    def set_cookies(self, cookies):
        self.cookies.update(cookies)
        return self

    def build_full_url(self):
        param_string = "&".join([f"{k}={v}" for k, v in self.parameters.items()])
        return f"{self.base_url}:{self.port}{self.request_url}?{param_string}"

    def execute_get(self):
        full_url = self.build_full_url()
        self.logger.info(f"GET 요청 URL: {full_url}")  # 로그 추가

        response = self.grinder_request.GET(full_url)
        self.logger.info(f"GET 응답: {response.text}")  # 응답 로그 기록
        return response

    def execute_post(self):
        full_url = f"{self.base_url}:{self.port}{self.request_url}"
        self.logger.info(f"POST 요청 URL: {full_url}")  # 로그 추가
        self.logger.info(f"POST 요청 데이터: {self.parameters}")  # 요청 데이터 로그

        response = self.grinder_request.POST(full_url, self.parameters)
        self.logger.info(f"POST 응답: {response.text}")  # 응답 로그 기록
        return response

from net.grinder.script.Grinder import grinder
from net.grinder.plugin.http import HTTPRequest
from common_module import RequestBuilder

# nGrinder의 HTTP Request 객체 생성
http_request = HTTPRequest()

# Logger 객체 생성
logger = grinder.logger

# RequestBuilder 인스턴스 생성
builder = RequestBuilder(http_request, logger)
builder.set_base_url("http://example.com") \
       .set_request_url("/api/test") \
       .set_port(8080) \
       .set_parameters({"key1": "value1", "key2": "value2"}) \
       .set_cookies({"SESSION": "abc123"})

# GET 요청 실행 및 로그 출력
get_response = builder.execute_get()
print(f"GET Response: {get_response.text}")

# POST 요청 실행 및 로그 출력
post_response = builder.execute_post()
print(f"POST Response: {post_response.text}")