python - Why can I perform an HTTP get request to the same flask app once but not two or more times? -


the following python snippet simple flask app debugging on , 2 workers. takes sequence of ports routes , performs http request using urllib2 first port given in path, , passes along rest of ports argument.

for instance if application serving on port 4000, then

curl localhost:4000/4001

will issue http request localhost:4001 path /

for whatever reason, can 1 hop if have multiple flasks running.

port=4000 python flasky.py port=4001 python flasky.py port=4002 python flasky.py 

if curl localhost:4000/, hi. if curl localhost:4000/4000 or curl localhost:4000/4001, fine well. however, can't have 3 "hops" or i'll urlerror: <urlopen error [errno 111] connection refused>, if ports involved different.

curl localhost:4000/4001/4002 

fails, instance

from flask import flask import os import urllib2 import validators  app = flask(__name__)  def make_url(host, port, path):     "make , validate url, hardcoded http protocol"     assert isinstance(host, str)     assert isinstance(port, str) or isinstance(port, int)     assert isinstance(path, str)      port = str(port)      candidate_url = "http://%s:%s%s" % (host, port, path)     if validators.url(candidate_url):         return candidate_url     else:         raise valueerror(candidate_url, "is not url")  # handle incoming list of ports # use first segment port , # send @app.route('/', defaults={'path': '/'}) @app.route('/<path:path>') def handle(path):     # base case!     if path == '/':         return "hi"      segments = path.split('/')     # reject empty segments     segments = [x x in segments if x != '']     x in range(len(segments)):         segments[x] = int(segments[x])      downstream_path = "/".join(str(x) x in segments[1:])     if downstream_path == '':         downstream_path = '/'      # verify downstream path shorter incoming path     assert len(downstream_path) < path      response = urllib2.urlopen(         make_url(             host='127.0.0.1',             port=segments[0],             path=downstream_path))     html = response.read()      return "hi " + html  if __name__ == "__main__":     app.run(         host='127.0.0.1',         port=int(os.environ["port"]),         processes=2,         debug=true) 

and here full stack trace resulting curl localhost:4000/4000/4000:

traceback (most recent call last):   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1836, in __call__     return self.wsgi_app(environ, start_response)   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1820, in wsgi_app     response = self.make_response(self.handle_exception(e))   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1403, in handle_exception     reraise(exc_type, exc_value, tb)   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1817, in wsgi_app     response = self.full_dispatch_request()   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request     rv = self.handle_user_exception(e)   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1381, in handle_user_exception     reraise(exc_type, exc_value, tb)   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request     rv = self.dispatch_request()   file "<home>/workspace/python/venv/lib/python2.7/site-packages/flask/app.py", line 1461, in dispatch_request     return self.view_functions[rule.endpoint](**req.view_args)   file "<home>/workspace/python/flasky.py", line 53, in handle     path=downstream_path))   file "/usr/lib/python2.7/urllib2.py", line 154, in urlopen     return opener.open(url, data, timeout)   file "/usr/lib/python2.7/urllib2.py", line 431, in open     response = self._open(req, data)   file "/usr/lib/python2.7/urllib2.py", line 449, in _open     '_open', req)   file "/usr/lib/python2.7/urllib2.py", line 409, in _call_chain     result = func(*args)   file "/usr/lib/python2.7/urllib2.py", line 1227, in http_open     return self.do_open(httplib.httpconnection, req)   file "/usr/lib/python2.7/urllib2.py", line 1197, in do_open     raise urlerror(err) urlerror: <urlopen error [errno 111] connection refused> 

the clue in line of traceback:

      file "<home>/workspace/python/flasky.py", line 53, in handle         path=downstream_path)) 

this means downstream_path passing path make_url() not proper path.

the bug because "/".join() not add leading / path in url. request curl localhost:4000/4001 succeeds because there no path add request localhost:4001.

the validator not realise error because used validators.url() instead of validators.url.url().

here corrected version of code(i have commented on changes):

    flask import flask     import os     import urllib2     import validators      app = flask(__name__)      def make_url(host, port, path):         "make , validate url, hardcoded http protocol"         assert isinstance(host, str)         assert isinstance(port, str) or isinstance(port, int)         assert isinstance(path, str)          port = str(port)          #add forward slash between port , path          candidate_url = "http://%s:%s/%s" % (host, port, path)         #use correct validator function here.         if validators.url.url(candidate_url):             return candidate_url         else:             raise valueerror(candidate_url, "is not url")      # handle incoming list of ports     # use first segment port ,     # send     @app.route('/', defaults={'path': '/'})     @app.route('/<path:path>')     def handle(path):         # base case!         if path == '/':             return "hi"          segments = path.split('/')         # reject empty segments         segments = [x x in segments if x != '']         x in range(len(segments)):             segments[x] = int(segments[x])          downstream_path = "/".join(str(x) x in segments[1:])          #this if statement not required since explicitly         #adding forward slash in make_url function.          #if downstream_path == '':             #downstream_path = '/'          # verify downstream path shorter incoming path         assert len(downstream_path) < path          response = urllib2.urlopen(             make_url(                 host='127.0.0.1',                 port=segments[0],                 path=downstream_path))         html = response.read()          return "hi " + html      if __name__ == "__main__":         app.run(             host='127.0.0.1',             port=int(os.environ["port"]),             processes=2,             debug=true) 

note: use urlparse library create url avoid error.


Comments

Popular posts from this blog

Django REST Framework perform_create: You cannot call `.save()` after accessing `serializer.data` -

Why does Go error when trying to marshal this JSON? -