如何在tclhttpd中正确计算Content-length?

问题描述 投票:0回答:1

我的T​​cl源文件位于utf-8中。 Tclhttpd无法正确发送国家字符,因此我对其进行了一些修改。但是,我也发送jpg图像之类的二进制文件,有时我的utf-8 HTML中也存在二进制块。我很难计算出正确的Content-length以完全匹配浏览器收到的内容(否则,某些尾随字符会破坏next-request标头,或者浏览器每次请求都等待30秒,直到超时)。

换句话说,我能知道puts $socket写入套接字多少字节吗?

我发现一个特殊的11字节序列弄乱了计数:

proc dump3 string {
    binary scan $string c* c
    binary scan $string H* hex
    return [sdump $string]\n$c\n$hex
};#dump3
proc Httpd_ReturnData {sock type content {code 200} {close 0}} {
    global Httpd
    upvar #0 Httpd$sock data
    #...skip non-pertinent code...
set content \x4f\x4e\xc2\x00\x03\xff\xff\x80\x00\x3c\x2f
#content=ONÂÿÿ�</
#79 78 -62 0 3 -1 -1 -128 0 60 47
#4f4ec20003ffff80003c2f
puts content=[dump3 $content]
puts utf8=[dump3 [encoding convertto utf-8 $content]]

    if {[catch {
puts "string length=[string length $content] type=$type"
puts "stringblength=[string bytelength $content]"
    set len [string length $content]
    if [string match -nocase *utf-8* $type] {
        fconfigure $sock -encoding utf-8
        set len [string bytelength $content]
    }
puts "len=$len fcon=[fconfigure $sock]"
    HttpdRespondHeader $sock $type $close $len $code
    HttpdSetCookie $sock
    puts $sock ""
    if {$data(proto) != "HEAD"} {
        ##fconfigure $sock -translation binary -blocking $Httpd(sockblock)
        ##native: -translation {auto crlf} 
        fconfigure $sock -translation lf -blocking $Httpd(sockblock)
        puts -nonewline $sock $content
    }
    Httpd_SockClose $sock $close
    } err]} {
    HttpdCloseFinal $sock $err
    }
}

控制台上的输出是:

内容=ONÿÿ。79 78 -62 0 3 -1 -1 -128 0 60 474f4ec20003ffff80003c2futf8 =ONÃ�â¿Ã¿79 78 -61 -126 0 3 -61 -65 -61 -65 -62 -128 0 60 474f4ec3820003c3bfc3bfc280003c2f字符串长度= 11类型=文本/ html;字符集= utf-8stringblength = 17len = 17 fcon = -blocking 0-缓冲全-buffersize 16384-编码utf-8 -eofchar {{} {}}-翻译{auto crlf} -peername {128.0.0.71 128.0.0.71 55305} -sockname {128.0.0.8 gen 8016}HttpdRespondHeader 17

结果Content-Length:17太多,浏览器一直在等待。如果我只能事先知道,我的字符串中将有多少字节puts,其余的将很容易。有办法吗?

utf-8 tcl content-length http-content-length
1个回答
1
投票

对于通过HTTP传输的数据,观察到的content length should be the number of bytes in the data ]。使用Httpd_ReturnData时,需要确保为它提供要传输的binary数据。 它不为您处理数据编码。发送具有一定长度的二进制数据实际上很容易,您可以这样做:

set binaryData [...] Httpd_ReturnData $sock "application/octet-stream" $binaryData # There are many other binary encodings; that's just the most universal one # Choose the right one for your application, of course

要发送一定长度的文本数据,您需要对encoding convertto做更多的工作:

set textData [...] Httpd_ReturnData $sock "text/plain; charset=utf-8" \ [encoding convertto utf-8 $textData] # Similarly, text/plain is a decent fallback here too

(是的,如果您选择其他编码,那么您应该在两个地方都提到它。您可能应该在这个时代使用UTF-8表示所有文本内容。]

如果可以从文件中提取数据,则应这样做; Httpd_ReturnFileHttpd_ReturnData更有效率,因为它可以使用有效的数据传输技术来移动数据。如果发送文本文件,则需要注意正确描述文件的编码。到目前为止,最简单的方法是按照约定进行操作,例如确定系统上的所有文本文件均为UTF-8 ...


您实际上绝对不应该使用string bytelength,因为该报告是以Tcl仅内部编码(轻度规范化的几乎UTF-8)之一的单位报告的。它返回的度量仅在您执行非常奇怪的操作时才是正确的,例如生成C代码,需要了解缓冲区大小,这些缓冲区大小包含将输入到Tcl的实现中的字符串,而这与您正在执行的操作大不相同(我已经在使用Tcl的20多年中仅做过一次此类事情;我从未听说过其他合法用途)。我认为它之所以被弃用,恰恰是因为它在许多人如何使用它方面存在许多细微的错误。
© www.soinside.com 2019 - 2024. All rights reserved.