我正在写一个小型网络服务器。我想阅读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
答案 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
的情况下执行此操作,但我很高兴功能存在。