728x90
반응형

기존에 Java로 만들어진 프로젝트를 Golang으로 다시 만들고 있는데

 

문자열을 gzip으로 압축한 뒤 base64로 인코딩한 결과를 파일명으로 만드는 로직이 있었다.

 

처음엔 Golang에서도 gzip과 base64가 있어 이를 이용하면 당연히 결과가 같을 거라 생각했다.

 

하지만 인코딩한 결과가 Java에서 수행한 결과와 달랐다.

 

그래서 무엇이 다른지 16진수로 결과를 보니 헤더의 OS 값 및 압축된 값이 달랐다.

 

RFC 문서를 보면 다음과 같이 헤더가 정의돼있었다.

+---+---+---+---+---+---+---+---+---+---+
|ID1|ID2|CM |FLG|     MTIME     |XFL|OS | (more-->)
+---+---+---+---+---+---+---+---+---+---+

ID1, ID2는 고정값으로 Java와 Golang 둘 다 1F 8B로 같았다.

 

CM은 압축 방법인데 두 언어 다 deflate(08)로 같았다.

 

FLG는 bit 단위로 설정하는데 0 ~ 3 비트만 설정이 가능하고 나머진 사용하지 않는다.

 

이 값도 두 언어 모두 00으로 같았다.

 

MTIME은 수정 시간으로 이 값 또한 00 00 00 00 으로 같았다.

 

XFL은 추가 플래그로 2 또는 4의 값을 갖는다고 문서에는 나와있으나 두 언어 모두 00으로 돼있었다.

 

마지막으로 OS는 현재 운영체제가 무엇인지 나타내는 값인데 Java에서는 00, Golang에서는 FF였다.

 

헤더에서 OS 값만 달라 0으로 값을 설정했지만 압축한 결과는 여전히 달랐다.

 

코드를 보니 다른 언어들과는 달리 Golang은 deflate를 직접 구현해서 사용하고 있었다.

 

그래서 Golang의 소스를 수정해보려고 했지만 복잡하고 시간이 꽤 걸릴 것 같았다.

 

차선으로 Java, Python 또는 Node로 API 서버를 띄워서 결과값을 반환 받는 방법이 생각했다.

 

이 중에 Python은 특이하게도 MTIME은 수정이 가능하지만 OS는 수정이 불가능했다.

 

하지만 서버 통신이 번거로운 것 같아 shell로 할 수 있는지 찾아보았다.

 

다음과 같이 shell로 만들어서 Java와 같은 결과를 얻을 수 있었다.

echo -n $INPUT | gzip -c | xxd -s 10 -p -u -c 1000000 | xargs printf '1F8B0800000000000000%s' | xxd -r -p | openssl enc -a -A | tr -d '=' | tr '/+' '_-'

echo로 아무 옵션이 없을 때 gzip 결과를 확인해보니 실제 문자열보다 한글자 더 길었다.

 

그래서 -n 옵션을 주어 정확히 해당 문자열만 나오도록 했다.

 

gzip 명령어에서 MTIME과 OS를 변경하는 옵션이 없어 16진수로 변경한 뒤 앞의 헤더를 치환했다.

 

참고 문헌

  1. https://tools.ietf.org/html/rfc1952#page-5

  2. https://github.com/Moodstocks/moodstocks-api-clients/blob/master/bash/base64url.sh

  3. http://fibrevillage.com/scripting/502-how-to-compress-string-in-bash

반응형

'Golang' 카테고리의 다른 글

[Golang] Go의 선(The Zen of Go)  (0) 2020.06.04
[Golang] Kafka 연동 문제  (0) 2020.04.30
[Golang] Go를 사용하면서 발생했던 문제들  (0) 2020.04.23
[Golang] 410 Gone  (0) 2020.01.25
[Golang] Echo 415 에러 해결  (0) 2020.01.25

+ Recent posts