1
votes

I am trying to upload a blob to BlobStore from python and it works when on https://...appspot.com and https://...com/ but when the exact same code is executed from http it does not work and BlobStore returns 500 error.

I have tried making the connection always secure even even when not.

Here is my code:

@staticmethod
def save_to_blobstore(_request, id, file_contents, file_type, file_name = 'fixmeh.png'):
    upload_url  = blobstore.create_upload_url('/upload-item/blob-key/{}'.format(id))

    if upload_url.startswith('http://') and 'localhost.com' not in _request.get_host():
        upload_url = 'https' + upload_url[4:]

    # ----- CREATING FORMDATA -----
    boundary = 'WebKitFormBoundaryE19zNvXGzXaLvS5C'
    body = '\r\n'.join([
        '--' + boundary,
        'Content-Disposition: form-data; name="file"; filename="{}"'.format(file_name),
        'Content-Type: {}'.format(file_type),
        '',
        file_contents,
        '',
        '--' + boundary + '--',
        '',
    ])

    headers = {
        'Content-Type'  : 'multipart/form-data; boundary={}'.format(boundary),
        'User-Agent'    : 'Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0',
    }

    logging.critical('blobstore save')

    # TODO Why the hell do we receive deadline limit exceeded?
    request = urllib2.Request(upload_url)

    # ----- FORCING SECURE CONNECTION EXCEPT ON LOCALHOST -----
    if 'localhost.com' in _request.get_host():
        conn = httplib.HTTPConnection(request.get_host(), timeout = 50)
    else:
        conn = httplib.HTTPSConnection(request.get_host(), timeout = 50)

    conn._follow_redirects = True

    logging.info(['upload_url', upload_url ])
    logging.info(['get_host', request.get_host() ])
    logging.info(['get_selector', request.get_selector() ])
    conn.request('POST', request.get_selector(), body, headers)

    try:
        response = conn.getresponse()
        response_body = response.read()

        logging.info(response_body)

        # TODO we need to have an exception if the response is not 200
    except DeadlineExceededError:
        logging.exception('Saving blob - DeadlineExceededError')
    except:
        logging.exception('Saving blob')

When executed through HTTP this is the return from BlobStore, though it does not help a lot. Is there a way to log blobstore error in https://console.developers.google.com/project/.../logs or anywhere else.

<html><head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">
<title>500 Server Error</title></head>
<body text=#000000 bgcolor=#ffffff>
<h1>Error: Server Error</h1>
<h2>The server encountered an error and could not complete your request.
<p>Please retry your last submission.</p>
<p>If the problem persists, please contact the person responsible for the application you're using, or, if you are that person,
<a href="http://code.google.com/appengine/community.html">report</a> your
problem and mention this error message and the query that caused it.</h2>
</body></html>

Can you help me with any ideas why the may not work on http but works on https. (NOTE it works with http on the SDK - no ssl there, this is only happening on appspot)

2
What error is in your logs? You have two logging.exception calls with string arguments. Do they appear? - Josh J

2 Answers

1
votes

I used this code for the full upload url using webapp2 routing:

upload_url = create_upload_url(webapp2.uri_for('blob_update', _full=True))

And the handler uses a webapp2 named route: 'blob_update'

class BlobUpdate(blobstore_handlers.BlobstoreUploadHandler):
    """ has named route : blob_update : 
    webapp2.Route(r'/blob_update', handler='....BlobUpdate', name='blob_update') """

    def post(self):
        """ blob upload handler returns the new blobkey"""

    blob_info = self.get_uploads('file')[0]
    ....

More here: App Engine update blob

0
votes

Thanks a lot for the directions and the speedy response. I have taken some ideas from your code and tweaked mine.

I really wished not to use google.appengine.api.urlfetch, sadly I have no time to experiment now at the moment.

Here is the final code just in case any one stumbles upon stuff (also please refer to voscausa's url "App Engine update blob":

    back_url = '{}{}/upload-item/blob-key/{}'.format(_request.protocol, _request.get_host(), id)
    # logging.info(back_url)

    upload_url  = blobstore.create_upload_url(back_url)

    BNDR = b'WebKitFormBoundaryE19zNvXGzXaLvS5C'  # '--PythonBlobstorevarBoundaryVXGzXaLvS5C'
    CRLF = b'\r\n'
    DD   = b'--'

    body = b''.join([
        DD + BNDR + CRLF,
        b'Content-Disposition: form-data; name="file"; filename="{}"'.format(file_name) + CRLF,
        b'Content-Type: {}'.format(file_type) + CRLF,
        CRLF,
        file_contents + CRLF,
        DD + BNDR + DD + CRLF,
    ])

    headers = {
        b'Content-Type' : b'multipart/form-data; boundary={}'.format(BNDR),
        # b'User-Agent' : b'Mozilla/5.0 (X11; Linux x86_64; rv:31.0) Gecko/20100101 Firefox/31.0',
    }

    try:
        response = urlfetch.fetch(
            url                 = upload_url,
            payload             = body,
            method              = urlfetch.POST,
            deadline            = 40,
            follow_redirects    = False,
            headers             = headers
        )

        if response.status_code == 200:
            logging.info(response.content)
        else:
            logging.info(response)
            logging.error(response.content)
            logging.exception('URL : {} fetch ERROR : {}'.format(upload_url, response.status_code))
    except (urlfetch.DownloadError, DeadlineExceededError), e:
        logging.exception('fetch {} download or deadline error, exception : {}'.format(upload_url, str(e)))