ruby-on-railsrubyhttptcpnginx

Forward TCP connection to HTTP on Nginx


I'm running an app which accepts data from GPS loggers, being this data sent via SMS, HTTP or TCP. I was using the HTTP connection to transmit the data, which was straightforward to receive through a GET request on my Rails app.

For battery saving purposes, we changed the connection to pure TCP and nginx is not accepting these requests for now:

From nginx's access.log:

HTTP:

xx.xx.xx.xxx - - [03/Mar/2013:20:17:45 -0500] "GET /?imei=123456789012345&rmc=$GPRMC,035106.000,A,4145.1451,N,08506.8784,W,1.56,176.49,010213,,*13,3656mV,AUTO HTTP/1.1" 302 247 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.152 Safari/537.22"

TCP:

xx.xx.xx.xxx - - [03/Mar/2013:18:31:22 -0500] "imei=123456789012345&rmc=$GPRMC,233012.000,A,4221.6614,N,07106.1014,W,17.25,218.94,030313,,*21,4102mV,AUTO,310,260,ADB7,13EF,057,310,260,0000,0000,044,310,260,0000,0000,055,310,260,0000,0000,05A,310,260,0000,0000,059,310,260,0000,0000,05E,0,0,0000,0000,000,2" 400 172 "-" "-"

Does anyone know a way to filter these TCP requests on Nginx and process them as HTTP GET requests to be available through a Rails app?

Thanks in advance

Answer:

I was able to achieve this by creating a custom proxy, using em-proxy and faraday:

require 'em-proxy'
require 'faraday'

Proxy.start(:host => "0.0.0.0", :port => 8080, :debug => false) do |conn|

  conn.on_data do |data|
    http = Faraday.new(:url => 'http://example.com') do |faraday|
      faraday.request  :url_encoded             # form-encode POST params
      faraday.response :logger                  # log requests to STDOUT
      faraday.adapter  Faraday.default_adapter  # make requests with Net::HTTP
    end
    http.get "/upload?#{data}"
  end
end

Solution

  • Nginx is a HTTP server so it expects clients to speak HTTP. It is not possible to have a client speaking a non-HTTP protocol to nginx in the manner you're describing (ok, maybe you could write a custom module to do it, but that seems silly).

    I think what you need to do is write your own proxy server which will convert the raw TCP protocol into HTTP requests. Your GPS loggers would talk to the proxy which would then talk to nginx. This ought to be fairly simple since the TCP payload appears to just be a urlencoded string, so you could just use those directly.