python catch web redirection - python

my problem is about Web redirect ,, i'm using urllib>getcode() to know what status codes return
so here is my code
import urllib
a = urllib.urlopen("http://www.site.com/incorrect-tDirectory")
a.getcode()
a.getcode() return 200 but actually it's redirect to main page and i've check references that says redirect should return as i remember 300 or 301 but it's not 200 hopefully you got me
so my question how to catch the redirection

urllib2.urlopen() doc page says:
This function returns a file-like object with two additional methods:
geturl() — return the URL of the resource retrieved, commonly used to determine if a redirect was followed
info() — return the meta-information of the page, such as headers, in the form of an mimetools.Message instance (see Quick Reference to HTTP Headers)
urllib.urlopen() actually implements geturl(), too, but it's not put as explicitly in the documentation.

Related

Return custom http code after redirection in flask

there I am new to the flask.
The scenario:
I am trying to redirect to a certain route after submitting the form.
So I am using flask redirect for this along with code parameter.
#topics_bp.route('/create_topic/',methods =['GET','POST'] )
def create_topic():
if request.method == 'GET':
#send the form for create topic!
formData = TopicForm()
return render_template('create-topic.html',form = formData)
if request.method == 'POST':
# check the post method and redirect
return redirect(url_for('topic.topics'),code=201)
Basically , I want to return HTTP code 201 for a record created and then redirect to the intended route.
But if I do like this, it simply returns a redirection page. Every time I need to click manually.
Is there any workaround to return 201 code and redirect automatically?
Thanks in advance!
I want to return HTTP code 201 for a record created and then redirect to the intended route.
That's not something you can do with HTTP. A redirect is itself a specific HTTP 30x status code:
In HTTP, redirection is triggered by a server sending a special redirect response to a request. Redirect responses have status codes that start with 3, and a Location header holding the URL to redirect to.
Either you return a 201 status code or you return one of the HTTP redirection status codes. You can't do both.
The flask.redirect() function generates a valid 30x response (with the required Location header), and the documentation for the function states what redirect status codes are supported:
Supported codes are 301, 302, 303, 305, 307, and 308. 300 is not supported because it’s not a real redirect and 304 because it’s the answer for a request with a request with defined If-Modified-Since headers.
The function doesn't enforce this, however; the status code is not validated.
You need to distinguish between a browser and other clients here. A 201 Created response is something you typically return from a REST API to a client that expects simple JSON or XML interactions at a programmable level. Redirects, on the other hand, are more typically used in a frontend, in the presentation layer.
If you are coding a HTML-based front-end, just return a redirect. Humans don't read response codes, they read rendered HTML pages. They don't care and don't need to know the exact HTTP codes used to make the browser do the right thing. Given that your route also includes a form, you are almost certainly building a site for humans and not for programmatic clients.
If you are building a REST API, then return a 201 response, and document that the API client will have to make a new request based on the Location header you included, or on something in the body of the response. A HTML browser will not follow the Location header on 201 responses however.
I then would not use the redirect() function for this, even if it does allow you to use 201 as the status code, because it always produces a (simple) HTML body containing the text you see in your browser about an automatic redirect.

Flask: Can one create a custom 302 (Redirect) page?

During unit testing a Flask application I, at first accidentally, omitted the follow_redirects=True parameter, which caused the following test to fail:
from unittest import TestCase
class TestFlask(TestCase):
def test_settings(self):
# user not logged in
r = self.app.get("/user/settings", follow_redirects=False)
data = r.data.decode('utf-8')
self.assertIn("Sign In", data)
For this page (/user/settings) the user needs to be logged in and would usually be redirected to the login page, which contains the words "Sign In". With follow_redirects=False I, of course, get an AssertionError (note the automatically generated HTML):
AssertionError: 'Sign In' not found in '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n<title>Redirecting...</title>\n<h1>Redirecting...</h1>\n<p>You should be redirected automatically to target URL: /user/login?next=%2Fuser%2Fsettings. If not click the link.'
Question
How can I customize the HTML generated by a 302 redirect that is not being followed?
What I tried
from flask import Flask
app = Flask(__name__)
# ...
#app.errorhandler(404)
def page_not_found(e):
return "page not found, {}".format(e)
#app.errorhandler(302)
def redirect(e):
return "redirecting... {}".format(e)
Taking the same approach as I would for a custom 404 page causes a KeyError: 302 upon starting the web server. I am aware that 302 does not indicate an error, thus, trying an errorhandler was destined to fail. I did, however, not find any alternative.
Per RFC 7231:
The server's response payload usually contains a short hypertext note with a hyperlink to the different URI(s).
But in practice the redirect payload is completely ignored by most user agents. When a browser encounters the Location header it immediately begins redirecting to the new page, so the payload of the 302 response is never rendered.
If you care about the behavior of non-browser user agents on unfollowed redirects (why?) you can just build a response like you would normally (e.g. using flask.render_template) and manually set response.status = 302 and response.headers['Location'] = '/path/to/redirect/to', instead of using the flask.redirect helper function. If you find yourself doing this sort of thing all the time, you could define your own redirect function to use instead, or you could write a Werkzeug middleware that transforms redirect responses for you.

Post and redirect to cross domain URL

I want to post some data (say id=123) to a cross domain URL and then redirect to that URL. Code:
#app.route("/postreq", methods=['GET','POST'])
def my_webservice():
return redirect('127.0.0.1:3005/developer?id=123')
This redirect works fine but I want to send id via post request to hide it from query string. Any suggestions?
First of all, redirecting GET to POST should be avoided, as the two verbs have different meanings: GET requests should be idempotent, POST request are supposed to modify the internal state of the application.
Secondly, after a POST, browsers usually can be redirected to a resource that they will fetch with GET (303 redirect code), or using the same POST verb (307 redirect code), but the spec (https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) does not show a way to do GET -> POST.

Post print dictionary/json returns error to client

I am sending post request in the body of some json data, to process on server and I want the results back to client(c++ app on phone) in the form of json data and hence parse on mobile.
I have the following code inside handler:
class ServerHandler(tornado.web.RequestHandler):
def post(self):
data = tornado.escape.json_decode(self.request.body)
id = data.get('id',None)
#process data from db (take a while) and pack in result which is dictinary
result = process_data(id)# returns dictionary from db= takes time
print 'END OF HANDLER'
print json.dumps(result)
#before this code below I have tried also
#return result
#return self.write(result)
#return self.write(json.dumps(result))
#return json.dumps(result)
self.set_header('Content-Type', 'application/json')
json_ = tornado.escape.json_encode(result)
self.write(json_)
self.finish()
#return json.dumps(result)
I always get printed 'END OF HANDLER' and valid dictinary/json below on console but when I read at client mobile I always get
<html><title>405: Method Not Allowed</title><body>405: Method Not Allowed</body></html>
Does anyone have any idea what is the bug ?
(I am using CIwGameHttpRequest for sending request and it works when file is static =>name.json but now same content is giving error in post request. )
The error (HTTP 405 Method Not Allowed) means that you have made a request to a valid URL, but you are using an HTTP verb (e.g. GET, POST, PUT, DELETE) that cannot be used with that URL.
Your web service code appears to handle the POST verb, as evidenced by the post method name, and also by the fact that incoming requests appear to have a request body. You haven't shown us your C++ client code, so all I can do is to speculate that it is making a GET request. Does your C++ code call Request->setPOST();? (I haven't worked with CIwGameHttpRequest before, but Googling for it I found this page from which I took that line of code.)
I've not worked with Tornado before, but I imagine that there is some mechanism somewhere that allows you to connect a URL to a RequestHandler. Given that you have a 405 Method Not Allowed error rather than 404 Not Found, it seems that however this is done you've done it correctly. You issue a GET request to Tornado for the URL, it determines that it should call your handler, and only when it tries to use your handler it realises that it can't handle GET requests, concludes that your handler (and hence its URL) doesn't support GETs and returns a 405 error.

Django : Testing if the page has redirected to the desired url

In my django app, I have an authentication system. So, If I do not log in and try to access some profile's personal info, I get redirected to a login page.
Now, I need to write a test case for this. The responses from the browsers I get is :
GET /myprofile/data/some_id/ HTTP/1.1 302 0
GET /account/login?next=/myprofile/data/some_id/ HTTP/1.1 301 0
GET /account/login?next=/myprofile/data/some_id/ HTTP/1.1 200 6533
How do I write my test ? This what I have so far:
self.client.login(user="user", password="passwd")
response = self.client.get('/myprofile/data/some_id/')
self.assertEqual(response.status,200)
self.client.logout()
response = self.client.get('/myprofile/data/some_id/')
What could possibly come next ?
Django 1.4:
https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.TestCase.assertRedirects
Django 2.0:
https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects
SimpleTestCase.assertRedirects(response, expected_url, status_code=302, target_status_code=200, msg_prefix='', fetch_redirect_response=True)
Asserts that the response returned a status_code redirect status, redirected to expected_url (including any GET data), and that the final page was received with target_status_code.
If your request used the follow argument, the expected_url and target_status_code will be the url and status code for the final point of the redirect chain.
If fetch_redirect_response is False, the final page won’t be loaded. Since the test client can’t fetch external URLs, this is particularly useful if expected_url isn’t part of your Django app.
Scheme is handled correctly when making comparisons between two URLs. If there isn’t any scheme specified in the location where we are redirected to, the original request’s scheme is used. If present, the scheme in expected_url is the one used to make the comparisons to.
You could also follow the redirect with:
response = self.client.get('/myprofile/data/some_id/', follow=True)
which would mirror the user experience in the browser and make assertions of what you expect to find there, such as:
self.assertContains(response, "You must be logged in", status_code=401)
You can check response['Location'] and see if it matchs with the expected url. Check also that status code is 302.
response['Location'] doesn't exist in 1.9. Use this instead:
response = self.client.get('/myprofile/data/some_id/', follow=True)
last_url, status_code = response.redirect_chain[-1]
print(last_url)
You can use assertRedirects eg:
response = self.client.get('/sekrit/')
self.assertRedirects(response, '/other/login/?next=/sekrit/')
https://docs.djangoproject.com/en/2.0/topics/testing/tools/#django.test.SimpleTestCase.assertRedirects
If you need to get url which redirected
If follow is True
You will get url in
response.redirect_chain[-1]
If follow is False
response.url

Categories