-
- 1. 브라우저의 GET 요청의 인코딩 판별
-
-
- 1.1. wiki.pl 수정
-
- 1.2. 추가 업데이트 내역
-
- 1.3. 참고 자료
-
- 1.4. 의견
-
1. 브라우저의 GET 요청의 인코딩 판별
IE의 "URL을..." 옵션에 따라서 EUC-KR로 들어오는 페이지 이름을 UTF-8로 바꿔야 한다.
1.1. wiki.pl 수정
다음 함수는 인자로 받은 스트링을 보고, 인코딩을 추측하여 UTF-8로 변환해준다.
- Unicode::CheckUTF8 모듈이 있으면 "legal UTF-8"인지 정확히 알 수 있다. 이건 없어도 큰 지장 없을 듯
- Encode와 Encode::Guess 모듈이 있어야 추측하고 변환하는 것이 가능하다.
- Encode는 웬만한 서버에는 있을 법 하고, Encode::Guess는 모르겠다.
- 무수한 캐릭터셋을 다 대조해볼 수 없기 때문에, 후보군을 넣어야 한다. 아래의 경우는 euc-kr과 utf8 중에서 비교. (utf-8이라고 대쉬를 쓰면 안 된다. 그러면 결과가 "utf-8-strict or utf8" 두 가지로 나온다.)
- 후보군을 한중일 세 언어를 동시에 넣을 수 있으면 좋겠는데, euc-kr과 euc-jp,shift뭐시기 등의 일본어 셋과는 코드가 겹치는 게 많아서, 한글을 넣었는데 일본어로 판단하는 경우가 생겨서 힘들 듯
sub guess_and_convert {
my ($string) = @_;
if ($HttpCharset =~ /utf-8|utf8/i) {
if (eval "require Unicode::CheckUTF8;") {
if (Unicode::CheckUTF8::is_utf8($string)) {
return $string;
}
}
}
if (eval "require Encode; require Encode::Guess;") {
my @suspects = qw(euc-kr utf8);
my $decoder = Encode::Guess::guess_encoding($string, @suspects);
if (ref($decoder)) {
return convert_encode($string, $decoder->name, $HttpCharset);
}
}
return $string;
}
EUC-KR 시퀀스로, %-인코딩된 문자열이, 하필 ?뒤에 쿼리로 들어올 경우(예: wiki.pl?%C0%A7%C5%B0)가 있다. 슬래쉬 링크를 쓰는 이상 현재는 이런 경우가 생기지 않는데, 예전에 ext1.*을 쓰던 당시에 구글에 등록된 주소라거나, 다른 사이트에서 링크를 해둔 경우 등이 있을 수 있다. 이 경우는 쿼리스트링 바꿔치기를 하는 시점에는 아스키 문자열이라서 변환이 안 되므로, 결국 나중에 CGI모듈이 디코딩해 준 것을 가지고 변환을 해야 한다. wiki.pl?페이지이름 의 경우와, id= 파라메터로 들어온 것만이라도 처리해 준다.
sub DoBrowseRequest {
...
if ($id) {
$id = guess_and_convert($id);
if ($FreeLinks && (!-f &GetPageFile($id))) {
$id = &FreeToNormal($id);
}
if (($NotFoundPg ne '') && (!-f &GetPageFile($id))) {
$id = $NotFoundPg;
}
$DocID = $id;
&BrowsePage($id) if &ValidIdOrDie($id);
return 1;
}
$action = lc(&GetParam('action', ''));
$id = &GetParam('id', '');
$id = guess_and_convert($id);
$q->param('id', $id);
$DocID = $id;
...
}
CGI 오브젝트를 생성하기 전에 QUERY_STRING 환경변수의 값을 인코딩 검사를 해서 바꿔치기 해버린다. slashlink 관련 처리도 이 시점에 해 버린다.
sub DoWikiRequest {
...
if ($SlashLinks && (length($ENV{'PATH_INFO'}) > 1)) {
$ENV{'QUERY_STRING'} .= '&' if ($ENV{'QUERY_STRING'});
$ENV{'QUERY_STRING'} .= substr($ENV{'PATH_INFO'}, 1);
}
$ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'});
&InitLinkPatterns();
if (!&DoCacheBrowse()) {
eval $BrowseCode;
&InitRequest() or return;
if (!&DoBrowseRequest()) {
eval $OtherCode;
&DoOtherRequest();
}
}
}
이 지점에서 변경할 때의 장점은,
- UseCache 옵션을 켰을 때도 잘 동작한다.
- 쿼리에 페이지이름이나 id= 이외에 어떤 파라메터에 들어간 한글도 다 인코딩 변환이 된다.
- 나머지 코드 어느 지점이 수정되어도 인코딩 걱정을 할 필요가 없다.
단점...은,
- 이래도 괜찮은 건지 모르겠음 -_-; [comp.lang.perl.misc 그룹]에서는 CGI 모듈을 쓰기로 했으면 CGI모듈에서 제공하는 기능을 사용하라고 말리는 분위기였다. 근데 주인장은 아무리 생각해도 어차피 멀티바이트 캐릭터에만 영향을 미치기 때문에 상관없을 거라 생각하고 있다.
- 요청이 EUC-KR이나 UTF-8일 때만 테스트해보고 있는데, 라틴 언어권에서 요청을 보내면 제대로 되는지 확인할 수 없음. 설마 ext2 버전을 그 동네에서 쓰는 사람이 있을라구 -_-;
1.2. 추가 업데이트 내역
ext2.4a -
2007-03-21, 이제 보니 QUERY_STRING과 PATH_INFO가 넘어오는 방식이 좀 다르다. -_-; 쿼리스트링이 %-인코딩된 상태로 요청이 오면 위키 스크립트에도 그 상태 그대로 넘어오고, 따라서 guess_and_convert를 해도 변환이 안 되고 (아스키니까 -_-;) 만일 EUC-KR 시퀀스로 %-인코딩된 문자열을 쿼리로 받는 경우는 처리가 안 된다. (일반적인 상황에서는 위키의 인코딩과 다른 형태의 인코딩으로, 그걸 다시 %인코딩해서 쿼리로 넘겨주는 링크가 생길 일이 없는데... 검색엔진에 옛날에 수집되었던 주소나, 남이 옛날에 링크를 했던 것들이 이런 문제가 있다. 예를 들어 게시판에 nyxity님이 적은 경우:
구글로 '모카포트' '에스프레소'를 검색하면 각각
nyxity.com/wiki/wiki.pl?%B8%F0%C4%AB%C6%F7%C6%AE <-- 이런 거
nyxity.com/wiki/wiki.pl?%BF%A1%BD%BA%C7%C1%B7%B9%BC%D2
이렇게 페이지가 검색되는데, 클릭하면 페이지가 연결이 안되네요.
할 수 없이, QUERY_STRING에서 %+16진수2개 꼴로 이뤄진 형태를 일단 디코딩한 후에 guess_and_convert에 넘겨주기로 함. 이거 고치면 고칠수록 서버의 플랫폼과 웹서버의 환경에 의존하게 되는 듯.
ext2.5b -
- ext2.4a 의 패치는, 디코딩하지 말아야 하는 것까지 디코딩하는 문제가 있다. OTL 예를 들어 UseModWiki소스수정/웹페이지링크쉽게올리기에서 북마클릿 URL에 들어가는 인자. 따라서 2.4a 의 패치는 주석 처리하고, 예전에 넣었다가 없앤 패치를 다시 적용한다. (CGI모듈을 통해 가져온 인자를 guess_and_convert에 넣음)
생각해보니... 위키를 불러올때 꼭 "wiki.pl/페이지이름" 아니면 "wiki.pl/action=액션이름&id=아이디" 형태만 있는게 아니라서...
- /reverse=페이지이름 - 이건 아예 역링크를 부르는 액션을 action=reverse&id=페이지이름 의 형태로 바꿔버렸고 -_-;
- /search=문자열 - 이렇게 GET으로 특정 문자열 찾기 요청을 할 수도 있고
- /action=links&reverse=페이지이름 - action=links&reverse=UseModWiki소스수정처럼 reverse 파라메터가 또 등장하는 곳도 있고...
등등 따지고 보면 guess_and_convert를 해야 하는 것들이 한 두 군데가 아니다. 게다가 이런 action들은 앞으로도 얼마든지 늘어날 수 있는데 이때마다 파라메터들의 컨버트를 다 챙길수도 없고...
아예, CGI 오브젝트를 만들기 전에 스크립트로 넘어오는 환경변수를 통채로 바꿔치기 하면 어떨까
sub DoWikiRequest {
...
$ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'});
$ENV{'PATH_INFO'} = guess_and_convert($ENV{'PATH_INFO'});
&InitLinkPatterns();
if (!&DoCacheBrowse()) {
eval $BrowseCode;
&InitRequest() or return;
if (!&DoBrowseRequest()) {
eval $OtherCode;
&DoOtherRequest();
}
}
}
위와 같이 생각하여 테스트용 사이트에서 해보니 별 문제 없어 보이긴 하는데, 이렇게 무지막지한 짓을 해도 정말 괜찮은 건지 확신이 안 서고 있습니다. =.=;;
생각해보면 이미 UseModWiki소스수정/SlashLinks처리를 위해서 PATH_INFO 환경변수를 QUERY_STRING으로 옮기는 코드도 있었으니 이것도 비슷하게 봐 줄 수 있을 법 한데... 그럼 말이 난김에 그 코드도 InitRequest가 아니라 이 곳으로 옮기면 캐쉬를 쓰는 경우까지 되지 않을까 싶음.
if ($SlashLinks && (length($ENV{'PATH_INFO'}) > 1)) {
$ENV{'QUERY_STRING'} .= '&' if ($ENV{'QUERY_STRING'});
$ENV{'QUERY_STRING'} .= substr($ENV{'PATH_INFO'}, 1);
}
$ENV{'QUERY_STRING'} = guess_and_convert($ENV{'QUERY_STRING'});
&InitLinkPatterns();
if (!&DoCacheBrowse()) {
eval $BrowseCode;
...
- 음, "이래도 괜찮은 거냐"라는 질문 자체가 "그렇다"라고 대답하기 쉽지 않은 질문이긴 하지만.... [KLDP 질문글]과 [펄매니아 질문글]에 주말이 지나도록 그렇다 아니다 답글이 없어서, [comp.lang.perl.misc 그룹]에도 올림...
위키위키분류