웬디의 기묘한 이야기

글 작성자: WENDYS
반응형

이번에 크로미움 등 브라우저 URL 전달 시 특수문자, 한글 등 문제 때문에 필요해서 만들어보았습니다.

다른 encoder, decoder에 비해 간단하게 제작이 가능하며, 더 좋은 방법이 있으면 댓글로 달아주세요 :)

 

URL 전달을 위한 urlencode & urldecode

인터넷에서의 URL은 ASCII 문자열을 이용해서만 전송될 수 있는데, 그렇지 않게 전송한 경우 브라우저의 특성에 따라 question mark(?), ampersand(&), 슬래시(/), 공백 문자 같은 특수문자의 경우 잘리거나 의도치않게 변형이 될 수 있습니다.

그래서 이런 특수문자는 인코딩이 되는 것이 좋습니다. ASCII에 포함되지 않는 문자들(한글, 일본어 등등)은 더욱 encoding이 필요하게 됩니다.

인코딩은 %octer 형태로 만들어 주는 것입니다. ex) #은 %23

 

Character Encoding Chart

To help promote the cause of Web Standards and adhering to specifications,

here is a quick reference chart explaining which characters are “safe” and which characters should be encoded in URLs.

Safe characters Alphanumerics [0-9a-zA-Z], special characters $-_.+!*'(),, and reserved characters used for their reserved purposes (e.g., question mark used to denote a query string) NO
ASCII Control characters Includes the ISO-8859-1 (ISO-Latin) character ranges 00-1F hex (0-31 decimal) and 7F (127 decimal.) YES
Non-ASCII characters Includes the entire “top half” of the ISO-Latin set 80-FF hex (128-255 decimal.) YES
Reserved characters ; / ? : @ = & (does not include blank space) YES
Unsafe characters Includes the blank/empty space and " < > # % { } | \ ^ ~ [ ] ` YES

그렇다면 샘플을 한번 보실까요?


#include <iostream>
#include <Windows.h>
#include <string>

char _x2c(
    __in char hex_up, 
    __in char hex_low
    ) {
    char digit;

    digit = 16 * (hex_up >= 'A' ? ((hex_up & 0xdf) - 'A') + 10 : (hex_up - '0'));
    digit += (hex_low >= 'A' ? ((hex_low & 0xdf) - 'A') + 10 : (hex_low - '0'));
    
    return digit;
}

DWORD url_decode(
    __out std::string& output_string,
    __in std::string& encode_string
    ) {

    DWORD error = ERROR_SUCCESS;

    do {

        if (encode_string.empty()) {
            error = ERROR_INVALID_PARAMETER;
            break;
        }

        std::string temp_output_string;

        for (size_t i = 0; i < encode_string.size(); i++) {
            switch (encode_string.at(i)) {
            case '%':
            {
                temp_output_string.push_back(_x2c(encode_string.at(i + 1), encode_string.at(i + 2)));
                i += 2;
            }
            break;

            default:
            {
                temp_output_string.push_back(encode_string.at(i));
            }
            break;

            }
        }

        if (false == temp_output_string.empty()) {
            output_string.assign(temp_output_string);
        }

    } while (false);

    return error;
}

DWORD url_encode(
    __out std::string& output_string,
    __in std::string& plain_string
    ) {
    DWORD error = ERROR_SUCCESS;

    do {

        if (plain_string.empty()) {
            error = ERROR_INVALID_PARAMETER;
            break;
        }

        std::string temp_output_string;

        for (size_t i = 0; i < plain_string.size(); i++) {
            char ch = plain_string.at(i);
            if (isdigit(ch)) {
                temp_output_string.push_back(ch);
            }
            else if (isalpha(ch)) {
                temp_output_string.push_back(ch);
            }
            else if (ch == '$' || // Safe characters 이지만 모두 encoding 해도 무관함.
                ch == '-' ||
                ch == '_' ||
                ch == '.' ||
                ch == '+' ||
                ch == '!' ||
                ch == '*' ||
                ch == '\'' ||
                ch == '(' ||
                ch == ')' ||
                ch == ',') {
                temp_output_string.push_back(ch);
            }
            else {
                char temp[3] = "";
                sprintf_s(temp, "%02x", ch);
                temp_output_string.push_back('%');
                temp_output_string.push_back(temp[0]);
                temp_output_string.push_back(temp[1]);
            }
        }

        if (false == temp_output_string.empty()) {
            output_string.assign(temp_output_string);
        }

    } while (false);

    return error;
}


int main()
{

    do {
        std::string plain_string = "plain & text !@#$%^&*()_+-=,.[]{};:\'\"`";
        std::string encode_string = "";

        DWORD error = url_encode(encode_string, plain_string);
        if (ERROR_SUCCESS != error) {
            break;
        }

        std::string decode_string = "";
        error = url_decode(decode_string, encode_string);

        if (ERROR_SUCCESS != error) {
            break;
        }

        printf(decode_string.c_str());

    } while (false);

    system("pause");
}


 

 

위의 조건에 맞게 작성해보았습니다.

정상 encoding 된 문자열이라면 decoding시 아무런 문제가 없겠지만, 검증이 되지 않은 문자열을 decoding 시도하면 분명 문제가 발생할 수 있습니다.

보장된 상황이 아니라면 추가 작업이 필요할 수 있지만, 기본적으론 사용에 문제가 없어 보이네요!

더 좋은 방법이 있으신 분은 댓글 달아주세요!!

반응형