http — HTTP/1.1 클라이언트 구현

http — HTTP/1.1 클라이언트 구현

Tcl에서 웹 서버에 요청을 보내 데이터를 가져와야 할 때가 있어요. GET, POST, HEAD를 지원하고 프록시 설정까지 갖춘 http 패키지가 그 역할을 해요.

출처: Tcl Bundled Packages — http

본문

사용 준비

package require http ?2.9?

http 패키지는 RFC 7230~7235에 정의된 HTTP/1.1 프로토콜의 클라이언트 쪽을 구현해요(RFC 2616을 대체). HTTP/1.1의 GET, POST, HEAD 연산을 구현하고, 방화벽을 통과하기 위한 프록시 호스트 설정을 지원해요. Safesock 보안 정책과 호환돼서 신뢰할 수 없는 애플릿이 제한된 호스트 집합에서 URL을 가져오는 용도로도 쓸 수 있어요. ::http::register로 커스텀 소켓 명령어를 제공하면 HTTPS 같은 추가 HTTP 전송 프로토콜을 지원하도록 확장할 수도 있어요.

내보내는 명령어: http 네임스페이스는 config, formatQuery, geturl, quoteString, register, registerError, reset, unregister, wait를 내보내요. 반면 cleanup, code, data, error, meta, ncode, size, status는 내보내지 않아요.

주요 동작

::http::geturl은 HTTP 트랜잭션을 수행해요. 옵션에 따라 GET, POST, HEAD 중 하나로 동작해요. 반환값은 트랜잭션의 토큰(token) 인데, 이 값은 ::http 네임스페이스 안에 있는 트랜잭션 상태 정보를 담는 배열의 이름이기도 해요.

-command 옵션을 지정하면 HTTP 작업이 백그라운드로 진행돼요. ::http::geturl은 HTTP 요청을 만든 뒤 즉시 반환하고, 트랜잭션이 끝나면 콜백을 호출해요. 그러려면 Tcl 이벤트 루프가 활성화되어 있어야 해요. Tk 애플리케이션에선 항상 그렇지만, 순수 Tcl 애플리케이션에선 ::http::geturl 뒤에 ::http::wait를 호출해 이벤트 루프를 시작할 수 있어요. -command 옵션이 없어도 이벤트 큐는 사용되므로, http::geturl이 도는 동안 임의의 명령어가 처리될 수 있어요.

구성 명령어 ::http::config

::http::config는 프록시 서버, 포트, HTTP 요청에 쓰는 User-Agent 이름을 설정하고 조회해요.

  • -accept mimetypes — 요청의 Accept 헤더. 기본은 */*(모든 문서 타입 수용). 쉼표로 구분한 mime 타입 패턴 목록을 줄 수 있어요(예: image/gif, image/jpeg, text/*).
  • -pipeline boolean — 영속 소켓에서 HTTP/1.1 트랜잭션을 파이프라인으로 처리할지. 기본은 1.
  • -postfresh boolean — POST 메서드 요청이 항상 새 소켓을 쓰도록 해 http::geturl-keepalive 옵션을 무시할지. 기본은 0.
  • -proxyhost hostname — 프록시 호스트 이름. 빈 문자열이면 URL 호스트에 직접 접속.
  • -proxyport number — 프록시 포트 번호.
  • -proxyfilter command::http::geturl 중 주어진 호스트에 프록시가 필요한지 판단하는 콜백. 호출 시 호스트 이름 인자가 하나 추가돼요. 프록시가 필요하면 프록시 서버와 프록시 포트를 담은 두 요소 리스트를, 아니면 빈 리스트를 반환해요. 기본 필터는 -proxyhost·-proxyport 값이 비어 있지 않으면 그 값을 반환해요.
  • -repost boolean — 영속 연결에서 POST 요청이 서버가 연결을 반쯤 닫아서 실패했을 때 어떻게 할지. true면 자동 재시도, false면 재시도를 위해 사용자 확인을 받도록 애플리케이션에 맡겨요. true는 특정 조건에서만 써야 해요. 기본은 0.
  • -urlencoding encoding::http::formatQuery·::http::quoteString이 x-url-encoded URL을 만들 때 쓰는 인코딩. 기본은 RFC 2718이 정한 utf-8. http 2.5 이전엔 불특정이었고, 빈 문자열({})을 지정하면 그 동작으로 돌아가요. 다만 iso8859-1을 권장해요(비 라틴-1 문자 처리 시 오류를 내지 않는 비슷한 동작).
  • -useragent string — HTTP 요청의 User-Agent 헤더 값. 안전하지 않은 인터프리터에서 기본값은 OS와 http·Tcl 버전에 따라 다르며 예를 들면 Mozilla/5.0 (Windows; U; Windows NT 10.0) http/2.9.0 Tcl/8.6.9예요. 안전한 인터프리터는 OS를 알 수 없어 기본적으로 Windows 10 값에 현재 http·Tcl 버전 번호를 써요.
  • -zip booleantrue면 기본적으로 요청이 Accept-Encoding: gzip,deflate,compress 헤더를 보내고, false면 보내지 않아요. 두 경우 모두 개별 요청에서 http::geturl-headers 옵션으로 커스텀 Accept-Encoding 헤더를 주면 재정의할 수 있어요. 기본은 1.

요청 명령어 ::http::geturl

::http::geturl은 패키지의 핵심 프로시저예요. -query 옵션은 POST, -validate 옵션은 HEAD 동작을 만들고, 그 외에는 GET을 수행해요. -command 옵션으로 완료 시 불릴 콜백을 지정하지 않으면 트랜잭션이 끝날 때까지 블로킹돼요. 주요 옵션:

  • -binary boolean — URL 데이터를 강제로 바이너리로 해석할지. 보통은 자동 판별돼요(텍스트 콘텐츠 타입으로 시작하지 않거나 콘텐츠 인코딩이 gzip·compress이면 바이너리로 간주).
  • -blocksize size — URL을 읽을 때 한 번에 읽는 최대 바이트 수. 블록마다 -progress 콜백(지정 시)을 호출해요.
  • -channel name — URL 내용을 state(body)에 저장하는 대신 채널 name으로 복사.
  • -command callback — HTTP 트랜잭션이 끝난 뒤 콜백 호출. 이 옵션이 있으면 ::http::geturl이 즉시 반환해요. 콜백은 ::http::geturl이 반환한 토큰을 추가 인자로 받아요. 템플릿:
    proc httpCallback {token} {
        upvar #0 $token state
        # Access state as a Tcl array
    }
    
  • -handler callback — HTTP 데이터가 유효할 때마다 콜백 호출. 있으면 HTTP 데이터로 다른 일을 하지 않아요. 이 프로시저는 HTTP 데이터용 소켓과 토큰 두 추가 인자를 받고, 소켓에서 읽은 바이트 수를 반환해야 해요. 템플릿:
    proc httpHandlerCallback {socket token} {
        upvar #0 $token state
        set data [read $socket 1000]
        set nbytes [string length $data]
        return $nbytes
    }
    
    -handler는 압축·청크 전송 인코딩과 호환되지 않아서, 지정하면 http::geturl은 HTTP 프로토콜을 1.0으로 낮추고 -zip 옵션을 무시해요. -handler-channel을 함께 쓰면 핸들러가 HTTP 소켓에서 지정 채널로 데이터를 복사하는 책임을져요(채널 이름은 -channel 요소로 접근 가능).
  • -headers keyvaluelist — HTTP 요청에 추가할 헤더. 키-값이 번갈아 나오는 짝수 요소 리스트여야 해요. 키가 헤더 필드 이름이 되고, 값의 개행 문자는 제거돼서 헤더가 훼손되지 않아요. 예: Pragma no-cachePragma: no-cache.
  • -keepalive booleantrue면 여러 요청을 처리하기 위해 연결을 열어 두려고 시도. 기본 0.
  • -method type — HTTP 요청 메서드를 강제. 보통 다른 옵션으로 GET/POST/HEAD가 자동 선택되지만 이 옵션이 재정의하며, WebDAV 지원을 위한 PUT·DELETE 같은 선택지를 쓸 수 있게 해요. 헤더와 요청 본문이 요청 메서드 요구에 맞는지 확인할 책임은 호출자에게 있어요(예: 빈 본문의 POST는 -headers {Content-Length 0}도 함께 줘야 함).
  • -myaddr address — 여러 인터페이스가 있을 때 내부 소켓 호출에 특정 로컬 주소를 전달.
  • -progress callback — URL에서 데이터를 전송할 때마다 콜백 호출. 토큰, Content-Length 메타데이터의 예상 총 크기, 지금까지 전송된 바이트 수의 세 추가 인자를 받아요. 예상 총 크기를 모르면 0이 전달돼요.
  • -protocol version — 사용할 HTTP 프로토콜 버전. 1.0 또는 1.1(기본). HTTP/1.1을 이해 못 하거나 불평하는 서버일 때만 필요.
  • -query query — 값이 비어 있지 않으면 POST 요청을 만들어 query 문자열을 요청 페이로드 그대로 서버에 전달. 콘텐츠 형식·인코딩은 -type 옵션이 정한 Content-Type 헤더가 알려줘요. -type을 지정하지 않으면 기본 application/x-www-form-urlencoded이고, 이 경우 query는 x-url-encoding 형식이어야 해요(HTML 폼에서 제출되는 POST와 동일). 포맷은 ::http::formatQuery로 만들 수 있어요.
  • -queryblocksize size — URL에 쿼리 데이터를 보낼 때 한 번에 쓰는 최대 바이트 수. 블록마다 -queryprogress 콜백(지정 시) 호출.
  • -querychannel channelID — POST 요청으로 channelID의 데이터를 서버에 전달. -type 옵션을 쓰지 않으면 데이터는 x-url-encoding 형식이어야 해요. -headers로 Content-Length 헤더를 지정하지 않으면 ::http::geturl이 post 데이터 크기를 알아내 그 헤더를 만들려고 해요. 크기를 알 수 없으면 오류를 반환해요.
  • -queryprogress callback — URL에 데이터를 보낼 때마다(POST) 호출. -progress와 동일하게 동작·형식.
  • -strict boolean — 요청에 RFC 3986 URL 검증을 적용할지. 기본 1.
  • -timeout milliseconds — 0이 아닌 값이면 그 밀리초 후 타임아웃을 설정해요. 타임아웃이 되면 ::http::reset과(지정 시) -command 콜백을 호출해요. 타임아웃 후 ::http::status의 반환값은 timeout이에요.
  • -type mime-type — POST 작업 시 기본값(application/x-www-form-urlencoded) 대신 이 값을 Content-Type으로 사용.
  • -validate boolean — 0이 아닌 값이면 HTTP HEAD 요청을 수행. URL의 메타 정보만 반환하고 내용은 반환하지 않아요. 메타 정보는 트랜잭션 후 state(meta) 변수에서 볼 수 있어요.

유틸리티 명령어

  • ::http::formatQuery key value ?key value ...? — 쿼리 데이터를 x-url-encoding. 짝수 인자를 받아 키·값을 인코딩하고 &= 구분자가 맞게 들어간 하나의 문자열을 생성해요. ::http::geturl-query 값으로 적합해요.
  • ::http::quoteString value — 단일 문자열을 x-url-encoding.
  • ::http::reset token ?why?token이 식별하는 트랜잭션을 리셋. state(status)why(기본 reset)로 설정하고 등록된 -command 콜백을 호출.
  • ::http::wait token — 트랜잭션이 끝날 때까지 블로킹·대기하는 편의 프로시저. vwait을 쓰므로 신뢰할 수 있는 코드에서만 동작해요. -command 없이 호출한 경우엔 ::http::geturl이 이미 끝날 때까지 반환하지 않으므로 쓸모없어요.
  • ::http::data tokenstate 배열의 body 요소(URL 데이터) 반환.
  • ::http::error tokenstate 배열의 error 요소 반환.
  • ::http::status tokenstate 배열의 status 요소 반환.
  • ::http::code tokenstate 배열의 http 요소 반환.
  • ::http::ncode tokenhttp 요소에서 숫자 반환 코드(200, 404 등)만 추출.
  • ::http::size tokencurrentsize 요소 반환(URL에서 받은 바이트 수).
  • ::http::meta token — HTTP 응답 헤더를 담는 meta 요소 반환.
  • ::http::cleanup tokentoken이 식별하는 연결과 관련된 상태를 정리. 이 호출 후에는 ::http::data 같은 프로시저로 정보를 얻을 수 없어요. HTTP 요청을 끝낸 뒤엔 이 함수를 호출할 것을 강력히 권장해요. 호출하지 않으면 메모리가 해제되지 않아, ::http::geturl을 충분히 여러 번 호출하면 메모리 누수가 성능 저하...아니면 더 나쁜 결과를 낼 수 있어요.
  • ::http::register proto port command — HTTPS 같은 커스텀 HTTP 전송 타입을 지원하도록 접두사·기본 포트·Tcl 채널 생성 명령어를 등록. 예:
    package require http
    package require tls
    ::http::register https 443 ::tls::socket
    set token [::http::geturl https://my.secure.site/]
    
  • ::http::registerError port ?message? — 등록된 프로토콜 핸들러가 http에 전달할 오류 메시지를 제공. 이 명령어는 오류를 일으키지 않아요. 등록된 프로토콜이 문제(예: 유효하지 않은 TLS 인증서)를 감지해 http로 오류가 전파될 때 유용하며, http가 일반 오류보다 정확한 오류 메시지를 내도록 해요. 마지막 호출에서 인자 message로 준 값을 반환하고, 그런 호출이 없었으면 빈 문자열을 반환해요.
  • ::http::unregister proto — 이전에 ::http::register로 등록한 프로토콜 핸들러를 등록 해제. 이전에 설치된 핸들러가 있었으면 기본 포트와 핸들러 명령어의 두 항목 리스트를 반환하고, 없었으면 오류를 반환해요.

오류 (ERRORS)

::http::geturl은 다음 경우에 오류를 일으켜요: 잘못된 명령줄 옵션, 잘못된 URL, 존재하지 않는 호스트의 URL, 존재하는 호스트의 잘못된 포트 URL. 이런 오류는 네트워크 트랜잭션을 시작조차 못 한다는 뜻이에요. HTTP 요청 헤더를 쓰다 I/O 오류가 나도 오류를 일으켜요. 동기 호출(-command 미지정)에선 응답 헤더나 데이터를 읽다 I/O 오류가 나도 오류를 일으켜요. 이 경우 ::http::geturl은 토큰을 반환하지 않으므로 필요한 정리를 모두 수행해 ::http::cleanup을 호출할 필요가 없어요.

비동기(-command) 호출에선 위 오류 상황이 모두 적용되지만, 응답 헤더·데이터를 읽는 중 오류가 나도 예외는 발생하지 않아요. HTTP 헤더를 쓴 뒤 ::http::geturl이 반환되고 나머지는 백그라운드에서 일어나기 때문이에요. 명령어 콜백은 ::http::status로 상태를 확인하고 오류면 ::http::error로 메시지를 얻을 수 있어요. 또는 주 프로그램 흐름이 비동기 요청 결과를 알아야 하는 지점에 도달하면 ::http::wait를 호출한 뒤 콜백처럼 status·error를 확인할 수 있어요.

::http::geturl-command, -handler, -proxyfilter 콜백을 catch 안에서 실행해요. 그래서 콜백의 오류는 bgerror 핸들러를 호출하지 않아요. 이런 콜백을 디버깅할 땐 콜백 안에서 catch를 써 오류를 stdout에 쓰는 게 편리해요. 어떤 경우든 끝나면 ::http::cleanup으로 상태 배열을 삭제해야 해요.

::http::status로 확인하는 트랜잭션의 다른 결과 상태는 다음과 같아요.

  • ok — 트랜잭션이 완전히 끝나면 ok. 그래도 ::http::code 값을 확인해 HTTP 상태를 봐야 해요. ::http::ncode는 숫자 오류(200, 404, 500)만, ::http::codeHTTP 404 File not found 같은 값을 반환해요.
  • eof — 서버가 응답 없이 소켓을 닫으면 오류는 없지만 상태가 eof.
  • error — 오류 메시지가 state(error) 요소에도 저장돼 ::http::error로 접근 가능.
  • timeout — 트랜잭션이 끝나기 전에 타임아웃 발생.
  • reset — 사용자 리셋.

또 다른 오류 가능성은 ::http::geturl이 서버가 응답하고 소켓을 닫기 전에 모든 post 쿼리 데이터를 쓰지 못하는 경우예요. 오류 메시지는 state(posterror) 요소에 저장되고 ::http::geturl은 트랜잭션 완료를 시도해요. 서버 응답을 읽을 수 있으면 ok, 아니면 eof 상태가 돼요.

상태 배열 (STATE ARRAY)

::http::geturl이 반환하는 토큰으로 트랜잭션 상태에 Tcl 배열로 접근할 수 있어요. upvar #0 $token state로 쓰기 쉬운 배열 변수를 만들 수 있어요. URL 데이터가 더 이상 필요 없으면 상태 배열을 unset해 저장 공간을 해제해야 하고, 그 용도로 ::http::cleanup이 제공돼요.

지원되는 배열 요소:

  • binary — (Content-Encoding 응답 헤더가 지정한 압축을 디코딩한 후) HTTP 응답이 바이너리면 true, 텍스트면 false.
  • body — URL의 내용. -channel 옵션을 지정하면 비어 있어요. ::http::data가 반환하는 값.
  • charset — Content-Type 메타데이터의 charset 속성 값. 지정되지 않으면 RFC 표준 iso8859-1 또는 $::http::defaultCharset 값. 들어오는 텍스트 데이터는 이 charset에서 utf-8로 자동 변환돼요.
  • coding — Content-Encoding 메타데이터 값의 복사본.
  • currentsize — URL에서 지금까지 가져온 바이트 수. ::http::size가 반환하는 값.
  • error — 정의돼 있으면 트랜잭션이 중단될 때 본 오류 문자열.
  • http — 서버의 HTTP 상태 응답. ::http::code가 반환하는 값. 형식은 HTTP/1.1 code string. code는 HTTP 표준의 세 자리 숫자로, 200이 OK. 4·5로 시작하면 오류, 3으로 시작하면 리다이렉션 오류(이 경우 Location 메타데이터가 새 URL을 지정).
  • meta — HTTP 프로토콜이 반환하는 URL 내용 설명 메타데이터. 키와 값의 리스트로, array set meta $state(meta)처럼 메타데이터만 담는 배열 초기화에 적합한 형식이에요. 주요 키: Content-Type(내용 타입, 예: text/html, image/gif, application/x-tcl), Content-Length(광고된 크기 — 실제 크기는 state(currentsize)), Location(요청한 데이터를 담은 대체 URL). HTTP 표준이 더 많은 키를 정의하고 서버가 자체 키를 추가할 수도 있어요.
  • posterror — post 쿼리 데이터를 서버에 쓰는 동안 발생한 오류(있다면).
  • status — 위 ERRORS 장 참고. 트랜잭션 중엔 빈 문자열.
  • totalsize — Content-Length 메타데이터 값의 복사본.
  • type — Content-Type 메타데이터 값의 복사본.
  • url — 요청한 URL.

영속 연결 (PERSISTENT CONNECTIONS)

기본: 영속 연결은 여러 HTTP/1.1 트랜잭션을 같은 TCP 연결로 처리하게 해요. 파이프라이닝은 클라이언트가 각 응답을 기다리지 않고 영속 연결에 여러 요청을 보내는 것이고, 서버는 요청을 받은 순서대로 응답을 보내요. POST 요청이 실패하면 보통 재전송 전에 사용자 확인이 필요해요(실패한 POST가 서버를 수정했는지 확인하고 싶을 수 있으므로).

HTTP 요청은 http::geturl 호출에 -keepalive true 옵션이 있으면 영속 소켓을 사용해요. http::config 옵션 -pipelinetrue(기본값)면 허용되는 곳에서 파이프라이닝을 사용해요.

http 패키지는 각 서버(즉 각 domain:port 값)에 영속 연결을 하나만 유지해요. 영속 연결이 다른 요청으로 바쁜데 그 위로 요청하면, 연결이 자유로울 때까지 큐에 보관돼요. http 패키지는 Keep-Alive 헤더로 제어되는 HTTP/1.0 영속 연결은 지원하지 않아요.

특수 경우: RFC 7230에 따라 http::geturl은 POST 메서드를 쓰는 요청을 파이프라인으로 처리하지 않아요. POST가 영속 연결을 쓰는데 그 연결의 첫 요청이 아니면, 이전 요청의 응답을 받을 때까지 기다리거나(-postfreshfalse면), POST마다 새 연결을 써요(-postfresh true). 서버가 파이프라인 요청들을 처리하다 마지막이 아닌 응답에 Connection: close 헤더를 보내면 이후 응답은 이행되지 않아요. http::geturl은 이행되지 않은 요청을 새 연결로 다시 보내요.

HTTP 클라이언트가 한동안 유휴 상태였던 영속 연결에 요청을 보낼 때 어려움이 생겨요. HTTP 서버가 겉보기에 유휴인 연결을 반쯤 닫아버렸는데 클라이언트가 요청을 보내는 중이라면(요청이 서버에 도착하기 전에, '비동기 닫힘 이벤트'), 요청은 실패해요. HEAD·GET 요청이면 http::geturl이 다른 연결을 열어 재전송하지만, POST면 RFC 7230이 기본적으로 자동 재시도를 금지해요(사용자 확인 또는 애플리케이션을 의미론적으로 이해하는 user-agent 소프트웨어의 확인을 권장). http::config 옵션 -repost로 두 가능성을 모두 다룰 수 있어요.

비동기 닫힘 이벤트는 짧은 시간 간격에서만 일어날 수 있어요. http 패키지는 각 영속 연결을 서버가 닫는지 모니터링하고, 감지하면 클라이언트 쪽에서도 연결을 닫고 이후 요청은 새 연결을 사용해요. -keepalive true로 호출하면 기존 영속 연결을 쓰려 하고, 서버에 Connection: keep-alive 요청 헤더를 보내 미래 요청을 위해 연결을 열어 두게 요청해요.

http::config 옵션 -pipeline, -postfresh, -repost는 영속 연결과 관련돼요.

  • -pipelinetrue면 영속 연결의 GET·HEAD 요청을 파이프라인으로 처리해요. POST는 파이프라인하지 않아요 — 연결의 첫 트랜잭션이 아니면 이전 응답이 끝날 때까지 보내지 않아요. POST 이후의 GET·HEAD도 POST 응답이 전달될 때까지 보내지 않고, POST가 실패하면 보내지 않아요.
  • -postfreshtruehttp::geturl 옵션 -keepalive를 무시하고 POST 요청에 항상 새 연결을 열어요.
  • -reposttrue면 서버가 반쯤 닫은 영속 연결을 써서 실패한 POST(비동기 닫힘 이벤트)를 자동 재시도하게 해요. 실패한 파이프라인의 이후 GET·HEAD 요청도 재시도돼요. 재시도가 적절하다고 애플리케이션이 이해할 때만 써야 해요 — 특히 실패한 POST가 서버 상태를 수정했더라도 반복 POST가 나쁜 영향을 주지 않는다는 걸 알아야 해요.

프로토콜 업그레이드 (PROTOCOL UPGRADES)

HTTP/1.1 ConnectionUpgrade 클라이언트 헤더는 클라이언트가 기존 연결에서 사용할 프로토콜을 바꾸고 싶다는 걸 서버에 알려줘요(RFC 7230). 이 메커니즘으로 WebSocket(RFC 6455), 더 높은 HTTP 버전(HTTP 2), TLS 암호화를 요청할 수 있어요. 서버가 업그레이드 요청을 수락하면 응답 코드는 101이에요.

http::geturl에서 프로토콜 업그레이드를 요청하려면 -headers 옵션으로 적절한 Connection·Upgrade 값을 줘야 하고, -command 옵션으로 요청 프로토콜을 구현하면서 서버가 거부할 때 응답도 처리할 수 있는 명령어를 줘야 해요. 업그레이드 요청에서 http::geturl은 -keepalive 값을 무시하고 항상 0을 사용해, 여러 HTTP 요청용으로 의도된 연결에 업그레이드 요청이 가해지지 않게 해요.

Tcllib 라이브러리의 websocket은 WebSocket을 구현하며 http 패키지의 명령어들을 필요한 대로 호출해요. 현재 HTTP/2용 네이티브 Tcl 클라이언트 라이브러리는 없어요.

Upgrade 메커니즘은 웹 브라우저에서 TLS를 요청하는 데 쓰이지 않아요 — http와 https는 다른 포트에서 서비스되기 때문이에요. IPP(Internet Printing Protocol)처럼 http(s) 위에 구축되고 보안·비보안 트래픽에 같은 TCP 포트를 쓰는 프로토콜이 사용해요. 브라우저에서 기회적 암호화는 Upgrade-Insecure-Requests 클라이언트 헤더로 구현돼요. 보안 서비스가 가능하면 서버 응답 코드는 307 리다이렉트이고 Location 헤더가 대상 URL을 지정해요. 브라우저는 이 URL을 가져오기 위해 http::geturl을 다시 호출해야 해요.

예제

URL을 파일로 복사하면서 진행률 표시기를 출력하고 URL 메타데이터를 찍는 프로시저:

proc httpcopy { url file {chunk 4096} } {
    set out [open $file w]
    set token [::http::geturl $url -channel $out \
            -progress httpCopyProgress -blocksize $chunk]
    close $out

    # This ends the line started by httpCopyProgress
    puts stderr ""

    upvar #0 $token state
    set max 0
    foreach {name value} $state(meta) {
        if {[string length $name] > $max} {
            set max [string length $name]
        }
        if {[regexp -nocase ^location$ $name]} {
            # Handle URL redirects
            puts stderr "Location:$value"
            return [httpcopy [string trim $value] $file $chunk]
        }
    }
    incr max
    foreach {name value} $state(meta) {
        puts [format "%-*s %s" $max $name: $value]
    }

    return $token
}
proc httpCopyProgress {args} {
    puts -nonewline stderr .
    flush stderr
}

더 알아보기