title: How can store a file on Google Storage from URL on Google App Engine?
body: <p>I want to create a service on Google App Engine (Python) that will receive a URL of an image and store it on Google Storage. I managed to upload from a local file using <code>boto</code> or <code>gsutil</code> command line, but not by retrieving the file via URL. I tried doing it using the <a href="http://code.google.com/apis/storage/docs/reference-methods.html#putobject" rel="nofollow noreferrer">HTTP requests (<code>PUT</code>)</a> and I'm getting error responses for wrong signatures. Obviously I'm doing something wrong, but unfortunately I have no idea where. </p>
  
  <p>So my question is: How can I retrieve a file from a URL and store it on Google Storage using Python for Google App Angine?</p>
  
  <p>Here is what I've done (using another <a href="https://stackoverflow.com/questions/3822385/google-storage-api-put-file-problem-in-python/3837802#3837802">answer</a>):</p>
  
  <pre><code>class ImportPhoto(webapp.RequestHandler):
      def get(self):
          self.response.headers['Content-Type'] = 'text/plain'
          srow = self.response.out.write
          url = self.request.get('url')
          srow('URL: %s\n' % (url))
          image_response = urlfetch.fetch(url)
          m = md5.md5()
          m.update(image_response.content)
          hash = m.hexdigest()
          time = "%s" % datetime.utcnow().strftime("%a, %d %b %Y %H:%M:%S GMT")
          str_to_sig = "PUT\n" + hash + "\n\n" + 
                        time + "\nx-goog-acl:public-read\n/lipis/8418.png"
          sig = base64.b64encode(hmac.new(
                                    config_credentials.GS_SECRET_ACCESS_KEY,
                                    str_to_sig, hashlib.sha1).digest())
          total = len(image_response.content) 
          srow('Size: %d bytes\n' % (total))
  
          header = {"Date": time,
                    "x-goog-acl": "public-read",
                    "Content-MD5": hash,
                    'Content-Length': total,
                    'Authorization': "GOOG1 %s:%s" % 
                                      (config_credentials.GS_ACCESS_KEY_ID, sig)}
  
          conn = httplib.HTTPConnection("lipis.commondatastorage.googleapis.com")
          conn.set_debuglevel(2)
  
          conn.putrequest('PUT', "/8418.png")
          for h in header:
              conn.putheader(h, header[h])
          conn.endheaders()
          conn.send(image_response.content + '\r\n')
          res = conn.getresponse()
  
          srow('\n\n%d: %s\n' % (res.status, res.reason))
          data = res.read()
          srow(data)
          conn.close()
  </code></pre>
  
  <p>And I'm getting as a response:</p>
  
  <pre><code>URL: https://stackoverflow.com/users/flair/8418.png
  Size: 9605 bytes
  
  400: Bad Request
  &lt;?xml version='1.0' encoding='UTF-8'?&gt;&lt;Error&gt;&lt;Code&gt;BadDigest&lt;/Code&gt;&lt;Message&gt;The Content-MD5 you specified did not match what we received.&lt;/Message&gt;&lt;Details&gt;lipis/hello.jpg&lt;/Details&gt;&lt;/Error&gt;
  </code></pre>