Val G.
Val G.

Reputation: 141

Flask passing another url through url variable

I'm trying to build a cors proxy through flask from scratch. Here's my code

@app.route('/api/v1/cors/url=<name>&method=<method>', methods=['GET'])
def api_cors(name, method):
    if method == 'http' or method == 'https':
        r = request.urlopen(method+"://"+name)
        return r.read()
    else:
        return "method not set!"

It is working good so far but I have one problem, when I pass "url=google.com&method=https" it is working fine but when I pass something like "url=google.com/images/image.jpg&method=https" the "/" will considered as a new directory

Is there anyway to evade this in flask?

Upvotes: 2

Views: 2725

Answers (3)

w. Patrick Gale
w. Patrick Gale

Reputation: 2307

In my use-case I am building a MS Graph file browser which receives a @odata.nextLink value from Graph API calls, which look like https://graph.microsoft.com/v1.0/groups/myGroupId/drive/items('driveItem')/children?$select=id,name,webUrl&$top=10&$skiptoken=someToken.

In my main python script I add a quote function to the jinja environment using urllib.parse.quote. We need this to encode the URLs within our jinja templates:

import urllib
app.jinja_env.globals.update(Auth=identity.web.Auth, quote=urllib.parse.quote)

In my Jinja template I use the following to encode the result['@odata.nextLink'] URL and make sure to set safe='' so the / characters are also encoded. This encoded URL is sent to our odNextLink route:

<a href="{{ url_for('odNextLink', nextLink=quote(result['@odata.nextLink'], safe='')) }}">Next link</a>

In our route we need to make sure we have import urllib so we can unencoded the URL using urllib.parse.unquote(nextLink) before calling the API endpoint.

# this route should return results from a Graph API 'nextLink' call
@app.route("/od_group_items/<nextLink>")
def odNextLink(nextLink):
    import urllib
    token = app.auth.get_token_for_user(ast.literal_eval(os.getenv('SCOPE')))
    if "error" in token:
        return redirect(url_for("login"))
    api_result = requests.get(
        urllib.parse.unquote(nextLink),
        headers={'Authorization': 'Bearer ' + token['access_token']},
        timeout=30,
    ).json()
    return api_result

Upvotes: 0

Jake Conway
Jake Conway

Reputation: 909

If you want use the same URL scheme that you're using now, change your routing decorator to this and it will work.

@app.route('/api/v1/cors/url=<path:name>&method=<method>', methods=['GET'])

Upvotes: 2

Daniel Roseman
Daniel Roseman

Reputation: 599580

Don't try and pass the value as part of the route itself. Pass it as a query parameter.

@app.route('/api/v1/cors/')
def api_cors():
    url = request.args.get('url')

and call it as "/api/v1/cors/?url=https://google.com/images/image.jpg".

Upvotes: 4

Related Questions