App.yaml on app engine is not forwarding wildcards properly - python

I tried recently to enable html5mode browsing in angular with
// use the HTML5 History API
$locationProvider.html5Mode(true);
Suddenly though, when I try to go to one of my client side routes, app engine seems not to even forward my request to my webapp2 handler.
For example, localhost:8080/#/myRoute routes properly when entered directly but localhost:8080/myRoute gives me a 404.
I recognize # indicates a client side route, but as long as my request is forwarded to my index.html angular should handle the request. I didn't explicitly create a route for /#/ so it seems like it's handling those as wildcards but not other routes.
I tried these routes in my app.yaml:
- url: /
script: server.web_server.main.app
- url: .*
script: server.web_server.main.app
- url: /.*
script: server.web_server.main.app
My server.web_server.main.app routing setup looks like:
app = webapp2.WSGIApplication([
# Main SPA handler
webapp2.Route('/', MainHandler, name='main'),
], debug=True)
MainHandler never even sees a request when I don't use # and the server logs indicate indeed they did have a 404. I could understand if both # and nothing caused a 404 then my wildcards would not be working properly, but why would /#/ work and / not work if I haven't put any special routing for /#/?
Can someone explain what I'm doing wrong?
Thanks in advance!
-- Jp.

MainHandler isn't seeing a request for /myRoute because only / is being routed (within the app) to that handler, even though your app.yaml is routing requests to the app.
Try adding something like
webapp2.Route('/myRoute', MainHandler, name='myroutemain'),
to the WSGIApplication.

So the post above is totally correct, but I thought I would add an even simpler solution solution which doesn't require you to hand specify each client side route.
You can add a wildcard regex by doing the following:
class MainHandler(BaseHandler):
def get(self, opt=None):
self.render("index.html", {"title": "My Angular App"})
app = webapp2.WSGIApplication([
# Main SPA handler
webapp2.Route(r'/<:.*>', MainHandler, name='main')
], debug=True)
I didn't quite have the syntax right for the regex when I tried originally. The captured value gets passed to get which you can use if you want.

Related

Webob / Pyramid query string parameters out of order upon receipt

I am running Pyramid as my API server. Recently we started getting query string parameters out of order when handed to the RESTful API server. For example, a GET to /v1/finishedGoodRequests?exact=true&id=39&join=OR&exact=false&name=39
is logged by the RESTful api module upon init as request.url:
v1/finishedGoodRequests?join=OR&name=39&exact=true&exact=false&id=39
with request.query_string: join=OR&name=39&exact=true&exact=false&id=39
I process the query params in order to qualify the search, in this case id exactly 39 or 39 anywhere in the name. What kind of possible server setting or bug could have crept in to the server code to cause such a thing? It is still a MultiDict...
As a simple example, this works fine for me, and the MultiDict has always preserved the order and so I suspect something is getting rewritten by something you're using in your stack.
from pyramid.config import Configurator
from pyramid.view import view_config
from waitress import serve
#view_config(renderer='json')
def view(request):
return list(request.GET.items())
config = Configurator()
config.scan(__name__)
app = config.make_wsgi_app()
serve(app, listen='127.0.0.1:8080')
$ curl http://localhost:8080\?join=OR\&name=39\&exact=true\&exact=false\&id=39
[["join", "OR"], ["name", "39"], ["exact", "true"], ["exact", "false"], ["id", "39"]]
Depending on which WSGI server you are using, often you can view environ vars to see the original url which may be handy. Waitress does not, so instead just put something high up in the pipeline (wsgi middleware) that can log out the environ['QUERY_STRING'] and see if it doesn't match somewhere lower down in your stack.

Redirect doesn't seem to work on G.A.E

I'm using Python 2.7 and Google App engine. I've written a page that redirects a user to a form after Oauth has completed. This works perfectly on localhost, but it fails when I deploy to the app engine. What am I doing wrong?
The error message I get is "404. That’s an error. The requested URL /form was not found on this server. That’s all we know."
The server logs don't show my /form request at all.
Relevant snippets follow:
1.app.yaml
handlers:
- url: .*
script: public.main.app
builtins:
- remote_api: on
- admin_redirect: on
2.main.py
app = webapp2.WSGIApplication([
('/form?$', content.Home),
('/oauthcallback?$', content.CallbackHandler),],
debug=True)
3.content.py fxn for /oauthcallback
....
http = credentials.authorize(http)
self.redirect('/form')
Hooray!
Thanks guys for all your help.
#Dave Smith, that syntax: '/form?$' is perfectly alright.
It turns out that '/form' is reserved by the GAE. I renamed my entry and now it works perfectly.
See: https://developers.google.com/appengine/docs/python/config/appconfig#Reserved_URLs

Restrict view to only be accessible by App Engine internal network

I would like to find a way to restrict a view (request handler) to only be called from within the Google App Engine internal network from within my view and not within app.yaml.
For example, I have a view to handle inbound email within my Flask application
#app.route('/_ah/mail/notifications#example.appspotmail.com', methods=['POST'])
def inbound_notification_email():
from google.appengine.api import mail
message = mail.InboundEmailMessage(request.data)
...
return '' # 200 OK
While I know I could put all my mail handlers in their own file / wsgi instance like so:
handlers:
- url: /_ah/mail/.+
script: inbound_mail.app
login: admin
I would prefer not to have to do this as I'm using Flask instead of Webapp. Right now the request works as setup above, but it is exposed to the world.
Inspecting the request to my inbound_notification_email() view, I see X-App-Country in the request header is set to ZZ and the request's remote address is 0.1.0.20. I know the 0.x.x.x IP range is IANA reserved for local networks so it seems logical that checking if request.remote_address starts with "0." would work, but I'm not sure if all internal requests within App Engine are always handled this way (push queues and xmpp come to mind).
One thing I was surprised to see was users.is_current_user_admin() returns False within inbound_notification_mail() even though you're to set login: admin when using Webapp.

Pylons - Redirects will drop from HTTPS to HTTP unless I specify the protocol... Is there a way to fix this?

On my Pylons website, I have my login form sending it's data to 'https://mysite.com'. Upon a successful login, a redirect takes place to send them to their profile page.
redirect(url(controller='profile'))
This sends the user to http://mysite.com/profile instead of https://mysite.com/profile. The only way I've found to fix this is to change the redirect to:
redirect(url(controller='profile', protocol='https'))
The problem I have with this is "what if, for whatever reason, my cert goes away and I have to drop SSL" I don't want to have to go through my entire code looking for all redirects I specify the 'https' protocol in. I want my login to send the user to HTTPS and that's it...
Is there a reason the redirect drops to HTTP? Is there a way to stop it? :/
Since I spent a couple of hours wading through the pylons/routes/beaker/etc. source I thought I'd share my solution.
First a bit of context. I'm using an elastic load balancer (ELB) on AWS with SSL termination. The application is built to run solely over https; this is a post-firesheep world after all. It's layered like so:
ELB -> nginx -> pasteWSGI -> pylons
ELB is jolly good in terms of simplicity but any call to pylons.controllers.util.redirect would trigger a 302 Redirect to "http://mysite/". The ELB would not change that on the way back (no reason to) and so my browser would be sent back to port 80 and there is no ELB listening on that port.
I've tried updating the Mapper as suggested above.
it did not work,
I wanted my redirects to be relative. Switching to https in pylons means that the URL generator goes and fetches the host to create a new URL (https://localhost/....)
Note that Mapper.redirect_to works out of the box and uses relative redirects so there is no need to mess with that. The fundamental problem is that controllers.redirect uses a slightly different code path. In particular, in Routes, the controllers.util.redirect is not a redirect (there's an "if routes and routes.redirect" which evals to False).
My solution: replace all calls to redirect by a new controller method (called redirect too) to change redirects from absolute to relative redirects.
The code is as follows:
lib/helpers.py
def relative_redirect(to_url, start_response):
"""Returns a redirect that is compatible with AWS ELB (no absolute http responses)
Using pylons.controllers.util.redirect triggers an exception that'll be turned into a 302
But with an absolute path so the response does not contains https but simple http
"""
start_response("302 Found", [("Content-Type", "text/plain; charset=utf-8"), ("Location", url(to_url))])
return ["You are being redirected to {0}".format(url(to_url))]
With that bit called from the base class of my controllers:
class BaseController(WSGIController):
...
def redirect(self, to_url):
"""Force a relative redirection, to work with AWS ELB"""
return relative_redirect(to_url, self.start_response)
I'd customize the Mapper so that every call to "url" would force the correct protocol...
Inside routing.py:
class CustomMapper(Mapper):
def generate(self, *args, **kwargs):
kwargs["protocol"] = "https"
return Mapper.generate(self, *args, **kwargs)
def make_map(config):
"""Create, configure and return the routes Mapper"""
map = CustomMapper(directory=config['pylons.paths']['controllers'],
always_scan=config['debug'])

App Engine Python how to handle urls?

I just want to ask a simple question, as I don't imagine how to do it.
In the app.yaml, when I want to declare query string parameter, how do I do it?
For example, to make a multi language site, I create the url in this format:
mysite.com/english/aboutus
mysite.com/italiano/aboutus
and in app.yaml the script to handle them are
- url: /english/aboutus
script: index.py
- url: /italiano/aboutus
script: index.py
In which way can I determine the difference between these two urls, and how to handle them in index.py?
I know this is simple question, I could look around for references, but it might help for others in stackoverflow.com as well.
I remember doing something like this:
in app.yaml put
- url: /(.*)/(.*)/?
script: main.py
and in main.py
class MainHandler(webapp.RequestHandler):
def get(self, Urlpart1, Urlpart2):
def main():
application = webapp.WSGIApplication([('/(.*)/(.*)/', MainHandler),
('/(.*)/(.*)', MainHandler)],
debug=True)
where Urlparts are words between slashes
Instead you could use the webapp framework to handle the URL's.
For example, in index.py
application = webapp.WSGIApplication(
[('/english', EnglishHandler)],
[('/italiano', ItalianHandler)],
debug=True)
More information can be found here. http://code.google.com/appengine/docs/python/gettingstarted/usingwebapp.html
The SCRIPT_NAME environ entry contains the path under which your script was invoked. Haven't tested this in GAE specifically, but it's something WSGI inherited from CGI.
language= environ['SCRIPT_NAME'][1:].split('/', 1)[0]
if language not in ('english', 'italiano'):
language= 'english'
There're 39 human languages supported. Best way seems comply via lib/django/django/conf/locale/
Here's an app that translates all engines messages via parameter hl=[languageCode]
[code disposable]2

Categories

Resources