Occasionally incomplete response from HTTP request - lua

I'm downloading quite big JSON data with luasocket (request), but sometimes, data are incomplete. There is no pattern, if X runs, I have Y fails and Z successful downloads. My downloading code looks like this:
local response = {}
local one, code, headers, status = https.request {
url = url,
sink = ltn12.sink.table(response)
}
And btw, everytime it fails on character 3615. Where is the problem and how to fix it? Is it issue in my code, luasocket, or server?

Related

How to read POST requests in Lua?

I have this Telegram bot written in Lua that I am doing as a hobby for a language network. And I have been reading new messages via the getUpdates API call all the time. Now I want to rewrite it to use webhooks, but I have no experience with that whatsoever. I have googled but didn't find anything certain. I kinda feel that WSAPI is the library to use, but I am not sure. Moreover, I am not really sure I need any special library just for reading POST requests (which is all that the Telegram bot API uses). I tried using sockets:
socket = require 'socket'
server = assert(socket.bind("*", 9000))
function read(client, pattern, prefix)
local data, emsg, partial = client:receive(pattern, prefix)
if data then
return data
end
if partial and #partial > 0 then
return partial
end
return nil, emsg
end
while true do
local client = server:accept()
client:settimeout(3)
local msg, err = read(client, '*a')
if not err then
print(msg)
client:close()
end
end
The print(msg) here gives me the full POST request including headers, which I am probably able to parse (the body is supposed to always be a JSON). I am not really that familiar with HTTP requests though and I'm not sure I can just throw away everything that goes before the first {.
My setup is Lua 5.2, Ubuntu x64 16.04 and Nginx. What I need to do is to receive and read POST requests, nothing more.
TL;DR: is it okay to parse the POST request I receive from the code above or am I missing something, like a library that'd make my life easier?
Thanks!

cherrypy (python httpserver), how to post xml file in body

I want cherrypy to return a xml file in response body in post.
In POST(self), I read a xml file and modify some of the attributes and do these things:
cherrypy.response.headers['Content-Type'] = 'application/soap+xml;charset=UTF-8'
cherrypy.response.headers['Content-Length'] = len(data)
cherrypy.response.body = data
cherrypy.log("response body is: %s" % cherrypy.response.body)
When the client calls, it won't get the body.
curl waits for few seconds and returns this:
curl: (18) transfer closed with 4018 bytes remaining to read
Not sure if I am doing the right thing to send the data back to the client.
I took wireshark trace and I am not seeing any data getting sent out from the server.
Can someone please suggest?
I think I have made this work. Earlier I was calling another function to set above mentioned values. Once I moved them in POST function, things started working. I am not sure what difference do it make. Now, I am setting them this way:
cherrypy.response.headers['Content-Type'] = 'application/soap+xml;charset=UTF-8'
cherrypy.response.headers['Content-Length'] = len(data)
return data

Alamofire http request to local webserver

I'm developing an iPhone app and the plan is to send a JSON packet every so often from the app to a local webserver. To do this, I had planned to use Alamofire. My POST method looks like this:
Alamofire.request(Alamofire.Method.POST, "http://XXX.XX.X.XX:3000/update", parameters: dictPoints, encoding: .JSON)
.responseJSON {(request, response, JSON, error) in
println(JSON)
}
The IP address is marked out, but I've made sure that this corresponds to the IPv4 wireless address of my local server. The server is set to listen to port 3000. The server configuration looks like this:
var express = require('express');
var app = express();
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/test');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function (callback) {
console.log("MongoDB connection is open.");
});
// Mongoose Schema definition
var Schema = mongoose.Schema;
var LocationSchema = new Schema({
//some schema here
});
// Mongoose Model definition
var LocationsCollection = mongoose.model('locations', LocationSchema);
// URL management
app.get('/', function (req, res) {
res.sendFile(__dirname + '/index.html');
});
app.get('/update', function (req, res) {
console.log("Got something from the phone!");
});
// Start the server
var server = app.listen(3000, function () {
var host = server.address().address
var port = server.address().port
console.log('App listening at %s:%s',host, port)
})
So, this server seems to work ok. I can test it in my browser and type the URL: http://127.0.0.1:3000 and it will feed me the index.html file. If I type in http://127.0.0.1:3000/update... then I get the "Got something from the phone!" message. However, when I run my app (making sure my phone is on the same wireless network as the server) and the Alamofire method gets called... the response I get is nil. I also don't see the "Got something from the phone!" message. Can anyone let me know why that would be happening... or better yet, how to fix it?
A few thoughts:
You are creating a POST request in Alamofire, but you've told Express to handle GET requests for /update. Use app.post(...) if you want to handle it as a POST.
Your Alamofire code is looking for JSON response, but you don't appear to be creating a JSON response. In the short term, you could use responseString rather than responseJSON, but I presume you really want to change your web service to respond with JSON (to make it easier for the app to parse the responses).
Your Alamofire code sending a JSON request (but clearly when you send a request via the web browser, it's not JSON). Are you sure you wanted to send JSON request? (This is not to be confused with the JSON response issue.) Did you want to use the .URL encoding type parameter, rather than .JSON?
Whenever you have a request that works correctly from a web browser, but not from the app, it's useful to watch both using a tool like Charles and you can then compare how they differ and diagnose the source of the different behavior.
If you are running Express server and iOS Simulator on the same machine, try to use http://0.0.0.0:<port>/<url> instead of the actual IP, it helped in my case.
It sounds like the node server is not bound to the address you expect it to be. You should verify that when you type in the actual IP address in your "http://XXX.XX.X.XX:3000/update" in your web browser that it responds. Your question details suggest you've just been using the loopback address.

Send Get to website with lua

i'm having a trouble with lua.
I need send a request to a website by GET and get the response from website.
Atm all i have is this:
local LuaSocket = require("socket")
client = LuaSocket.connect("example.com", 80)
client:send("GET /login.php?login=admin&pass=admin HTTP/1.0\r\n\r\n")
while true do
s, status, partial = client:receive('*a')
print(s or partial)
if status == "closed" then
break
end
end
client:close()
What should i do to get the response from server ?
I want to send some info to this website and get the result of page.
Any ideas ?
This probably won't work as *a will be reading until the connection is closed, but in this case the client doesn't know how much to read. What you need to do is to read line-by-line and parse the headers to find Content-Length and then after you see two line ends you read the specified number of bytes (as set in Content-Length).
Instead of doing it all yourself (reading and parsing headers, handling redirects, 100 continue, and all that), socket.http will take care of all that complexity for you. Try something like this:
local http = require("socket.http")
local body, code, headers, status = http.request("https://www.google.com")
print(code, status, #body)
I solved the problem passing the header
local LuaSocket = require("socket")
client = LuaSocket.connect("example.com", 80)
client:send("GET /login.php?login=admin&pass=admin HTTP/1.0\r\nHost: example.com\r\n\r\n")
while true do
s, status, partial = client:receive('*a')
print(s or partial)
if status == "closed" then
break
end
end
client:close()

HTTP Response changed?

i have an HttpWebRequest that do 'POST' to a web server and get an HTML page In response.
I've been asked how is the best practice to know that the response i got has been changed or not?
I can't relay on the web server headers, they don't have to be.
this will increase performance in a way that i wont be need to parse the response over again and will go to the next request in a half of a sec or so.
thank you in advanced
You can tell your webserver about last modification date. see here. If you can't rely on that you have to parse your response anyway. You could do that quickly using md5. So you "md5" your current response and compare it with the previous.
You shouldn't be attempting to rely on the headers for a POST request, as it shouldn't emit any caching headers anyway.
What you need to do instead is perform a hash/checksum (this can either be CRC(32) for absolute performance or a "real" hash such as md5) on the returned content (this means, everything underneath the \r\n\r\n in the headers) and do a comparison that way.
It should be good enough to store the last request's checksum/hash and compare against that.
For example (psuedo):
int lastChecksum = 0;
bool hasChanged() {
performWebRequest();
string content = stripHeaders();
int checksum = crc32string(content);
if(checksum != lastChecksum) {
lastChecksum = checksum;
return true;
}
return false;
}

Resources