4

Is it possible to use a cloud endpoint method as the callback for an upload? The uploadUrl is generated using the blobservice.

String url = blobstoreService.createUploadUrl("/_ah/api/project/v1/uploadcallback" , options);

For the moment, I get a 404 response from app engine server.

I get the following exception from the local test server :

HTTP ERROR 500

Problem accessing /_ah/upload/agtrdWJpdHktdGVzdHIbCxIVX19CbG9iVXBsb2FkU2Vzc2lvbl9fGAEM. Reason:

    Unexpected character ('-' (code 45)) in numeric value: expected digit (0-9) to follow minus sign, for valid numeric value
 at [Source: java.io.StringReader@3d3f1775; line: 1, column: 3]

Caused by:

com.google.appengine.repackaged.org.codehaus.jackson.JsonParseException: Unexpected character ('-' (code 45)) in numeric value: expected digit (0-9) to follow minus sign, for valid numeric value
 at [Source: java.io.StringReader@3d3f1775; line: 1, column: 3]
    at com.google.appengine.repackaged.org.codehaus.jackson.JsonParser._constructError(JsonParser.java:1432)
    at com.google.appengine.repackaged.org.codehaus.jackson.impl.JsonParserMinimalBase._reportError(JsonParserMinimalBase.java:385)
    at com.google.appengine.repackaged.org.codehaus.jackson.impl.JsonParserBase.reportUnexpectedNumberChar(JsonParserBase.java:960)
    at com.google.appengine.repackaged.org.codehaus.jackson.impl.ReaderBasedParser._handleInvalidNumberStart(ReaderBasedParser.java:957)
    at com.google.appengine.repackaged.org.codehaus.jackson.impl.ReaderBasedParser.parseNumberText(ReaderBasedParser.java:671)
    at com.google.appengine.repackaged.org.codehaus.jackson.impl.ReaderBasedParser.nextToken(ReaderBasedParser.java:476)
    at com.google.appengine.repackaged.org.codehaus.jackson.map.ObjectMapper._initForReading(ObjectMapper.java:2761)
    at com.google.appengine.repackaged.org.codehaus.jackson.map.ObjectMapper._readMapAndClose(ObjectMapper.java:2709)
    at com.google.appengine.repackaged.org.codehaus.jackson.map.ObjectMapper.readValue(ObjectMapper.java:1854)
    at com.google.api.server.spi.tools.devserver.RestApiServlet$LilyRequestMarshaller.createBackendRequestBody(RestApiServlet.java:76)
    at com.google.api.server.spi.tools.devserver.RestApiServlet$LilyRequestMarshaller.marshall(RestApiServlet.java:59)
    at com.google.api.server.spi.tools.devserver.RestApiServlet$LilyRequestMarshaller.access$100(RestApiServlet.java:54)
    at com.google.api.server.spi.tools.devserver.RestApiServlet.service(RestApiServlet.java:144)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
    at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:327)
    at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
    at com.google.appengine.api.blobstore.dev.UploadBlobServlet.handleUpload(UploadBlobServlet.java:432)
    at com.google.appengine.api.blobstore.dev.UploadBlobServlet.access$000(UploadBlobServlet.java:71)
    at com.google.appengine.api.blobstore.dev.UploadBlobServlet$1.run(UploadBlobServlet.java:117)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.google.appengine.api.blobstore.dev.UploadBlobServlet.doPost(UploadBlobServlet.java:114)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:637)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1166)
    at com.google.appengine.api.socket.dev.DevSocketFilter.doFilter(DevSocketFilter.java:74)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.ResponseRewriterFilter.doFilter(ResponseRewriterFilter.java:123)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.HeaderVerificationFilter.doFilter(HeaderVerificationFilter.java:34)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:61)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at com.google.appengine.tools.development.BackendServersFilter.doFilter(BackendServersFilter.java:97)
    at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
    at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
    at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
    at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
    at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
    at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
    at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:94)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:409)
    at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
    at org.mortbay.jetty.Server.handle(Server.java:326)
    at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
    at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:938)
    at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:755)
    at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:218)
    at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
    at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
    at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Cœur
  • 37,241
  • 25
  • 195
  • 267
Alex Kubity
  • 364
  • 4
  • 16

2 Answers2

4

From Uploading a Blob:

The form must include a file upload field, and the form's enctype must be set to multipart/form-data. When the user submits the form, the POST is handled by the Blobstore API, which creates the blob. The API also creates an info record for the blob and stores the record in the datastore, and passes the rewritten request to your application on the given path as a blob key.

As Endpoints doesn't (as far as I know) accept multipart/form-data as a valid encoding, this won't work. The error messaging you see is because the Endpoint is expecting JSON.

Dan Holevoet
  • 9,183
  • 1
  • 33
  • 49
3

I had the exact same problem. It appears it's an issue with Endpoints and the fact that JSON is being POSTed.

In the end I just stepped outside the Endpoints framework and had a custom servlet handle the POST.

Everything else so far is still inside the Endpoints.