Loosing Header over nginx

In my app I serve a booking form - newbooking.html - , after sending it I want to present the user a detail.html page, showing the content of the just sent booking in a table and under the table buttons. The first button should always be visible, it’s there to send the admins a message concerning the booking (users can visit the detail page for all their bookings, not just a recently sent one). The second one should only be there if the user got redirected to the detail.html page from the newbooking.html page; so after submitting the newbooking form. This button simply links to the newbooking.html page and says something like “send another booking”

Initial solution - request.referrer

My initial solution was to check for the request.referrer in the jinja2 template and if it matches my domain and the path for newbooking.html, show the second button. So in my routes I check if I have a validate_on_submit() do stuff to the form data and the redirect to the detail.html page passing along the dynamic uuid. routes.py

 1@bp.route('/newbooking', methods=['GET', 'POST'])
 2def newbooking():
 3    
 4    form=BookingForm()
 5
 6    if form.validate_on_submit():
 7        uuid = generate('123456789ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz', 8)
 8        #do stuff with the data from the form
 9
10        
11        flash('You just sent us the following booking:'
12      return redirect(url_for('detail', buuid=uuid))

jinja2 template

 1{% extends 'base.html' %}
 2
 3{% block app_content %}
 4<h1>Details for Booking: {{ buuid.booking_uuid }}</h1>
 5<div class="row">
 6    <div class="table-responsive">
 7        <table class="table table-condensed table-hover">          
 8            <tr>
 9                <td>BOOKING CONTENT HERE</td>
10            </tr>   
11        </table>
12
13        {% if request.referrer != None and request.referrer[-11:] == "/newbooking" %}
14            <tr>
15                <td colspan="2"><a href="{{ url_for('bookingmsg', buuid=buuid.booking_uuid) }}"><button type="button" class="btn btn-warning" style="width:100%; margin-bottom: 15px;">send us a message for this booking</button></a></td>
16            </tr>
17            <tr>
18                <td colspan="2"><a href="{{ url_for('newbooking') }}"><button type="button" class="btn btn-success" style="width:100%">make a new booking</button></a></td>
19            </tr>
20            
21            {% else %}
22            <tr>
23                <td colspan="2"><a href="{{ url_for('bookingmsg', buuid=buuid.booking_uuid) }}"><button type="button" class="btn btn-warning " style="width:100%; margin-bottom: 15px;">send us a message for this booking</button></a></td>
24            </tr>
25            {% endif %}
26
27    </div>
28
29</div>
30
31    
32{% endblock app_content %}

This worked fine on my local setup. The client receives the request.referrer (one can check it in the developer console with document.referrer). So I happily pushed to production. It stopped working.

Production server problems

My production server is a small AWS Lightsail instance running debian and service my flask app via gunicorn and a nginx reverse proxy.

 1server {
 2
 3listen 443 ssl;
 4
 5server_name app.info
 6
 7
 8access_log /var/log/access.log;
 9
10error_log /var/log/error.log;
11
12
13location / {
14
15proxy_pass http://localhost:8000;
16
17proxy_redirect off;
18
19proxy_set_header Host $host;
20
21proxy_set_header X-Real-IP $remote_addr;
22
23proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
24
25}
26
27ssl_certificate path/to/cert
28
29ssl_certificate_key /path/to/certkey
30
31}

Surfing on my app the referrer normally showed up fine: app.info/whateverpage. BUT after submitting a form and getting redirected to the detail.html page left the referrer empty. So obviusly my jinja template never showed the make a new booking button. My guess was that there is a problem between the nginx reverse proxy and gunicorn, which removes the referrer, when landing on a page after a flask redirect, since it worked fine after flask render_template. I tried building my own responses and including the referrer in the header - to no avail. I was ready to give up. I already spent several hours making this button appear in production. Then I found a workaround!

request.args to the rescue

I appened a parameter/argument to the flask redirect after submitting the form! All this does it append ?redirected=True to the url. So hitting detail.html after the redirect shows up as https://app.info/detail/<buuid>?redirected=True So my updated routes.py:

 1@bp.route('/newbooking', methods=['GET', 'POST'])
 2def newbooking():
 3    
 4    form=BookingForm()
 5
 6    if form.validate_on_submit():
 7        uuid = generate('123456789ABCDEFGHJKMNPQRSTUVWXYZabcdefghjkmnpqrstuvwxyz', 8)
 8        #do stuff with the data from the form
 9
10        
11        flash('You just sent us the following booking:'
12      return redirect(url_for('detail', buuid=uuid, **redirected=True**)) #added parameter here!

updated part of the jinja2 template for detail.html:

 1{% if **request.args.get('redirected') == "True"** %} 
 2     <tr>
 3                <td colspan="2"><a href="{{ url_for('bookingmsg', buuid=buuid.booking_uuid) }}"><button type="button" class="btn btn-warning" style="width:100%; margin-bottom: 15px;">send us a message for this booking</button></a></td>
 4            </tr>
 5            <tr>
 6                <td colspan="2"><a href="{{ url_for('newbooking') }}"><button type="button" class="btn btn-success" style="width:100%">make a new booking</button></a></td>
 7            </tr>
 8            
 9            {% else %}
10            <tr>
11                <td colspan="2"><a href="{{ url_for('bookingmsg', buuid=buuid.booking_uuid) }}"><button type="button" class="btn btn-warning " style="width:100%; margin-bottom: 15px;">send us a message for this booking</button></a></td>
12            </tr>
13            {% endif %}       

The only caveat is that users can manually append ?redirected=True to their url. However, since the only functionality is to show or not show a button linking to a page they find in any way also in their navbar, I don’t see any problem (please correct me if I’m wrong)