11

The LuaSocket HTTP module documentation says that a timeout can be set on a HTTP connection:

The following constants can be set to control the default behavior of the HTTP module:

PORT: default port used for connections; PROXY: default proxy used for connections; TIMEOUT: sets the timeout for all I/O operations; USERAGENT: default user agent reported to server. http://w3.impa.br/~diego/software/luasocket/http.htm

How do I set these constants in a lua script?

ripat
  • 3,076
  • 6
  • 26
  • 38
  • 1
    Add your solution as an answer and accept it, so this question would be complete. – Alexander Gladysh May 16 '11 at 12:03
  • I tried but I have to wait 8 hours after the time of the first post before I can answer to my own question. I will do it this evening (CET). – ripat May 16 '11 at 12:19
  • That restriction should be gone now that you have over 10 rep points. – BMitch May 16 '11 at 13:26
  • Nope. I still have thet same notice: New users can't answer their own question for 8 hours. Please use comments, or edit your question instead. – ripat May 16 '11 at 14:05

2 Answers2

15

It was easier than I thought. simply

local mysocket = require("socket.http")
mysocket.TIMEOUT = 5
ripat
  • 3,076
  • 6
  • 26
  • 38
  • 2
    does this have 'side effects', changing http socket configurations outside of the file that does the require ? (i.e. code on the same program but on another file that does its own require for http.socket) – josinalvo Oct 31 '14 at 18:45
  • 1
    @josinalvo: Yes, all files within a program share the same instances of their common modules under `package.loaded`. See [my answer](http://stackoverflow.com/a/6021774/34799) for a way to do this without side effects. – Stuart P. Bentley Mar 22 '17 at 02:03
13

You can do this to set a timeout for one request instead of the entire HTTP module:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  req_sock:settimeout(5)
  return req_sock
end}

Note that the default behavior of :settimeout, as well as global settings like http.TIMEOUT, sets a time limit for any individual operation within the request - in other words, it's how long the operation may go without any activity before timing out. If you wish to set an overall upper bound on an operation - a time that the overall request can't exceed, regardless of activity - you should pass a mode argument of 't' as the second parameter to :settimeout, like so:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  -- note the second parameter here
  req_sock:settimeout(5, 't')
  return req_sock
end}

As an example to illustrate the distinction between the two modes, imagine that, after making your request, the server responded with a chunk of the response once a second, taking seven seconds overall to complete. With req_sock:settimeout(5, 'b') (or just req_sock:settimeout(5)) setting a 5-second block timeout, this request would proceed just fine, as none of the underlying I/O operations took longer than five seconds: however, with req_sock:settimeout(5, 't') setting a five-second total timeout, the request would fail after five seconds.

Of course, it may make sense to set restrictions for both of these durations, having both a short inactivity timeout as well as a longer overall timeout. As such, per the documentation, you can make two separate calls to specify both:

local socket = require "socket"
local http = require "socket.http"
response = http.request{url=URL, create=function()
  local req_sock = socket.tcp()
  req_sock:settimeout(5, 'b')
  req_sock:settimeout(30, 't')
  return req_sock
end}
Stuart P. Bentley
  • 10,195
  • 10
  • 55
  • 84
  • I am not sure I understand this. With the solution I found (posted below now), do I really change the timeout for all new HTTP sockets? If that is the case, I could reset its value to the default 60 seconds after the connection succeeded. Can you explain on your snippet, especially the `create = function()` part? – ripat May 16 '11 at 18:52
  • I just made some test and, indeed, when I change the timeout with `mysocket.TIMEOUT` it keeps that value for all new HTTP sockets created afterwards unless you change it again. With your suggestion don't you create two sockets? One http and one tcp? – ripat May 16 '11 at 19:22
  • 1
    @ripat The `create` parameter of the request specifies the function to *create* the TCP socket it uses to *perform* the HTTP request ([the HTTP Application layer going over the TCP Transport layer](http://en.wikipedia.org/wiki/TCP/IP_model)). If you don't specify a create function, http.request will use a plain call to `tcp()` by default (see [the manual](http://w3.impa.br/~diego/software/luasocket/http.html)). – Stuart P. Bentley May 16 '11 at 20:11
  • 1
    Oh, I see. Although setting the default value for the entire module for the duration of the script is usually not a problem, your solution offers better control on the HTTP socket. Thanks Stuart. – ripat May 17 '11 at 05:47
  • Line 2 `require "socket.tcp"` and Line 4 `local socket = tcp()` are **invalid**. Line 2 should be deleted and Line 4 should be `local socket = socket.tcp()`. –  May 18 '11 at 16:28
  • I got better results with req_sock:settimeout(2,'t'). The 't' is a mode that specifies that the timeout... well, idk. But it works – josinalvo Oct 31 '14 at 19:56
  • FYI, stack overflow (in my case) hid the last two comments (which are important). Can you change the line to req_sock:settimeout(5,'t') which will set the total timeout. The default 'block' timeout is not intuitive and doesn't behave the same as the similar "http.TIMEOUT=5" cases mentioned throughout answers to the question. – David Thornley Mar 21 '17 at 02:25
  • As far as I can tell [from the documentation](http://w3.impa.br/~diego/software/luasocket/http.html), the "block" timeout mode *does* behave the same way as `http.TIMEOUT` - both control the timeout time *for each I/O operation*. I've added an explanation about timeout modes to the answer, but I'm sticking to the default in the initial section describing the alternative to `http.TIMEOUT`. – Stuart P. Bentley Mar 22 '17 at 01:59