Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CORS (Cross-origin resource sharing) not supported by cloud-function-python #48

Closed
santhoshdc1590 opened this issue Apr 11, 2018 · 14 comments

Comments

@santhoshdc1590
Copy link

santhoshdc1590 commented Apr 11, 2018

On POSTMAN the cloud function is working as expected.

Only when the cloud function URL is called from a browser I'm getting this error in the logs.

Traceback (most recent call last):
File "function.py", line 29, in
File "site-packages/cloudfn/http.py", line 45, in handle_http_event
File "site-packages/cloudfn/http.py", line 12, in init
KeyError: 'body'

This is my function.py file content

from FTUL import mainP
from cloudfn.google_account import get_credentials
from cloudfn.http import handle_http_event, Response
from google.cloud import bigquery
import json


def handle_http(req):
    
    biquery_client = bigquery.Client(credentials=get_credentials())
    
    console.log(req)
    console.log(req.method)
    console.log(req.body)

    if req.method == 'OPTIONS':
        return Response(
            status_code=200,
        )
    
    if req.method == 'POST':
        
        rBody = json.loads(req.body)
        im = rBody['image']
        rID = rBody['refID']
        rTable = rBody['refTable']
        uAlgo = 0
        empID = rBody['empID']
        val = mainP(im,rID,rTable,uAlgo,empID)

        return Response(
            status_code=200,
        )


handle_http_event(handle_http)

On the browser logs the error is being shown as a 500 error in the 'OPTIONS'

Browser is sending a req.method as OPTIONS but we have no body present in this req but function is expecting a body inside req.method.

What's the work around for this?

@MartinSahlen
Copy link
Owner

This seems to be a bug - does the same thing happen in GET requests?

@santhoshdc1590
Copy link
Author

santhoshdc1590 commented Apr 11, 2018

No this is not a BUG, its CORS.

Making Cross-Domain Requests with CORS

First OPTIONS is checked by the browser then the POST request is handled.

screen shot 2018-04-11 at 6 51 54 pm

But the file http.py, seems to have initialised the request in a pre-defined format, which expects body. Which is never going to happen. I need to make the request stop the search for the body by removing it from constructer I might screw up the entire code. I'm thinking about commenting out the self.body = raw_json['body']

Here's the http.py file

import json
import sys

import six
from six.moves.urllib_parse import urlparse


class Request:
    def __init__(self, raw_json):
        self.headers = raw_json['headers']
        self.method = raw_json['method']
        self.body = raw_json['body']
        self.url = raw_json['url']
        self.ip = raw_json['remote_addr']

        components = urlparse(self.url)
        self.path = components.path
        self.host = components.hostname
        self.scheme = components.scheme
        self.query = components.query
        self.port = components.port
        self.fragment = components.fragment
        self.params = components.params
        self.netloc = components.netloc


class Response:
    def __init__(self, headers=None, body='', status_code=200):
        self.headers = {} if headers is None else headers
        if isinstance(body, (six.text_type, six.binary_type, dict, list)):
            self.body = body
        else:
            self.body = str(body)
        self.status_code = status_code

    def _json_string(self):
        return json.dumps({
            'body': self.body,
            'status_code': self.status_code,
            'headers': self.headers,
        })


def handle_http_event(handle_fn):
    req = Request(json.loads(sys.stdin.read()))
    res = handle_fn(req)
    if isinstance(res, Response):
        sys.stdout.write(res._json_string())
    else:
        sys.stdout.write(Response()._json_string())

@santhoshdc1590
Copy link
Author

@MartinSahlen Can you help with this? I seem to be stuck, commenting the self.body = raw_json['body'] doesn't seem to be working

@santhoshdc1590
Copy link
Author

@MartinSahlen Will this work? A Python package for dealing with HTTP requests and same-origin policie
Can you help out here?

@santhoshdc1590
Copy link
Author

@MartinSahlen As you have written the main code here for the cloud-function-python and how it actually works. I feel you can fix this easily than me. Can you please fix it?

@santhoshdc1590 santhoshdc1590 changed the title KeyError: 'body' CORS (Cross-origin resource sharing) not included in cloud-function-python http.py popping KeyError:'body' Apr 11, 2018
@santhoshdc1590
Copy link
Author

santhoshdc1590 commented Apr 13, 2018

Tried to solve the CORS issue using django but I'm having python environments issue according to this issue I raised ImportError: Module "django.middleware.common" does not define a "CorsMiddleware" attribute/class

So tried versions of django-cors-headers, djangorestframework and django that are tested and working on python3.5. I still get ImportError. Looks like flask is the way to go

@santhoshdc1590
Copy link
Author

@MartinSahlen Looks like only you can help me. Please can you?

@MartinSahlen
Copy link
Owner

Hey! Unfortunately I do not have a lot of free time on my hands to investigate all of these issues, and at the moment the status of the library is very alpha, ie it “works on my machine”. I really am sorry to hear about all the issues you’re having though. I will try to carve out some time in the next week to help you out. In the meantime, you’re doing a (unfortunately for you) lot of good investigation so it’s easier to know where to start looking.

@santhoshdc1590
Copy link
Author

santhoshdc1590 commented Apr 13, 2018

@MartinSahlen I like to be optimistic. It's really nice that you have carved out so much of time to implement this cloud-function-python, Thank You for that. It's not unfortunate for me, I'm learning new things. Plus this is required at work for me, in fact this is currently my main work. 😅 I get that you don't have enough time to go through entire things at once to solve it.

Functionality I want to run on the cloud-function is perfect.

I want the function to be called from the browser. CORS is the only way to get the cloud-function when the browser sends out a request.

I am doing my best to figure out how you actually done this, to correct things on my own.

I DO NEED YOUR HELP BADLY, MORE THAN YOU KNOW😅

@santhoshdc1590
Copy link
Author

santhoshdc1590 commented Apr 13, 2018

@MartinSahlen Non of the version of the django-cors-headers are getting installed on the cloud. I'm getting the same error ImportError: No module named 'corsheaders'.

Failed to execute script function Traceback (most recent call last):
File "function.py", line 2, in File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py",
line 631, in exec_module File "mysite/wsgi.py",
line 16, in File "site-packages/django/core/wsgi.py",
line 13, in get_wsgi_application File "site-packages/django/init.py",
line 27, in setup File "site-packages/django/apps/registry.py",
line 85, in populate File "site-packages/django/apps/config.py",
line 90, in create File "importlib/init.py",
line 126, in import_module ImportError: No module named 'corsheaders'

I had a silly guess that memory of 256MB cloud-function was not enough so I used 2GB entire. But still the same error.

@santhoshdc1590 santhoshdc1590 changed the title CORS (Cross-origin resource sharing) not included in cloud-function-python http.py popping KeyError:'body' CORS (Cross-origin resource sharing) not supported by cloud-function-python Apr 13, 2018
@santhoshdc1590
Copy link
Author

@MartinSahlen
I had this error while importing the scipy

[13] Failed to execute script function Traceback (most recent call last):
File "function.py", line 7, in File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py",
line 631, in exec_module File "FTUL.py",
line 4, in File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py",
line 631, in exec_module File "site-packages/scipy/spatial/init.py",
line 95, in File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py",
line 714, in load_module File "messagestream.pxd",
line 5, in init scipy.spatial.qhull ImportError: No module named 'scipy._lib.messagestream'

I had to add

'--hidden-import', 'scipy._lib.messagestream', to cli.py line number 95 to support scipy

to fix it

I guess I just have to a similar import for this, before building cloud function python

Failed to execute script function Traceback (most recent call last):
File "function.py", line 2, in File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py",
line 631, in exec_module File "mysite/wsgi.py",
line 16, in File "site-packages/django/core/wsgi.py",
line 13, in get_wsgi_application File "site-packages/django/init.py",
line 27, in setup File "site-packages/django/apps/registry.py",
line 85, in populate File "site-packages/django/apps/config.py",
line 90, in create File "importlib/init.py",
line 126, in import_module ImportError: No module named 'corsheaders'

@santhoshdc1590
Copy link
Author

santhoshdc1590 commented Apr 14, 2018

I added

'--hidden-import', 'corsheaders.middleware', to cli.py file

which did take care of the ImportError: No module named 'corsheaders'

Now I'm getting this error

Internal Server Error: / Traceback (most recent call last):
File "site-packages/django/core/handlers/exception.py", line 39, in inner
File "site-packages/django/core/handlers/base.py", line 172, in _get_response
File "site-packages/django/urls/resolvers.py", line 267, in resolve
File "site-packages/django/utils/functional.py", line 35, in get
File "site-packages/django/urls/resolvers.py", line 310, in url_patterns
File "site-packages/django/utils/functional.py", line 35, in get
File "site-packages/django/urls/resolvers.py", line 303, in urlconf_module
File "importlib/init.py", line 126, in import_module
File "", line 986, in _gcd_import
File "", line 969, in _find_and_load
File "", line 958, in _find_and_load_unlocked
File "", line 673, in _load_unlocked
File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py", line 631, in exec_module
File "mysite/urls.py", line 17, in
File "/app/cloudfn/pip-cache-3.5/lib/python3.5/site-packages/PyInstaller/loader/pyimod03_importers.py", line 631, in exec_module
File "mysite/myapp/urls.py", line 2, in ImportError: No module named 'mysite.myapp.views'

I tried importing the module in all which ways mentioned but same ImportError

I guess the entire structure of django is not correct

@santhoshdc1590
Copy link
Author

@MartinSahlen

This is my urls.py file

from django.conf.urls import url
from .views import runAlgo

urlpatterns = [
    url(r'^run', runAlgo),
    ]

This is my views.py file

from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny
from FTUL import mainP

@api_view(http_method_names=['POST','OPTIONS'])
@permission_classes((AllowAny, ),)
def runAlgo(request):
    
    if request.method== 'OPTIONS':
    	return Response(status=status.HTTP_200_OK)

    if request.method == 'POST':

    	### Getting image URL
    	image = request.POST.getlist('image')
    	image = ''.join(str(e) for e in image)

    	#### Getting RefID
    	refID = request.POST.getlist('refID')

    	#### Getting RefTable
    	refTable = request.POST.getlist('refTable')

    	#### Getting RefID
    	empID = request.POST.getlist('empID')
    	empID = ''.join(str(e) for e in empID)

    	uAlgo = 0

    	typeID = request.POST.getlist('typeID')

    	appID = request.POST.getlist('appID')

    	version = request.POST.getlist('version')

    	#image URL, refID, refTable, Algo(cuurently selected 2), empID, typeID, appID, version 
    	val = mainP(image,refID,refTable,2,empID,typeID,appID,version)
        
	    return Response(
	            status=status.HTTP_201_CREATED)

This is my POSTMAN result

screen shot 2018-04-16 at 7 39 13 pm

This is the logs on the google cloud

screen shot 2018-04-16 at 7 42 33 pm

I have ran out of options I really need this thing working.

@kishore7403
Copy link

If you want to Allow all HTTP methods request to your google cloud function from the front end and face an issue with CORS. The Following template must work. It worked for me.

#import required packages
import json

def function_name(request):
    if request.method == 'OPTIONS':
        headers = {
            'Access-Control-Allow-Origin': '*',  # Allow your function to be called from any domain
            'Access-Control-Allow-Methods': '*',  # Allow all HTTP methods
            'Access-Control-Allow-Headers': 'Content-Type', 
            'Access-Control-Max-Age': '3600',
        }
        return ('', 204, headers)

    # Set CORS headers for main requests
    headers = {
        'Access-Control-Allow-Origin': '*',
    }

    # Your code logic goes here

    # Return your response
    return (json.dumps({'status': 'success'}), 200, headers)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants