Allow clients to upload skps to skiaserve
authorjoshualitt <joshualitt@chromium.org>
Wed, 27 Jan 2016 15:03:29 +0000 (07:03 -0800)
committerCommit bot <commit-bot@chromium.org>
Wed, 27 Jan 2016 15:03:29 +0000 (07:03 -0800)
BUG=skia:
GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1638883002

Review URL: https://codereview.chromium.org/1638883002

tools/skiaserve/skiaserve.cpp

index effd289..9252da8 100644 (file)
@@ -9,20 +9,11 @@
 #include "GrContextFactory.h"
 #include "SkCanvas.h"
 #include "SkCommandLineFlags.h"
-#include "SkOSFile.h"
-#include <SkPicture.h>
+#include "SkPicture.h"
 #include "SkStream.h"
 #include "SkSurface.h"
 
-// temporary junk
-#include "SkGradientShader.h"
-
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/select.h>
-#include <sys/stat.h>
 #include <sys/socket.h>
-#include <fcntl.h>
 #include <microhttpd.h>
 
 // To get image decoders linked in we have to do the below magic
@@ -42,7 +33,7 @@ static const int kImageWidth = 1920;
 static const int kImageHeight = 1080;
 
 // TODO factor this out into functions, also handle CPU path
-SkData* setupAndDrawToCanvas(const char* path, SkString* error) {
+SkData* setupAndDrawToCanvas(SkStream* stream, SkString* error) {
     GrContextOptions grContextOpts;
     SkAutoTDelete<GrContextFactory> factory(new GrContextFactory(grContextOpts));
 
@@ -64,15 +55,9 @@ SkData* setupAndDrawToCanvas(const char* path, SkString* error) {
     gl->makeCurrent();
 
     // draw
-    SkAutoTDelete<SkStream> stream(SkStream::NewFromFile(path));
-    if (stream.get() == nullptr) {
-        error->appendf("Could not read %s.\n", path);
-        return nullptr;
-    }
-
-    SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream.get()));
+    SkAutoTUnref<SkPicture> pic(SkPicture::CreateFromStream(stream));
     if (pic.get() == nullptr) {
-        error->appendf("Could not read %s as an SkPicture.\n", path);
+        error->appendf("Could not create picture from stream.\n");
         return nullptr;
     }
 
@@ -95,7 +80,6 @@ SkData* setupAndDrawToCanvas(const char* path, SkString* error) {
     }
     return data;
 }
-
 // TODO move to template file
 SkString generateTemplate(SkString source) {
     SkString debuggerTemplate;
@@ -119,53 +103,127 @@ SkString generateTemplate(SkString source) {
 
 }
 
+struct UploadContext {
+    SkDynamicMemoryWStream stream;
+    MHD_PostProcessor* pp;
+    MHD_Connection* connection;
+};
+
+struct Request {
+    Request() : fUploadContext(nullptr) {}
+    UploadContext* fUploadContext;
+    SkAutoTUnref<SkData> fPNG;
+};
+
+static const size_t kBufferSize = 1024;
+
+static int process_upload_data(void* cls, enum MHD_ValueKind kind,
+                               const char* key, const char* filename,
+                               const char* content_type, const char* transfer_encoding,
+                               const char* data, uint64_t off, size_t size) {
+    struct UploadContext* uc = reinterpret_cast<UploadContext*>(cls);
+
+    if (0 != size) {
+        uc->stream.write(data, size);
+    }
+    return MHD_YES;
+}
+
 int answer_to_connection(void* cls, struct MHD_Connection* connection,
                          const char* url, const char* method, const char* version,
                          const char* upload_data, size_t* upload_data_size,
                          void** con_cls) {
-    printf ("New %s request for %s using version %s\n", method, url, version);
-
-    struct MHD_Response* response;
-
-    // serve html to root
-    // TODO better url handling
-    int ret;
-    if (0 == strcmp("/", url)) {
+    SkDebugf("New %s request for %s using version %s\n", method, url, version);
+
+    Request* request = reinterpret_cast<Request*>(cls);
+
+    MHD_Response* response;
+    int ret = MHD_NO;
+
+    // TODO url handlers
+    // handle uploads
+    if (0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
+        0 == strcmp(url, "/new")) {
+        UploadContext* uc =  request->fUploadContext;
+
+        // New connection
+        if (!uc) {
+            // TODO make this a method on request
+            uc = new UploadContext;
+            uc->connection = connection;
+            uc->pp = MHD_create_post_processor(connection, kBufferSize, &process_upload_data, uc);
+            SkASSERT(uc->pp);
+
+            request->fUploadContext = uc;
+            return MHD_YES;
+        }
+
+        // in process upload
+        if (0 != *upload_data_size) {
+            SkASSERT(uc->pp);
+            MHD_post_process(uc->pp, upload_data, *upload_data_size);
+            *upload_data_size = 0;
+            return MHD_YES;
+        }
+
+        // end of upload
+        MHD_destroy_post_processor(uc->pp);
+        uc->pp = nullptr;
+
+        // TODO response
+        SkString error;
+        SkData* data = setupAndDrawToCanvas(uc->stream.detachAsStream(), &error);
+        if (!data) {
+            // TODO send error
+            return MHD_YES;
+        }
+
+        request->fPNG.reset(data);
+        // TODO Hack
         SkString debuggerTemplate = generateTemplate(SkString("http://debugger.skia.org"));
 
         response = MHD_create_response_from_buffer(debuggerTemplate.size(),
-                                                   (void*)const_cast<char*>(debuggerTemplate.c_str()),
+                                                   (void*) const_cast<char*>(debuggerTemplate.c_str()),
                                                    MHD_RESPMEM_MUST_COPY);
+
         ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
         MHD_destroy_response(response);
-        return MHD_YES;
-    }
-
-    // otherwise serve an image
-    // TODO take from post
-    SkString resourceName;
-    resourceName.appendf("%s/%s.skp", FLAGS_dir[0], FLAGS_name[0]);
-    SkDebugf("Loading skp: %s\n", resourceName.c_str());
-
-    SkString error;
-    SkAutoTUnref<SkData> data(setupAndDrawToCanvas(resourceName.c_str(), &error));
-    if (!data) {
-        // TODO send error
-        return MHD_YES;
+    } else if (0 == strcmp(method, MHD_HTTP_METHOD_GET)) {
+        if (0 == strcmp(url, "/")) {
+            SkString debuggerTemplate = generateTemplate(SkString("http://debugger.skia.org"));
+
+            response = MHD_create_response_from_buffer(debuggerTemplate.size(),
+                                                       (void*) const_cast<char*>(debuggerTemplate.c_str()),
+                                                       MHD_RESPMEM_MUST_COPY);
+
+            ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+            MHD_destroy_response(response);
+        } else if (0 == strcmp(url, "/img")) {
+            if (request->fPNG.get()) {
+                SkData* data = request->fPNG.get();
+                response = MHD_create_response_from_buffer(data->size(),
+                                                           const_cast<void*>(data->data()),
+                                                           MHD_RESPMEM_MUST_COPY);
+                MHD_add_response_header(response, "Content-Type", "image/png");
+
+                ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
+                MHD_destroy_response(response);
+            }
+        }
+    } else {
+        SkFAIL("whoops, need proper error handling");
+        return MHD_NO;
     }
 
-    response = MHD_create_response_from_buffer(data->size(), const_cast<void*>(data->data()),
-                                               MHD_RESPMEM_MUST_COPY);
-    MHD_add_response_header(response, "Content-Type", "image/png");
-    ret = MHD_queue_response(connection, MHD_HTTP_OK, response);
-    MHD_destroy_response(response);
     return ret;
 }
 
 int skiaserve_main() {
+    Request request; // This simple server has one request
     struct MHD_Daemon* daemon;
-    daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, NULL, NULL,
-                              &answer_to_connection, NULL, MHD_OPTION_END);
+    daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, PORT, nullptr, nullptr,
+                              &answer_to_connection, &request,
+                              MHD_OPTION_END);
     if (NULL == daemon) {
         return 1;
     }