0

i am trying to send a put request to simple server in ruby with data.

curl --request PUT 'http://localhost:2000/api/kill' --data "c=19"

my server implementation is:

require 'socket'      

server = TCPServer.open(2000)
loop do 
  socket = server.accept
  while(line = socket.gets)
    p line
  end
  socket.close
end

i want to extract the data from the request. Currently it only prints the following.

"PUT /api/kill HTTP/1.1\r\n"
"User-Agent: curl/7.35.0\r\n"
"Host: localhost:2000\r\n"
"Accept: */*\r\n"
"Content-Length: 4\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"\r\n"

Any help regarding how to extract c=19 sent as data

Vaibhav
  • 9
  • 4

2 Answers2

2

gets is waiting for a newline. curl isn't sending one, c=19 being the last thing that goes through the wire.

Also, you can't use while line, because line will never be false until the connection breaks, and curl will not break the connection, as it expects a response.

Look at "Detect end of HTTP request body" about how the server is supposed to know when the request body ends. There are several cases to consider in order to be fully spec-compliant, but the method that should work most of the time, detecting Content-Length, is not terribly difficult.

Still, I suggest you let a library (e.g. Rack) take care of parsing the request, it is trickier than it looks.

Community
  • 1
  • 1
Amadan
  • 191,408
  • 23
  • 240
  • 301
1

This works:

require 'socket'      

server = TCPServer.open(2000)
loop do 
  socket = server.accept
  line = ""
  until line == "\r\n"
    line = socket.readline
    if line.match /Content\-Length\:\s(\d+)/
      length = $1.to_i
    end
  end  
  line = socket.read(length)        
  socket.puts "The data was: #{line}"
  socket.close
end

It uses "\r\n" to detect the end of the header, and gets the length of the body from "Content-Length". It then uses that length to get the data via read

And note that the matching curl request is:

curl --request PUT 'http://localhost:2000/api/kill' --data "c=19"
ReggieB
  • 8,100
  • 3
  • 38
  • 46
  • Are you sure `read_nonblock` is a good idea? It works wonders when you are doing something else and it is in a loop; but won't this give you just partial data unless the connection is lightning-fast? In this case, I'd rather use plain `read` – Amadan Oct 30 '15 at 00:58
  • @Amadan, I think you are right - and that `read` is the better option. I've modified my answer to use `read` instead of `read_nonblock`. Thank you – ReggieB Oct 30 '15 at 08:43