博客

群星,我的归宿

HTTP Content-Length 应该是 string.bytesize 而不是 string.size

因为 Webrick 中的 FileHandler 对于中文编码不支持,在用 httpd host一个中文目录的时候会出现 500 错误,所以最近尝试用 Ruby socket 写一个简单的 HTTP 文件服务器,遇到中文的时候不至于崩溃,同时满足自己在局域网内更好的把文件分享给移动端的需求。

将根据请求的资源路径转化为实际的目录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server       = TCPServer.new('0.0.0.0', 2345)
socket       = server.accept
request_line = socket.gets
path        = requested_file(request_line)

def requested_file(request_line)
  request_uri  = request_line.split(" ")[1]
  path         = URI.unescape(URI(request_uri).path)

  clean = []

  parts = path.split("/")

  parts.each do |part|
    next if part.empty? || part == '.'
    part == '..' ? clean.pop : clean << part
  end

  File.join(WEB_ROOT, *clean)
end

但是如果我们host的是中文目录,在运行的时候,会遇到这个问题:

1
Encoding::CompatibilityError (incompatible character encodings: ASCII-8BIT and UTF-8):

join的时候,遇到了问题,类似的事情也发生在 (Paperclip)[https://github.com/thoughtbot/paperclip/issues/301] 上面。最后通过 force_encoding 解决了这个问题。

1
File.join(WEB_ROOT, *clean).force_encoding('UTF-8')

不要使用 size 或者 length 作为 Content-Length

在返回的 body 中,如果只有 ascii 字符,使用 size 或者 length 作为 Content-Length 是没有什么问题的。但是浏览器那边是根据字节流读取的,一旦流里面有了 unicode 字符,浏览器根据 Content-Length 截取的字节流长度就不准确了。

所以正确的做法是要么不要摄者 Content-Length,要么用string的 bytesize 作为 Length。

(Implementing an http file server)[https://practicingruby.com/articles/implementing-an-http-file-server]

Comments