使用Ruby 1.9.3无法正确读取HTTP请求标头

时间:2013-05-26 14:01:16

标签: ruby sockets http

我正在写一个小型网络服务器。我想阅读HTTP Request。它在没有涉及身体时起作用。但是当一个尸体被送去时,我无法以令人满意的方式阅读身体的内容。

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

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

所以我的问题是:

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

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

#!/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

1 个答案:

答案 0 :(得分:0)

所以...我在过去的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请求,发件人的地址信息和任何其他红宝石标志。

您可以使用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的情况下执行此操作,但我很高兴功能存在。