HTTPS to HTTP using CherryPy - python

Is it possible for CherryPy to redirect HTTP to HTTPS. Lets for example say the code below is http://example.com if someone visits via https://example.com I want them to be redirected to the plain HTTP URL (301 redirect maybe?) how do I accomplish this?
#!/usr/bin/env python
from pprint import pformat
from cherrypy import wsgiserver
def app(environ, start_response):
status = '200 OK'
response_headers = [('Content-type', 'text/plain')]
start_response(status, response_headers)
return [pformat(environ)]
server = wsgiserver.CherryPyWSGIServer(('0.0.0.0', 80), app)
try:
server.start()
except KeyboardInterrupt:
server.stop()

You can check the request.scheme if it is "https" then you can raise a redirect.
See https://github.com/cherrypy/cherrypy/blob/f185ecd005d7fdbafb0ed83b0e49f05ac76e43fd/cherrypy/_cprequest.py#L218

Andrew Cox's link is broken again, here's the updated link to it. I don't have enough points to comment on his answer, hence the new answer.
https://cherrypy.readthedocs.org/en/3.3.0/refman/_cprequest.html#cherrypy._cprequest.Request.scheme

Related

How to WSGI application to make a redirect?

interested in how to make a redirect in a simple WSGI app.
I try so:
def some_functions(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/html'), ('Location', 'http://some_page')])
return []
But it doesn't work.
Must make a "return" without it not working, but that the return don't understand.
Tell me what I'm doing wrong?
You'll need to specify a 3xx HTTP response code. For example, you can use 302 Found to tell the client to visit the Location you provided.
Your code then becomes:
def some_functions(environ, start_response):
start_response('302 Found', [('Location', 'http://some_page')])
return []
You are right that you do need to return something. The return [] line works fine here, since there isn't a request body to be returned. Normally, a WSGI app should return a list of bytes, and technically [] is just an empty list of bytes.
On that note, you also don't need to provide a Content-Type, since there is no content being returned. The only thing needed to be sent to the client is the redirect information.

Print or return the request arguments/form data

I am using wsgi-request-logger https://github.com/pklaus/wsgi-request-logger in a flask application and need it to also log the request parameters (ie. the arguments that would be sent with the request).
Using request.form or request.args doesn't work and returns -
RuntimeError: Working outside of request context.
val['params'] = url_decode(environ.get('QUERY_STRING', ''))
print val['params']
This does not work and returns MultiDict([]) (tried it in middleware and the views.py file, it returns the same thing for both cases).
if environ['REQUEST_METHOD'] == 'POST':
print parse_form_data(environ)[1]
This returns MultiDict[] too.
I don't get what I am missing here. Help would be great.
Code which calls the middleware. I edited the middleware a bit and changed the files name to request_logger_wsgi as Im testing it with a local clone right now.
#!flask/bin/python
from app import app
from request_logger_wsgi import WSGILogger, ApacheFormatters
from logging.handlers import TimedRotatingFileHandler
def application(environ, start_response):
response_body = 'The request method was %s' % environ['REQUEST_METHOD']
response_body = response_body.encode('utf-8')
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response('200 OK', response_headers)
print response_body, "231321"
return [response_body]
handlers = [ TimedRotatingFileHandler('access.log', 'd', 7) , ]
app.wsgi_app = WSGILogger(app.wsgi_app, handlers, ApacheFormatters.format_log)
app.run(debug=True)
You should post more code of your application, otherwise it's very difficult to help.
You can't use Flask's request object in the WSGI layer. The wsgi-request-logger runs before Flask, that's why there is no request context yet.
You other code was probably run in a module and you used os.environ, which is different from the WSGI environment.
What you actually have to do is to create a custom formatter and tell
def query_formatter(status_code, environ, content_length):
return "{0} {1} {2}".format(dt.now().isoformat(), status_code,
environ.get('QUERY_STRING', ''))
And then set the formatter:
app = WSGILogger(application, handlers, query_formatter)
It would however be better to reuse one of the Apache formatters instead:
import requestlogger
def apache_query_formatter(status_code, environ, content_length):
return requestlogger.ApacheFormatters.format_NCSA_log(
status_code, environ, content_length) + environ.get('QUERY_STRING', '')
This formatter will use the NCSA format and append the query string. There are probably better formats for the log message, but this should get you started.

Quick Python Book message_wall01.py

I was wondering is someone could help me figure out why I keep getting the error AssertionError: Header names/values must be of type str (got b'Content-type')
127.0.0.1 - - [26/Mar/2015 20:50:52] "GET /favicon.ico HTTP/1.1" 500 59. The code comes from "The Quick Python Book" from Manning publishing.
from wsgiref.simple_server import make_server
def message_wall_app(environ, start_response):
status = b'200 OK' # HTTP Status
headers = [(b'Content-type', b'text/html; charset=utf-8')]
start_response(status, headers)
# The returned object is going to be printed
return ["<h1>Message Wall</h1>"]
httpd = make_server('', 8000, message_wall_app)
print("Serving on port 8000...")
# Serve until process is killed
httpd.serve_forever()
Remove the b's from:
status = '200 OK' # HTTP Status
headers = [('Content-type', 'text/html; charset=utf-8')]
And add to return ["<h1>Message Wall</h1>"]. You read unicode/str and write bytes.
The old docs had a bug where the examples used b'200 OK' etc.. which is what the book may have been based on, there is an old bug report here. The current docs show the correct usage.
Once you do that you will see the output at http://localhost:8000/ and without error.

uWSGI AJAX, reading a request

Hi I'm trying to get an ajax response from a wsgi server behind nginx (if that matters). I think I'm having issues reading the request as it would seem the variable request_body_size is always 0; I get a return value of "No Request" in the alert box when I would like to see "test string".
I cant find many docs on this or examples of this working, so if anyone knows how to fix this I would be grateful.
I have this python code in the WSGI script:
import os, sys
from cgi import parse_qs
def application(environ, start_response):
try:
request_body_size = int(environ.get('CONTENT_LENGTH', 0))
except (ValueError):
request_body_size = 0
context = {}
if request_body_size != 0:
request_body = environ['wsgi.input'].read(request_body_size)
output = parse_qs(request_body)
else:
output = "No request"
status = '200 OK'
response_headers = [('Content-type', 'text/html'),('Content-Length', str(len(output)))]
start_response(status, response_headers)
return [output]
and this is the js making the request (jquery):
function test_request()
{
var test_string = "test string";
$.ajax({
type: 'GET',
url:"/ajax",
data: test_string,
success:function(result){alert(result)}}
);
}
The ajax() method converts the 'data' value to a QUERY_STRING when the method is GET. Using POST should address the issue (or you can read environ['QUERY_STRING'])

How to run make_server from the simple_server in python on multiprocess?

I have one simple program of wsgi.
from wsgiref.simple_server import make_server
import time
def application(environ, start_response):
response_body = 'Hello World'
status = '200 OK'
response_headers = [('Content-Type', 'text/plain'),
('Content-Length', str(len(response_body)))]
start_response(status, response_headers)
if environ['PATH_INFO'] != '/favicon.ico':
print "Time :", int(time.time())
if int(time.time()) % 2:
print "Even"
time.sleep(10)
else:
print "Odd"
return [response_body]
httpd = make_server('localhost', 8000, application)
httpd.serve_forever()
So as per the code if the timestamp is Even then it will send response after 10 second. But if the timestamp is Odd then it will send response directly without sleep.
So my question is if i will send 2 request and if first request will send the request in Even mode then my second request will be serve after completing first one.
I check the solution and found that 'multiprocesscan solve this problem. I set the apache configuration withmultiprocess. Then I get the response forOddwithout completingEven` request.
I check how to set the multiprocess with make_server method of simple_server module. When I run the python /usr/lib64/python2.7/wsgiref/simple_server.py I get the output and last few lines are
wsgi.errors = <open file '<stderr>', mode 'w' at 0x7f22ba2a1270>
wsgi.file_wrapper = <class wsgiref.util.FileWrapper at 0x1647600>
wsgi.input = <socket._fileobject object at 0x1569cd0>
wsgi.multiprocess = False
wsgi.multithread = True
wsgi.run_once = False
wsgi.url_scheme = 'http'
wsgi.version = (1, 0)
So I was search how to set this make_server multiprocess so make_server can handle more then 1 request if any request is in progress.
Thx in advance.
If you're using Apache/mod_wsgi than you don't need the make_server/serve_forever stuff. Apache will handle that for you (as it is the web server). It will handle the processes and run the application callback function.
Make sure your Apache and mod_wsgi configuration allows multiprocess/multithread. Good reference is available here

Categories