ruby - 无法使用 Ruby 1.9.3 正确读取 HTTP 请求 header

标签 ruby sockets http

我正在编写一个小型网络服务器。我想阅读 HTTP 请求。它在没有 body 参与时起作用。但是当发送正文时,我无法以令人满意的方式阅读正文的内容。

我通过TCPSocket读取来自客户端的数据。 TCPSocket::gets 方法读取直到接收到正文数据。没有分隔符或 EOF 发送到 HTTP 请求正文结尾的信号。 HTTP/1.1 Specification - Section 4.4列出五种情况来获取消息长度。第 1 点有效。第 2) 和 4) 点与我的申请无关。第 5 点)不是一个选项,因为我需要发送回复。

我可以读取 Content-Length 字段的值。但是当我试图通过 read(contentlength)rcv(contentlength)“说服”TCPSocket 读取 HTTP 请求的最后一部分时,我没有成功。逐行阅读,直到分隔 Header 和 Body 的 \r\n 起作用,但在那之后我被卡住了 - 至少以我想要的方式。

所以我的问题是:

是否有可能像我在代码中预期的那样做? 有没有更好的方法来实现我正确读取 HTTP 请求 的目标(我真的希望如此)?

这是可运行的代码。我想工作的部分在评论中。

#!/usr/bin/ruby
require 'socket'

server = TCPServer.new 2000
loop do
  Thread.start(server.accept) do |client|
    hascontent = false
    contentlength = 0
    content = ""
    request = ""
    #This seems to work, but I'm not really happy with it, too much is happening in
    #the loop
    while(buf = client.readpartial(4096))
       request = request + buf
       split = request.split("\r\n")
       puts request
       puts request.dump
       puts split.length
       puts split.inspect
       if(request.index("\r\n\r\n")>0)
         break
       end
    end
#This part is commented out because it doesn't work
=begin
    while(line = client.gets)
       puts ":" + line
       request = request + line
       if(line.start_with?("Content-Length"))
         hascontent = true
         split = line.split(' ')
         contentlength = split[1]
       end
       if(line == "\r\n" and !hascontent)
         break
       end
       if(line == "\r\n" and hascontent)
         puts "Trying to get content :P"
         puts contentlength
         puts content.length
         puts client.inspect
         #tried read, with and without parameter, rcv, also with and 
         #without param and their nonblocking couterparts
         #where does my thought process go in the wrong direction  
         while(readin = client.readpartial(contentlength))
           puts readin
           content = content + readin
         end
         break
       end
    end
=end
    puts request
    client.close
 end

最佳答案

所以...过去 2 小时我也遇到了这个问题,所以我深入研究了 Socket API。结果是 Socket 扩展了 BasicSocket,它有一个方法 recvmsg。当我尝试调用它时,我得到以下信息:

["GET / HTTP/1.1\r\nHost: localhost:12357\r\nConnection: keep-alive\r\nCache-Control: max-age=0\r\nUpgrade-Insecure-Requests: 1\r\nUser-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36\r\nAccept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8\r\nAccept-Encoding: gzip, deflate, br\r\nAccept-Language: en-US,en;q=0.9\r\n\r\n", #<Addrinfo: empty-sockaddr SOCK_STREAM>, 0]

即我的完整 HTTP 请求、发件人的地址信息和任何其他 ruby​​ 标记。

您可以使用 recvmsg 读取整个 HTTP 请求:

raw_request = client.recvmsg()
request = /(?<METHOD>\w+) \/(?<RESOURCE>[^ ]*) HTTP\/1.\d\r\n(?<HEADERS>(.+\r\n)*)(?:\r\n)?(?<BODY>(.|\s)*)/i.match(raw_request)
p request["BODY"]

如果没有 recvmsg,我不知道该怎么做,但我很高兴该功能存在。

关于ruby - 无法使用 Ruby 1.9.3 正确读取 HTTP 请求 header ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16759978/

相关文章:

ruby - 在 Ruby 程序执行时阻止 Windows 7 PC 进入休眠状态

ruby-on-rails - 双渲染错误轨

ruby-on-rails - Windows XP 上的 Ruby on Rails 控制台中的 CTRL+C 不会停止 mongrel

python - 在python中将字节转换为字符串

c - 如何正确使用 socket close for fork?

ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词

c# - SocketAsyncEventArgs UDP 服务器缓冲区偶尔充满零

http - 如何禁用 Tomcat 5.5.27 的 HTTP 方法

json - 安全和无状态的 JWT 实现

http - gitsharp 克隆 http 协议(protocol)失败,但 git 协议(protocol)成功!为什么?