blob: 09c3665a63ffee68a1aa80c703feded97f50820e [file] [log] [blame]
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Handles requests GCS API requests.
Includes a WSGI application that forwards Google Cloud Stroage API requests
to the local emulation layer.
"""
import httplib
import logging
import webob
from google.appengine.ext.cloudstorage import stub_dispatcher
from google.appengine.tools.devappserver2 import wsgi_server
# Regex for all requests routed through this module.
GCS_URL_PATTERN = '_ah/gcs/(.+)'
HTTP_308_STATUS_MESSAGE = 'Resume Incomplete'
class Application(object):
"""A WSGI application that forwards GCS requests to stub."""
def __call__(self, environ, start_response):
"""Handles WSGI requests.
Args:
environ: An environ dict for the current request as defined in PEP-333.
start_response: A function with semantics defined in PEP-333.
Returns:
An iterable over strings containing the body of the HTTP response.
"""
request = webob.Request(environ)
try:
result = stub_dispatcher.dispatch(request.method, request.headers,
request.url, request.body)
except ValueError as e:
status_message = httplib.responses.get(e.args[1], '')
start_response('%d %s' % (e.args[1], status_message), [])
return [e.args[0]]
# The metadata headers must be convereted from unicode to string.
headers = []
for k, v in result.headers.iteritems():
headers.append((str(k), str(v)))
# GCS uses non-standard HTTP 308 status code.
status_code = result.status_code
if status_code == 308:
status_message = HTTP_308_STATUS_MESSAGE
else:
status_message = httplib.responses.get(status_code, '')
start_response('%d %s' % (status_code, status_message), headers)
return [result.content]
class GCSServer(Application, wsgi_server.WsgiServer):
"""Serves API calls over HTTP."""
def __init__(self, host, port):
self._host = host
super(GCSServer, self).__init__((host, port), self)
def start(self):
"""Start the API Server."""
super(GCSServer, self).start()
logging.info('Starting Google Cloud Storage server at: http://%s:%d',
self._host, self.port)