thirdparty/google_appengine/google/appengine/tools/appengine_rpc.py
changeset 2273 e4cb9c53db3e
parent 828 f5fd65cc3bf3
child 3031 7678f72140e6
--- a/thirdparty/google_appengine/google/appengine/tools/appengine_rpc.py	Tue Apr 21 16:28:13 2009 +0000
+++ b/thirdparty/google_appengine/google/appengine/tools/appengine_rpc.py	Fri Apr 24 14:16:00 2009 +0000
@@ -41,6 +41,7 @@
 except ImportError:
   pass
 
+logger = logging.getLogger('google.appengine.tools.appengine_rpc')
 
 def GetPlatformToken(os_module=os, sys_module=sys, platform=sys.platform):
   """Returns a 'User-agent' token for the host system platform.
@@ -61,6 +62,33 @@
   else:
     return "unknown"
 
+def HttpRequestToString(req, include_data=True):
+  """Converts a urllib2.Request to a string.
+
+  Args:
+    req: urllib2.Request
+  Returns:
+    Multi-line string representing the request.
+  """
+
+  headers = ""
+  for header in req.header_items():
+    headers += "%s: %s\n" % (header[0], header[1])
+
+  template = ("%(method)s %(selector)s %(type)s/1.1\n"
+              "Host: %(host)s\n"
+              "%(headers)s")
+  if include_data:
+    template = template + "\n%(data)s"
+
+  return template % {
+      'method' : req.get_method(),
+      'selector' : req.get_selector(),
+      'type' : req.get_type().upper(),
+      'host' : req.get_host(),
+      'headers': headers,
+      'data': req.get_data(),
+      }
 
 class ClientLoginError(urllib2.HTTPError):
   """Raised to indicate there was an error authenticating with ClientLogin."""
@@ -70,13 +98,16 @@
     self.args = args
     self.reason = args["Error"]
 
+  def read(self):
+    return '%d %s: %s' % (self.code, self.msg, self.reason)
+
 
 class AbstractRpcServer(object):
   """Provides a common interface for a simple RPC server."""
 
   def __init__(self, host, auth_function, user_agent, source,
                host_override=None, extra_headers=None, save_cookies=False,
-               auth_tries=3, account_type=None):
+               auth_tries=3, account_type=None, debug_data=True, secure=False):
     """Creates a new HttpRpcServer.
 
     Args:
@@ -95,13 +126,19 @@
         implement this functionality.  Defaults to False.
       auth_tries: The number of times to attempt auth_function before failing.
       account_type: One of GOOGLE, HOSTED_OR_GOOGLE, or None for automatic.
+      debug_data: Whether debugging output should include data contents.
     """
+    if secure:
+      self.scheme = "https"
+    else:
+      self.scheme = "http"
     self.host = host
     self.host_override = host_override
     self.auth_function = auth_function
     self.source = source
     self.authenticated = False
     self.auth_tries = auth_tries
+    self.debug_data = debug_data
 
     self.account_type = account_type
 
@@ -115,9 +152,9 @@
     self.cookie_jar = cookielib.MozillaCookieJar()
     self.opener = self._GetOpener()
     if self.host_override:
-      logging.info("Server: %s; Host: %s", self.host, self.host_override)
+      logger.info("Server: %s; Host: %s", self.host, self.host_override)
     else:
-      logging.info("Server: %s", self.host)
+      logger.info("Server: %s", self.host)
 
     if ((self.host_override and self.host_override == "localhost") or
         self.host == "localhost" or self.host.startswith("localhost:")):
@@ -200,8 +237,9 @@
     continue_location = "http://localhost/"
     args = {"continue": continue_location, "auth": auth_token}
     login_path = os.environ.get("APPCFG_LOGIN_PATH", "/_ah")
-    req = self._CreateRequest("http://%s%s/login?%s" %
-                              (self.host, login_path, urllib.urlencode(args)))
+    req = self._CreateRequest("%s://%s%s/login?%s" %
+                              (self.scheme, self.host, login_path,
+                               urllib.urlencode(args)))
     try:
       response = self.opener.open(req)
     except urllib2.HTTPError, e:
@@ -291,30 +329,39 @@
     socket.setdefaulttimeout(timeout)
     try:
       tries = 0
+      auth_tried = False
       while True:
         tries += 1
         args = dict(kwargs)
-        url = "http://%s%s?%s" % (self.host, request_path,
-                                  urllib.urlencode(args))
+        url = "%s://%s%s?%s" % (self.scheme, self.host, request_path,
+                                urllib.urlencode(args))
         req = self._CreateRequest(url=url, data=payload)
         req.add_header("Content-Type", content_type)
         req.add_header("X-appcfg-api-version", "1")
         try:
+          logger.debug('Sending HTTP request:\n%s' %
+                       HttpRequestToString(req, include_data=self.debug_data))
           f = self.opener.open(req)
           response = f.read()
           f.close()
           return response
         except urllib2.HTTPError, e:
-          logging.debug("Got http error, this is try #%s" % tries)
+          logger.debug("Got http error, this is try #%s" % tries)
           if tries > self.auth_tries:
             raise
           elif e.code == 401:
+            if auth_tried:
+              raise
+            auth_tried = True
             self._Authenticate()
           elif e.code >= 500 and e.code < 600:
             continue
           elif e.code == 302:
+            if auth_tried:
+              raise
+            auth_tried = True
             loc = e.info()["location"]
-            logging.debug("Got 302 redirect. Location: %s" % loc)
+            logger.debug("Got 302 redirect. Location: %s" % loc)
             if loc.startswith("https://www.google.com/accounts/ServiceLogin"):
               self._Authenticate()
             elif re.match(r"https://www.google.com/a/[a-z0-9.-]+/ServiceLogin",
@@ -337,14 +384,14 @@
   def _Authenticate(self):
     """Save the cookie jar after authentication."""
     if cert_file_available and not uses_cert_verification:
-      logging.warn("ssl module not found. Without this the identity of the "
-                   "remote host cannot be verified, and connections are NOT "
-                   "secure. To fix this, please install the ssl module from "
-                   "http://pypi.python.org/pypi/ssl")
+      logger.warn("ssl module not found. Without this the identity of the "
+                  "remote host cannot be verified, and connections are NOT "
+                  "secure. To fix this, please install the ssl module from "
+                  "http://pypi.python.org/pypi/ssl")
     super(HttpRpcServer, self)._Authenticate()
     if self.cookie_jar.filename is not None and self.save_cookies:
-      logging.info("Saving authentication cookies to %s" %
-                   self.cookie_jar.filename)
+      logger.info("Saving authentication cookies to %s" %
+                  self.cookie_jar.filename)
       self.cookie_jar.save()
 
   def _GetOpener(self):
@@ -369,19 +416,19 @@
         try:
           self.cookie_jar.load()
           self.authenticated = True
-          logging.info("Loaded authentication cookies from %s" %
-                       self.cookie_jar.filename)
+          logger.info("Loaded authentication cookies from %s" %
+                      self.cookie_jar.filename)
         except (OSError, IOError, cookielib.LoadError), e:
-          logging.debug("Could not load authentication cookies; %s: %s",
-                        e.__class__.__name__, e)
+          logger.debug("Could not load authentication cookies; %s: %s",
+                       e.__class__.__name__, e)
           self.cookie_jar.filename = None
       else:
         try:
           fd = os.open(self.cookie_jar.filename, os.O_CREAT, 0600)
           os.close(fd)
         except (OSError, IOError), e:
-          logging.debug("Could not create authentication cookies file; %s: %s",
-                        e.__class__.__name__, e)
+          logger.debug("Could not create authentication cookies file; %s: %s",
+                       e.__class__.__name__, e)
           self.cookie_jar.filename = None
 
     opener.add_handler(urllib2.HTTPCookieProcessor(self.cookie_jar))