Cannot await combined future of multiple async requests, proc hangs when doing so - http

I wanted to do some performance testing of my site. For that purpose I wanted to fire n requests asynchronously, combine the Futures that result of that into one future that completes when they all complete and then wait for that futures completion.
However, my code gets stuck awaiting the combined future and never completes.
My code looked like this:
import benchy
import std/[sugar, strformat, sequtils, httpclient, asyncfutures, asyncdispatch]
proc callSite(client: AsyncHttpClient, url: static string, callCount: int): Future[string] {.async.} =
var futures : seq[Future[AsyncResponse]] = #[]
for x in 1..callCount:
futures.add client.get(url)
echo "pre combo"
let comboFuture = all(futures)
let responses = await comboFuture
echo "post awaited combo"
result = await responses[0].body
echo "post response"
var myClient = newAsyncHttpClient()
myClient.headers = newHttpHeaders({
"Authorization": "Bearer " & token,
"Accept": "application/json"
})
const url = <Some URL>
timeIt "campaign overview":
let x = waitFor myClient.callSite(url, 3)
keep(x)
When I run this I never get past "pre combo", the request gets stuck, even though the server receives 3 requests and sends 3 responses (I checked that in server-side logs).
What is going wrong here?

The reason for the issue is that clients from std/httpclient do not support a client dealing with more than one request at a time!
import benchy
import std/[sugar, strformat, sequtils, httpclient, asyncfutures, asyncdispatch]
proc callSite(clients: seq[AsyncHttpClient], url: static string): Future[string] {.async.} =
var futures : seq[Future[AsyncResponse]] = #[]
for client in clients:
futures.add client.get(url)
let comboFuture = all(futures)
let responses = await comboFuture
result = await responses[0].body
proc createMyClient(): AsyncHttpClient =
result = newAsyncHttpClient()
result.headers = newHttpHeaders({
"Authorization": "Bearer " & token,
"Accept": "application/json"
})
let fiftyClients: seq[AsyncHttpClient] = (1..50).toSeq().mapIt(createMyClient())
const url = <Some Url>
timeIt "50 client":
let x = waitFor fiftyClients.callSite(url)
keep(x)

Related

What is difference between node-fetch(nodejs) and requests(python)

python codes get response but javascript code can't get response.
what is diff between the two??
import fetch from 'node-fetch';
const url = "http://host3.dreamhack.games:15592/img_viewer"
const imageUrl = "/static/dream.png"
const data = {
"url": imageUrl
}
const res = await fetch(url, {
method: "POST",
body: JSON.stringify(data)
})
const text = await res.text()
console.log(text)
//<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
//<title>500 Internal Server Error</title>
//<h1>Internal Server Error</h1>
//<p>The server encountered an internal error and was unable to complete your request. Either the //server is overloaded or there is an error in the application.</p>
import requests
url = "http://host3.dreamhack.games:15592/img_viewer"
imageUrl = "/static/dream.png"
data = {
"url": imageUrl
}
response = requests.post(url, data=data)
print(response.text)
I think the two codes are same, why get different response?
(after time above url is not available)
** server
#app.route("/img_viewer", methods=["GET", "POST"])
def img_viewer():
if request.method == "GET":
return render_template("img_viewer.html")
elif request.method == "POST":
url = request.form.get("url", "")
urlp = urlparse(url)
if url[0] == "/":
url = "http://localhost:8000" + url
elif ("localhost" in urlp.netloc) or ("127.0.0.1" in urlp.netloc):
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
try:
data = requests.get(url, timeout=3).content
img = base64.b64encode(data).decode("utf8")
except:
data = open("error.png", "rb").read()
img = base64.b64encode(data).decode("utf8")
return render_template("img_viewer.html", img=img)
I see 2 reasons:
The headers in node-js might be drifferent by default. You could specify them to make the requests identical tho.
It seems like javascript has a different fingerprint than python-requests, even when using the same headers. Some websites like cloudfare can detect that, and then usually throw a 403 [Forbidden] http error.
But I didn't find out, what exactly is defferent that case.

How to pass form-urlencoded data in GET request with SWIFT 5

I'm using Swift 5 and attempting to get an access token from an API I'm developing using asp.net MVC. With Postman I set my request to GET, pass in some information in the body, and I get back an access token.
In XCode when I try this it gives me the error: "GET method must not have a body."
My Code:
func GetToken(email: String, password: String) {
let dataToSend = [
"grant_type": "password",
"username": email,
"password": password
]
let newData = try! JSONSerialization.data(withJSONObject: dataToSend, options: [])
var request = URLRequest(url: getNewTokenURL)
request.httpMethod = "Get"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.httpBody = newData
URLSession.shared.dataTask(with: request) { (data, response, error) in
guard let data = data else {return}
do {
let myData = try JSONDecoder().decode(TokenResponse.self, from: data)
self.userToken = myData.accessToken
}
catch {
}
}.resume()
}
How do I perform the GET request with the data I need to send to it?
GET requests don't have a body. Parameters in a GET request are passed along with it's url as query parameters.
let url = URL(string: "https://www.example.com/getExample?sampleParam=sampleValue&anotherParam=anotherValue")
Edit: Also you need to give method in all caps. Since GET is the default you didn't have an issue.
Also if you are sure that the data is being passed as JSON then the method should be a POST method for that you just need to set the method of the request to POST as follows:
request.method = "POST"
Note: It's case sensitive.

Flutter http get precent of completion?

Hy everybody,
I try now to get the precent of completion of a http get request, but this cann't work, every time I get this error:
flutter: Bad state: Can't finalize a finalized Request.
Code I writed:
http.Response response = await client.get(url, headers: {"email": email, "password": password});
var __ = await client.send(response.request);
var length = response.contentLength;
var received = 0;
__.stream.map((s) {
received += s.length;
print("${(received / length) * 100} %");
return 1;
});
finally I should get a json data.
Could have anyone a ideea, how can this fixed or other programmed?
use Dio package it includes up/download status counter

Angular 5 to CherryPy POST

I am trying to send data to a cherrypy backend from an Angular 5 app. I am able to call the correct cherrypy function and get a 200 response, but none of my parameters are getting through.
One thing that caught my eye was that my payload, when I click view source in the chrome debugger looks like this {"username":"admin","password":"admin"}. Is this supposed to be formatted differently?
Here's my post:
getUserDetails(username, password) {
const _headers = new HttpHeaders();
const headers = _headers.append('Content-Type', 'application/json');
const options = {headers: headers };
this.data = JSON.stringify({ username, password });
return this.http.post(this.url1 + 'login', this.data, options )
.subscribe(data => {
console.log(data);
});
}
Again, this gets to the proper endpoint, just none of the data gets through.
Here's cherryPy:
Login Function:
class authServer(object):
#cherrypy.expose
def login(self,*args, **kwargs):
print(type(args),args, kwargs)
I've tried various args, if I have username and password I get the error saying missing parameters.
Here's the cherrypy configuration.
def CORS():
"""Allow AngularJS apps not on the same server to use our API
"""
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
cherrypy.response.headers["Access-Control-Allow-Headers"] = \
"content-type, Authorization, X-Requested-With"
cherrypy.response.headers["Access-Control-Allow-Methods"] = 'GET, POST'
if __name__ == '__main__':
cherrypy.tools.CORS = cherrypy.Tool('before_handler', CORS)
cherrypy.log.error_log.propagate = False
cherrypy.log.access_log.propagate = False
cherrypy.config.update({'server.thread_pool': 30,
'tools.CORS.on': True,
'server.socket_host': '0.0.0.0',
'server.socket_port': 8081})
cherrypy.quickstart(authServer(), '/')
I've made countless posts to cherrypy before. The only difference here is the frontend I'm using. Any help would be greatly appreciated.
Thanks,
Turns out it was a CORS issue. I changed my CORS function from this:
def CORS():
cherrypy.response.headers["Access-Control-Allow-Origin"] = "*"
cherrypy.response.headers["Access-Control-Allow-Headers"] = \
"content-type, Authorization, X-Requested-With"
cherrypy.response.headers["Access-Control-Allow-Methods"] = 'GET, POST'
to this:
def CORS():
if cherrypy.request.method == 'OPTIONS':
cherrypy.response.headers['Access-Control-Allow-Methods'] = 'POST'
cherrypy.response.headers['Access-Control-Allow-Headers'] = 'content-type'
cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
return True
else:
cherrypy.response.headers['Access-Control-Allow-Origin'] = '*'
cherrypy.tools.CORS = cherrypy._cptools.HandlerTool(CORS)
Above my main function I put this:
#cherrypy.expose
#cherrypy.config(**{'tools.CORS.on': True})
#cherrypy.tools.json_in()
#cherrypy.tools.json_out()

python3.5: with aiohttp is it possible to serve several responses concurently?

I'm using the latest version (1.0.2) of aiohttp with python3.5 I have the following server code
import asyncio
from aiohttp.web import Application, Response, StreamResponse, run_app
async def long(request):
resp = StreamResponse()
name = request.match_info.get('name', 'Anonymous')
resp.content_type = 'text/plain'
for _ in range(1000000):
answer = ('Hello world\n').encode('utf8')
await resp.prepare(request)
resp.write(answer)
await resp.write_eof()
return resp
async def init(loop):
app = Application(loop=loop)
app.router.add_get('/long', long)
return app
loop = asyncio.get_event_loop()
app = loop.run_until_complete(init(loop))
run_app(app)
If I then run two curl requests curl http://localhost:8080/long in different terminals, only the first one will receive data
My thought was that using asyncio you could, in a monothreaded code, start serving other response, while an other is waiting for I/O
Most of the code I found online about concurent+asyncio only talks about the client side, but not server side
Am I missing something or is my comprehension of how asyncio works is flawed ?
Just push await resp.drain() after resp.write() for giving aiohttp a chance to switch between tasks:
import asyncio
from aiohttp.web import Application, Response, StreamResponse, run_app
async def long(request):
resp = StreamResponse()
name = request.match_info.get('name', 'Anonymous')
resp.content_type = 'text/plain'
await resp.prepare(request) # prepare should be called once
for _ in range(1000000):
answer = ('Hello world\n').encode('utf8')
resp.write(answer)
await resp.drain() # switch point
await resp.write_eof()
return resp
async def init(loop):
app = Application(loop=loop)
app.router.add_get('/long', long)
return app
loop = asyncio.get_event_loop()
app = loop.run_until_complete(init(loop))
run_app(app)

Resources