EgoCube.URLTools 컴포넌트와 URLDecode() 메서드 분석

등록일시: 2002-03-15 이전,  수정일시: 2018-04-07 12:16
조회수: 16,596
본문은 최초 작성 이후, 약 22년 이상 지난 문서입니다. 일부 내용은 최근의 현실과 맞지 않거나 동떨어져 있을 수 있으며 문서 내용에 오류가 존재할 수도 있습니다. 또한 본문을 작성하던 당시 필자의 의견과 현재의 의견에 많은 차이가 존재할 수도 있습니다. 이 점, 참고하시기 바랍니다.

URLDecode() 메서드는 URL 인코딩된 문자열을 인자로 받아서 디코딩한 후 본래의 문자열을 리턴한다. 가만히 URLDecode() 메서드의 내부 코드를 살펴보면 작업 내용의 거의 대부분이 URLEncode() 메서드의 작업을 역으로 돌려놓는 것일 뿐이다. 다음은 URLDecode() 메서드의 전체 코드다. 역시 코드 자체가 매우 간단하므로 주석으로 대부분의 설명을 대신한다.

Public Function URLDecode(URLStr As String) As String

    Dim sURL                As String       '** 입력받은 URL 문자열
    Dim sBuffer             As String       '** 디코딩 작업 도중의 URL 을 담을 버퍼 문자열
    Dim cChar               As String       '** URL 문자열 중 현재 인덱스의 문자
    
    Dim Index               As Integer
    
    
    Dim lErrNum             As Long         '** 오류 번호
    Dim sErrSource          As String       '** 오류 소스
    Dim sErrDesc            As String       '** 오류 설명
    
    Dim sMsg                As String       '** 오류 메세지


On Error GoTo ErrorHanddle:


    sURL = Trim(URLStr)     '** URL 문자열을 얻는다.
    sBuffer = ""            '** 임시 버퍼용 문자열 변수 초기화.

    
    '******************************************************
    '* URL 디코딩 작업
    '******************************************************
    
    Index = 1

    Do While Index <= Len(sURL)
    
        cChar = Mid(sURL, Index, 1)
        
        If cChar = "+" Then
        
            '** '+' 문자 :: ' ' 로 대체하여 버퍼 문자열에 추가한다.
            sBuffer = sBuffer & " "
            Index = Index + 1
        
        ElseIf cChar = "%" Then
        
            '** '%' 문자 :: 디코딩하여 버퍼 문자열에 추가한다.
            cChar = Mid(sURL, Index + 1, 2)
            
            If CInt("&H" & cChar) < &H80 Then
            
                '** 일반 ASCII 코드 문자
                sBuffer = sBuffer & Chr(CInt("&H" & cChar))
                Index = Index + 3
            
            Else
            
                '** 2 바이트 한글 문자
                cChar = Replace(Mid(sURL, Index + 1, 5), "%", "")
                sBuffer = sBuffer & Chr(CInt("&H" & cChar))
                Index = Index + 6
            
            End If
            
        Else
        
            '** 그 외의 일반 문자들 :: 버퍼 문자열에 추가한다.
            sBuffer = sBuffer & cChar
            Index = Index + 1
            
        End If
    
    Loop
    
    
    '** 결과를 리턴한다.
    URLDecode = sBuffer
    
    Exit Function
        
    
ErrorHanddle:

    '** 오류가 발생하면 공백 문자를 리턴한다.
    URLDecode = ""
    
    '** 오류 정보를 얻는다.
    lErrNum = Err.Number
    sErrSource = Err.Source
    sErrDesc = Err.Description
    
    '** 이벤트 로그에 오류 내용을 기록한다.
    sMsg = vbCrLf & vbCrLf & _
            "Error Object : EgoCube.URLTools," & vbCrLf & _
            "Error Method : Public Function URLDecode(URLStr As String) As String," & _
            vbCrLf & _
            "Error Number : " & lErrNum & "," & vbCrLf & _
            "Error Source : " & sErrSource & "," & vbCrLf & _
            "Error Description : " & sErrDesc
    App.LogEvent sMsg, vbLogEventTypeError
    
    '** 오류를 발생시킨다.
    Err.Raise lErrNum, sErrSource, sErrDesc

    
    Exit Function
    
    
End Function

URLDecode() 메서드 역시 URLEncode() 메서드와 마찮가지로 인자로 받아들인 문자열을 sURL이라는 변수에 저장하고 가장 첫 문자에서부터 마지막 문자까지 Do ... Loop 문을 돌면서 차례대로 한 문자씩 디코딩 처리한다. URLEncode() 메서드와는 달리 For ... Next 문을 사용하지 않고 Do ... Loop 문을 사용한 이유는 Index 변수의 값이 항상 일정 단위로 증가하는 것이 아니라 경우에 따라 불규칙적으로 증가하므로 프로그래머가 직접 Index 변수의 값을 관리해야 할 필요성이 있기 때문이다. URLDecoding 과정 중에도 역시 모두 3가지 경우가 있을 수 있다.

첫 번째 경우는 현재 문자가 디코딩 할 필요가 없는 문자인 경우다. 즉 a~z, A~Z, 0~10, -, _, ., 그리고, * 같은 문자들은 애초에 인코딩 자체가 되지 않으므로 구태여 디코딩 할 필요가 없다. 따라서, 원래의 문자 그대로 임시 버퍼용 변수 sBuffer에 추가한다. 두 번째 경우는 현재 문자가 '+' 문자인 경우다. 이 경우엔 공백 문자(Space), 즉 빈칸으로 바꿔서 임시 버퍼용 변수 sBuffer에 추가한다. URLEncode() 메서드에서 이와 정 반대의 작업을 했으므로 이는 지극히 당연한 일이다.

마지막 경우는 현재 문자가 '%'인 경우다. 현재 위치의 문자가 '%' 문자라는 것은 임의의 어떤 문자가 인코딩되었고, 그 결과로 '%' 문자와 더불어 '%xx' 또는 '%xx%xx' 형태로 문자열에 추가되었다는 것을 의미한다. 그러므로 현재 문자가 '%' 문자라면 단순히 '%' 문자만을 처리하면 않되고 '%xx' 또는 '%xx%xx' 형태의 완전한 인코딩 문자 조합을 얻은 후 디코딩해야한다.

그런데, 이 때 한 가지 주의해야 할 점이 있다. 그것은 '%' 문자 다음에 있는 URL 인코딩 된 문자가 한글이나 한자와 같은 DBCS 문자가 인코딩 된 것('%xx%xx' 형태)인지, 아니면 일반 특수기호 같은 SBCS 문자가 인코딩 된 것('%xx' 형태)인지를 먼저 파악해야만 한다는 것이다. 만약, DBCS 문자라면 '%c0%ce'('인')와 같이 여섯 개의 문자 조합이 실제 한 개의 문자가 인코딩 된 결과일 테고, SBCS 문자라면 '%3f'('?')와 같이 세 개의 문자 조합이 실제 한 개의 문자가 인코딩 된 결과일 것이다.

이 문제는 URLEncode() 메서드를 정확하게 이해한 분이라면 누구든 쉽게 해결책을 생각해낼 수 있는 문제다. 필자는 URLEncode() 메서드를 설명하면서 DBCS 문자는 ASCII 코드 테이블의 후반부 128개 코드, 즉 128부터 255까지를 조합하여 만들어 낸다고 얘기했다. 따라서, 모든 DBCS 문자는 10진수로 변환했을 때 128(16진수로 80)보다 크거나 같다. 결국, '%' 문자 다음의 두 16진수값, 'xx'와 128과의 크기를 비교해보면 DBCS 문자와 SBCS 문자, 둘 중 어느 쪽이 인코딩 된 것인지를 쉽게 알 수 있다.

비교 결과가 SBCS 문자라면 현재 문자('%')의 다음 문자에서부터 두 문자('%xx' 중 'xx')를 가져와서 Integer 형으로 변환한 후 Chr() 함수를 이용하여 실제 문자를 얻어 임시 버퍼용 변수 sBuffer에 추가하면 된다. 반대로, DBCS 문자라면 현재 문자('%')의 다음 문자에서부터 다섯 문자('%xx%xx' 중 'xx%xx')를 가져와서 '%' 문자를 제거('xxxx')하고 Integer 형으로 변환한 다음, Chr() 함수를 이용하여 실제 문자를 얻어 변수 sBuffer에 추가하면 된다. 위의 코드에서 파란색으로 강조된 부분이 바로 이 작업을 실행하는 코드 부분이다.

그리고, 이전글에서도 말했던 것처럼 URLTools 컴포넌트를 코드만 따로 풀어내어 .inc 파일로 제작하여 ASP에서 #include 지시어를 이용하여 활용하거나 또는 .vbs 파일로 제작하여 HTML 상에서 JScript와 섞어서 사용하는 방법도 고려해 볼만하다. 다음의 링크들은 각각 ASP 용 스크립트 파일과 VBScript 용 스크립트 파일이다. 단, ASP 용 스크립트 파일의 확장자는 .inc 가 아니라 .asp 로 제작하였으므로 착오 없기 바란다.

URLTools_ASP.zip (1.46k)
URLTools_VBs.zip (1.45k)

사실 ASP에서 #include 지시어를 사용하는 방법이나 HTML에서 <script></script> 태그를 사용해서 .js 파일 또는 .vbs 파일을 사용하는 기법은 이제는 널리 알려진 매우 흔한 기법이므로 이에 관하여 따로 설명하지는 않겠다. 그대신 한 가지 매우 재미있는 사실에 대해서 얘기하고 넘어가기로 한다. 그것은 인터넷 익스플로러에서는 말 그대로 JavaScript와 VBScript를 섞어 쓰는 것이 가능하다는 것이다. 즉, 다음과 같은 코드가 가능하다는 뜻이다.

<html>
<head>

    <title>Script Test</title>
    
    <script language="VBScript" src="URLTools.vbs"></script>
    
    <script language="JavaScript">
    <!--
    var OrgMsg;
    var RtnMsg;
    
    OrgMsg = new String("이것은 JavaScript 입니다.");
    RtnMsg = URLEncode(OrgMsg);     '** VBScript 로 작성된 함수를 호출하고 있다.
    
    alert(RtnMsg);
    //-->
    </script>
        
</head>

이하 생략...

이 HTML 문서의 스크립트 코드를 보면 먼저 <script></script> 태그를 사용해서 URLTools.vbs 파일을 참조하고, 참조한 VBScript 내부의 함수를 JavaScript에서 호출하고 있다. 이 스크립트는 인터넷 익스플로러에서 전혀 오류를 발생시키지 않고 정확하게 실행되는데 이와 같은 특성을 교차 언어 지원이라고 한다. 그러나, 이러한 기법이 어떤 웹 브라우저에서나 다 제대로 지원될 것이라고 기대해서는 않된다. 대표적인 예로 Netscape 같은 경우에는 교차 언어 지원은 고사하고 VBScript 자체를 인식하지 못하므로 아예 무시해버리거나 오류를 발생시킨다. 결국 원하는 결과가 나올리 없는 것이다.

필자는 동일한 스크립트를 2002년 3월 현재 Netscape의 가장 최신 버전인 6.2 버전에서 테스트 해봤으나 예상과 같이 정상적으로 동작하지 않았고 비록 명시적인 오류 메세지는 나타나지 않았지만 JavaScript 콘솔(Netscape의 URL 입력란에 'javascript:'라고 입력하고 엔터키를 치면 나타난다)을 띄워보니 'Error: URLEncode is not defined, Source File: http://localhost/test.html, Line: 12' 라는 오류가 발생했다는 것을 알리는 메세지를 볼 수 있었다. 의외로 인터넷 익스플로러에서 교차 언어 지원을 제공한다는 사실을 모르고 계신 분들이 많은데, 정책적으로 브라우저를 제한할 수 있는 인트라넷(Intranet) 개발 환경에서나 인터넷 익스플로러가 전체 브라우저 사용자의 90% 이상을 장악하고 있는 우리나라와 같은 환경에선 종종 요긴하게 써먹을 수 있는 기법이다.

어떤 면에서 URL 인코딩과 URL 디코딩 기능은 지금 무리해서 구현하지 않더라도 곧 정식으로 출시될 .NET CLR에서 기본적으로 지원될 기능이다. 그럼에도 불구하고 굳이 고집스럽게, 그것도 두 차례에 걸쳐서까지 이 글을 적은 이유는 어느 정도는 개인적인 미련 때문이기도 하고 또 어느 정도는 아직까지도 존재하고 있는 기업 환경내의 Windows NT Server 4.0 관리자분들을 위한 것이다.