blob: d5a0132d0d189833ed8d48c927c1ba4f56330471 [file] [log] [blame]
joshualitt7f6a1e02016-01-22 11:21:43 -08001/*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "GrCaps.h"
9#include "GrContextFactory.h"
joshualitt24dd6872016-02-25 08:37:54 -080010
11#include "Request.h"
joshualitt26cc3f52016-02-25 11:09:36 -080012#include "Response.h"
joshualitt24dd6872016-02-25 08:37:54 -080013
joshualitt7f6a1e02016-01-22 11:21:43 -080014#include "SkCanvas.h"
15#include "SkCommandLineFlags.h"
joshualitt609d9792016-01-27 11:07:23 -080016#include "SkJSONCanvas.h"
joshualitt792345f2016-02-02 13:02:33 -080017#include "SkPictureRecorder.h"
18#include "SkPixelSerializer.h"
joshualittcdad12f2016-02-08 07:08:21 -080019
joshualitt7f6a1e02016-01-22 11:21:43 -080020#include <sys/socket.h>
joshualitt7f6a1e02016-01-22 11:21:43 -080021#include <microhttpd.h>
22
joshualitt26cc3f52016-02-25 11:09:36 -080023using namespace Response;
24
joshualitt7f6a1e02016-01-22 11:21:43 -080025// To get image decoders linked in we have to do the below magic
26#include "SkForceLinking.h"
27#include "SkImageDecoder.h"
28__SK_FORCE_IMAGE_DECODER_LINKING;
29
jcgregorio21ab1202016-01-28 06:24:19 -080030DEFINE_int32(port, 8888, "The port to listen on.");
joshualitt7f6a1e02016-01-22 11:21:43 -080031
joshualitt9a4e1882016-01-27 07:03:29 -080032static const size_t kBufferSize = 1024;
33
34static int process_upload_data(void* cls, enum MHD_ValueKind kind,
35 const char* key, const char* filename,
36 const char* content_type, const char* transfer_encoding,
37 const char* data, uint64_t off, size_t size) {
38 struct UploadContext* uc = reinterpret_cast<UploadContext*>(cls);
39
40 if (0 != size) {
joshualitt609d9792016-01-27 11:07:23 -080041 uc->fStream.write(data, size);
joshualitt9a4e1882016-01-27 07:03:29 -080042 }
43 return MHD_YES;
44}
45
joshualitt483b9012016-02-02 07:16:24 -080046class UrlHandler {
47public:
48 virtual ~UrlHandler() {}
49 virtual bool canHandle(const char* method, const char* url) = 0;
50 virtual int handle(Request* request, MHD_Connection* connection,
joshualitt136f5172016-02-02 11:07:39 -080051 const char* url, const char* method,
joshualitt483b9012016-02-02 07:16:24 -080052 const char* upload_data, size_t* upload_data_size) = 0;
53};
joshualittccfdaa52016-01-27 07:40:29 -080054
joshualitt29e5a892016-02-04 06:08:33 -080055class CmdHandler : public UrlHandler {
joshualitt483b9012016-02-02 07:16:24 -080056public:
57 bool canHandle(const char* method, const char* url) override {
joshualitt136f5172016-02-02 11:07:39 -080058 const char* kBasePath = "/cmd";
59 return 0 == strncmp(url, kBasePath, strlen(kBasePath));
joshualittccfdaa52016-01-27 07:40:29 -080060 }
61
joshualitt483b9012016-02-02 07:16:24 -080062 int handle(Request* request, MHD_Connection* connection,
joshualitt136f5172016-02-02 11:07:39 -080063 const char* url, const char* method,
joshualitt483b9012016-02-02 07:16:24 -080064 const char* upload_data, size_t* upload_data_size) override {
joshualitt136f5172016-02-02 11:07:39 -080065 SkTArray<SkString> commands;
66 SkStrSplit(url, "/", &commands);
67
68 if (!request->fPicture.get() || commands.count() > 3) {
69 return MHD_NO;
joshualitt483b9012016-02-02 07:16:24 -080070 }
joshualitt136f5172016-02-02 11:07:39 -080071
joshualittdb6a2542016-02-11 07:09:51 -080072 // /cmd or /cmd/N
73 if (0 == strcmp(method, MHD_HTTP_METHOD_GET)) {
74 int n;
75 if (commands.count() == 1) {
ethannicholas0a0520a2016-02-12 12:06:53 -080076 n = request->fDebugCanvas->getSize() - 1;
joshualittdb6a2542016-02-11 07:09:51 -080077 } else {
78 sscanf(commands[1].c_str(), "%d", &n);
79 }
ethannicholas3ff5d8c2016-02-22 08:59:57 -080080 return SendJSON(connection, request, n);
joshualitt136f5172016-02-02 11:07:39 -080081 }
82
83 // /cmd/N, for now only delete supported
84 if (commands.count() == 2 && 0 == strcmp(method, MHD_HTTP_METHOD_DELETE)) {
85 int n;
86 sscanf(commands[1].c_str(), "%d", &n);
87 request->fDebugCanvas->deleteDrawCommandAt(n);
jcgregorio12d47ce2016-02-10 14:10:37 -080088 return SendOK(connection);
joshualitt136f5172016-02-02 11:07:39 -080089 }
90
91 // /cmd/N/[0|1]
92 if (commands.count() == 3 && 0 == strcmp(method, MHD_HTTP_METHOD_POST)) {
93 int n, toggle;
94 sscanf(commands[1].c_str(), "%d", &n);
95 sscanf(commands[2].c_str(), "%d", &toggle);
96 request->fDebugCanvas->toggleCommand(n, toggle);
jcgregorio12d47ce2016-02-10 14:10:37 -080097 return SendOK(connection);
joshualitt136f5172016-02-02 11:07:39 -080098 }
99
joshualitt483b9012016-02-02 07:16:24 -0800100 return MHD_NO;
101 }
102};
103
104class ImgHandler : public UrlHandler {
105public:
106 bool canHandle(const char* method, const char* url) override {
107 static const char* kBasePath = "/img";
108 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
109 0 == strncmp(url, kBasePath, strlen(kBasePath));
joshualittccfdaa52016-01-27 07:40:29 -0800110 }
111
joshualitt483b9012016-02-02 07:16:24 -0800112 int handle(Request* request, MHD_Connection* connection,
joshualitt136f5172016-02-02 11:07:39 -0800113 const char* url, const char* method,
joshualitt483b9012016-02-02 07:16:24 -0800114 const char* upload_data, size_t* upload_data_size) override {
joshualitt136f5172016-02-02 11:07:39 -0800115 SkTArray<SkString> commands;
116 SkStrSplit(url, "/", &commands);
117
118 if (!request->fPicture.get() || commands.count() > 2) {
119 return MHD_NO;
joshualitt483b9012016-02-02 07:16:24 -0800120 }
joshualitta341b902016-02-02 07:37:21 -0800121
joshualitt136f5172016-02-02 11:07:39 -0800122 int n;
123 // /img or /img/N
124 if (commands.count() == 1) {
125 n = request->fDebugCanvas->getSize() - 1;
126 } else {
127 sscanf(commands[1].c_str(), "%d", &n);
128 }
129
joshualitt4dcbe432016-02-25 10:50:28 -0800130 SkAutoTUnref<SkData> data(request->drawToPng(n));
joshualitt136f5172016-02-02 11:07:39 -0800131 return SendData(connection, data, "image/png");
joshualitt483b9012016-02-02 07:16:24 -0800132 }
133};
joshualittccfdaa52016-01-27 07:40:29 -0800134
ethannicholas3ca1e1a2016-02-18 10:22:34 -0800135class BreakHandler : public UrlHandler {
136public:
137 bool canHandle(const char* method, const char* url) override {
138 static const char* kBasePath = "/break";
139 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
140 0 == strncmp(url, kBasePath, strlen(kBasePath));
141 }
142
143 static SkColor GetPixel(Request* request, int x, int y) {
joshualitt4dcbe432016-02-25 10:50:28 -0800144 SkCanvas* canvas = request->getCanvas();
ethannicholas3ca1e1a2016-02-18 10:22:34 -0800145 canvas->flush();
joshualitt4dcbe432016-02-25 10:50:28 -0800146 SkAutoTDelete<SkBitmap> bitmap(request->getBitmapFromCanvas(canvas));
ethannicholas3ca1e1a2016-02-18 10:22:34 -0800147 SkASSERT(bitmap);
148 bitmap->lockPixels();
joshualitt4dcbe432016-02-25 10:50:28 -0800149 uint8_t* start = ((uint8_t*) bitmap->getPixels()) + (y * Request::kImageWidth + x) * 4;
ethannicholas3ca1e1a2016-02-18 10:22:34 -0800150 SkColor result = SkColorSetARGB(start[3], start[0], start[1], start[2]);
151 bitmap->unlockPixels();
152 return result;
153 }
154
155 int handle(Request* request, MHD_Connection* connection,
156 const char* url, const char* method,
157 const char* upload_data, size_t* upload_data_size) override {
158 SkTArray<SkString> commands;
159 SkStrSplit(url, "/", &commands);
160
161 if (!request->fPicture.get() || commands.count() != 4) {
162 return MHD_NO;
163 }
164
165 // /break/<n>/<x>/<y>
166 int n;
167 sscanf(commands[1].c_str(), "%d", &n);
168 int x;
169 sscanf(commands[2].c_str(), "%d", &x);
170 int y;
171 sscanf(commands[3].c_str(), "%d", &y);
172
173 int count = request->fDebugCanvas->getSize();
174 SkASSERT(n < count);
175
joshualitt4dcbe432016-02-25 10:50:28 -0800176 SkCanvas* canvas = request->getCanvas();
ethannicholas3ca1e1a2016-02-18 10:22:34 -0800177 canvas->clear(SK_ColorWHITE);
178 int saveCount = canvas->save();
179 for (int i = 0; i <= n; ++i) {
180 request->fDebugCanvas->getDrawCommandAt(i)->execute(canvas);
181 }
182 SkColor target = GetPixel(request, x, y);
183 Json::Value response(Json::objectValue);
184 Json::Value startColor(Json::arrayValue);
185 startColor.append(Json::Value(SkColorGetR(target)));
186 startColor.append(Json::Value(SkColorGetG(target)));
187 startColor.append(Json::Value(SkColorGetB(target)));
188 startColor.append(Json::Value(SkColorGetA(target)));
189 response["startColor"] = startColor;
190 response["endColor"] = startColor;
191 response["endOp"] = Json::Value(n);
192 for (int i = n + 1; i < n + count; ++i) {
193 int index = i % count;
194 if (index == 0) {
195 // reset canvas for wraparound
196 canvas->restoreToCount(saveCount);
197 canvas->clear(SK_ColorWHITE);
198 saveCount = canvas->save();
199 }
200 request->fDebugCanvas->getDrawCommandAt(index)->execute(canvas);
201 SkColor current = GetPixel(request, x, y);
202 if (current != target) {
203 Json::Value endColor(Json::arrayValue);
204 endColor.append(Json::Value(SkColorGetR(current)));
205 endColor.append(Json::Value(SkColorGetG(current)));
206 endColor.append(Json::Value(SkColorGetB(current)));
207 endColor.append(Json::Value(SkColorGetA(current)));
208 response["endColor"] = endColor;
209 response["endOp"] = Json::Value(index);
210 break;
211 }
212 }
213 canvas->restoreToCount(saveCount);
214 SkDynamicMemoryWStream stream;
215 stream.writeText(Json::FastWriter().write(response).c_str());
216 SkAutoTUnref<SkData> data(stream.copyToData());
217 return SendData(connection, data, "application/json");
218 }
219};
220
ethannicholas0a0520a2016-02-12 12:06:53 -0800221/**
222 Updates the clip visualization alpha. On all subsequent /img requests, the clip will be drawn in
223 black with the specified alpha. 0 = no visible clip, 255 = fully opaque clip.
224 */
225class ClipAlphaHandler : public UrlHandler {
226public:
227 bool canHandle(const char* method, const char* url) override {
228 static const char* kBasePath = "/clipAlpha/";
jcgregorio3341d422016-02-16 10:31:07 -0800229 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
ethannicholas0a0520a2016-02-12 12:06:53 -0800230 0 == strncmp(url, kBasePath, strlen(kBasePath));
231 }
232
233 int handle(Request* request, MHD_Connection* connection,
234 const char* url, const char* method,
235 const char* upload_data, size_t* upload_data_size) override {
236 SkTArray<SkString> commands;
237 SkStrSplit(url, "/", &commands);
238
239 if (!request->fPicture.get() || commands.count() != 2) {
240 return MHD_NO;
241 }
242
243 int alpha;
244 sscanf(commands[1].c_str(), "%d", &alpha);
245
246 request->fDebugCanvas->setClipVizColor(SkColorSetARGB(alpha, 0, 0, 0));
247 return SendOK(connection);
248 }
249};
250
ethannicholas85fca852016-02-19 08:40:59 -0800251/**
252 Controls whether GPU rendering is enabled. Posting to /enableGPU/1 turns GPU on, /enableGPU/0
253 disables it.
254 */
255class EnableGPUHandler : public UrlHandler {
256public:
257 bool canHandle(const char* method, const char* url) override {
258 static const char* kBasePath = "/enableGPU/";
259 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
260 0 == strncmp(url, kBasePath, strlen(kBasePath));
261 }
262
263 int handle(Request* request, MHD_Connection* connection,
264 const char* url, const char* method,
265 const char* upload_data, size_t* upload_data_size) override {
266 SkTArray<SkString> commands;
267 SkStrSplit(url, "/", &commands);
268
269 if (commands.count() != 2) {
270 return MHD_NO;
271 }
272
273 int enable;
274 sscanf(commands[1].c_str(), "%d", &enable);
275
276 if (enable) {
joshualitt4dcbe432016-02-25 10:50:28 -0800277 SkSurface* surface = request->createGPUSurface();
ethannicholas85fca852016-02-19 08:40:59 -0800278 if (surface) {
279 request->fSurface.reset(surface);
ethannicholas3ff5d8c2016-02-22 08:59:57 -0800280 request->fGPUEnabled = true;
ethannicholas85fca852016-02-19 08:40:59 -0800281 return SendOK(connection);
282 }
283 return SendError(connection, "Unable to create GPU surface");
284 }
joshualitt4dcbe432016-02-25 10:50:28 -0800285 request->fSurface.reset(request->createCPUSurface());
ethannicholas3ff5d8c2016-02-22 08:59:57 -0800286 request->fGPUEnabled = false;
ethannicholas85fca852016-02-19 08:40:59 -0800287 return SendOK(connection);
288 }
289};
290
joshualitt483b9012016-02-02 07:16:24 -0800291class PostHandler : public UrlHandler {
292public:
293 bool canHandle(const char* method, const char* url) override {
294 return 0 == strcmp(method, MHD_HTTP_METHOD_POST) &&
295 0 == strcmp(url, "/new");
joshualittccfdaa52016-01-27 07:40:29 -0800296 }
297
joshualitt483b9012016-02-02 07:16:24 -0800298 int handle(Request* request, MHD_Connection* connection,
joshualitt136f5172016-02-02 11:07:39 -0800299 const char* url, const char* method,
joshualitt483b9012016-02-02 07:16:24 -0800300 const char* upload_data, size_t* upload_data_size) override {
301 UploadContext* uc = request->fUploadContext;
joshualittccfdaa52016-01-27 07:40:29 -0800302
joshualitt483b9012016-02-02 07:16:24 -0800303 // New connection
304 if (!uc) {
305 // TODO make this a method on request
306 uc = new UploadContext;
307 uc->connection = connection;
308 uc->fPostProcessor = MHD_create_post_processor(connection, kBufferSize,
309 &process_upload_data, uc);
310 SkASSERT(uc->fPostProcessor);
joshualitt609d9792016-01-27 11:07:23 -0800311
joshualitt483b9012016-02-02 07:16:24 -0800312 request->fUploadContext = uc;
313 return MHD_YES;
314 }
315
316 // in process upload
317 if (0 != *upload_data_size) {
318 SkASSERT(uc->fPostProcessor);
319 MHD_post_process(uc->fPostProcessor, upload_data, *upload_data_size);
320 *upload_data_size = 0;
321 return MHD_YES;
322 }
323
324 // end of upload
325 MHD_destroy_post_processor(uc->fPostProcessor);
326 uc->fPostProcessor = nullptr;
327
joshualitt136f5172016-02-02 11:07:39 -0800328 // parse picture from stream
329 request->fPicture.reset(
330 SkPicture::CreateFromStream(request->fUploadContext->fStream.detachAsStream()));
331 if (!request->fPicture.get()) {
332 fprintf(stderr, "Could not create picture from stream.\n");
333 return MHD_NO;
joshualitt483b9012016-02-02 07:16:24 -0800334 }
335
joshualitt136f5172016-02-02 11:07:39 -0800336 // pour picture into debug canvas
joshualitt4dcbe432016-02-25 10:50:28 -0800337 request->fDebugCanvas.reset(new SkDebugCanvas(Request::kImageWidth,
338 Request::kImageHeight));
joshualitt136f5172016-02-02 11:07:39 -0800339 request->fDebugCanvas->drawPicture(request->fPicture);
340
joshualitta341b902016-02-02 07:37:21 -0800341 // clear upload context
342 delete request->fUploadContext;
343 request->fUploadContext = nullptr;
344
joshualitt483b9012016-02-02 07:16:24 -0800345 return SendTemplate(connection, true, "/");
joshualittccfdaa52016-01-27 07:40:29 -0800346 }
joshualitt483b9012016-02-02 07:16:24 -0800347};
348
joshualitt792345f2016-02-02 13:02:33 -0800349class DownloadHandler : public UrlHandler {
350public:
351 bool canHandle(const char* method, const char* url) override {
352 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
353 0 == strcmp(url, "/download");
354 }
355
356 int handle(Request* request, MHD_Connection* connection,
357 const char* url, const char* method,
358 const char* upload_data, size_t* upload_data_size) override {
359 if (!request->fPicture.get()) {
360 return MHD_NO;
361 }
362
363 // TODO move to a function
364 // Playback into picture recorder
365 SkPictureRecorder recorder;
joshualitt4dcbe432016-02-25 10:50:28 -0800366 SkCanvas* canvas = recorder.beginRecording(Request::kImageWidth,
367 Request::kImageHeight);
joshualitt792345f2016-02-02 13:02:33 -0800368
369 request->fDebugCanvas->draw(canvas);
370
371 SkAutoTUnref<SkPicture> picture(recorder.endRecording());
372
373 SkDynamicMemoryWStream outStream;
374
375 SkAutoTUnref<SkPixelSerializer> serializer(SkImageEncoder::CreatePixelSerializer());
376 picture->serialize(&outStream, serializer);
377
378 SkAutoTUnref<SkData> data(outStream.copyToData());
379
380 // TODO fancier name handling
381 return SendData(connection, data, "application/octet-stream", true,
382 "attachment; filename=something.skp;");
383 }
384};
385
joshualitt29e5a892016-02-04 06:08:33 -0800386class InfoHandler : public UrlHandler {
387public:
388 bool canHandle(const char* method, const char* url) override {
389 const char* kBaseName = "/info";
390 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
391 0 == strncmp(url, kBaseName, strlen(kBaseName));
392 }
393
394 int handle(Request* request, MHD_Connection* connection,
395 const char* url, const char* method,
396 const char* upload_data, size_t* upload_data_size) override {
397 SkTArray<SkString> commands;
398 SkStrSplit(url, "/", &commands);
399
400 if (!request->fPicture.get() || commands.count() > 2) {
401 return MHD_NO;
402 }
403
404 // drawTo
joshualitt4dcbe432016-02-25 10:50:28 -0800405 SkAutoTUnref<SkSurface> surface(request->createCPUSurface());
joshualitt29e5a892016-02-04 06:08:33 -0800406 SkCanvas* canvas = surface->getCanvas();
407
408 int n;
409 // /info or /info/N
410 if (commands.count() == 1) {
411 n = request->fDebugCanvas->getSize() - 1;
412 } else {
413 sscanf(commands[1].c_str(), "%d", &n);
414 }
415
416 // TODO this is really slow and we should cache the matrix and clip
417 request->fDebugCanvas->drawTo(canvas, n);
418
419 // make some json
420 SkMatrix vm = request->fDebugCanvas->getCurrentMatrix();
421 SkIRect clip = request->fDebugCanvas->getCurrentClip();
422 Json::Value info(Json::objectValue);
423 info["ViewMatrix"] = SkJSONCanvas::MakeMatrix(vm);
424 info["ClipRect"] = SkJSONCanvas::MakeIRect(clip);
425
426 std::string json = Json::FastWriter().write(info);
427
428 // We don't want the null terminator so strlen is correct
429 SkAutoTUnref<SkData> data(SkData::NewWithCopy(json.c_str(), strlen(json.c_str())));
430 return SendData(connection, data, "application/json");
431 }
432};
433
joshualittcdad12f2016-02-08 07:08:21 -0800434class DataHandler : public UrlHandler {
435public:
436 bool canHandle(const char* method, const char* url) override {
437 static const char* kBaseUrl = "/data";
438 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
439 0 == strncmp(url, kBaseUrl, strlen(kBaseUrl));
440 }
441
442 int handle(Request* request, MHD_Connection* connection,
443 const char* url, const char* method,
444 const char* upload_data, size_t* upload_data_size) override {
445 SkTArray<SkString> commands;
446 SkStrSplit(url, "/", &commands);
447
448 if (!request->fPicture.get() || commands.count() != 2) {
449 return MHD_NO;
450 }
451
452 SkAutoTUnref<UrlDataManager::UrlData> urlData(
453 SkRef(request->fUrlDataManager.getDataFromUrl(SkString(url))));
454
455 if (urlData) {
456 return SendData(connection, urlData->fData.get(), urlData->fContentType.c_str());
457 }
458 return MHD_NO;
459 }
460};
joshualitt29e5a892016-02-04 06:08:33 -0800461
joshualitt483b9012016-02-02 07:16:24 -0800462class RootHandler : public UrlHandler {
463public:
464 bool canHandle(const char* method, const char* url) override {
465 return 0 == strcmp(method, MHD_HTTP_METHOD_GET) &&
466 0 == strcmp(url, "/");
467 }
468
469 int handle(Request* request, MHD_Connection* connection,
joshualitt136f5172016-02-02 11:07:39 -0800470 const char* url, const char* method,
joshualitt483b9012016-02-02 07:16:24 -0800471 const char* upload_data, size_t* upload_data_size) override {
472 return SendTemplate(connection);
473 }
474};
joshualittccfdaa52016-01-27 07:40:29 -0800475
476class UrlManager {
477public:
478 UrlManager() {
479 // Register handlers
joshualitt483b9012016-02-02 07:16:24 -0800480 fHandlers.push_back(new RootHandler);
481 fHandlers.push_back(new PostHandler);
482 fHandlers.push_back(new ImgHandler);
ethannicholas0a0520a2016-02-12 12:06:53 -0800483 fHandlers.push_back(new ClipAlphaHandler);
ethannicholas85fca852016-02-19 08:40:59 -0800484 fHandlers.push_back(new EnableGPUHandler);
joshualitt29e5a892016-02-04 06:08:33 -0800485 fHandlers.push_back(new CmdHandler);
joshualitt483b9012016-02-02 07:16:24 -0800486 fHandlers.push_back(new InfoHandler);
joshualitt792345f2016-02-02 13:02:33 -0800487 fHandlers.push_back(new DownloadHandler);
joshualittcdad12f2016-02-08 07:08:21 -0800488 fHandlers.push_back(new DataHandler);
ethannicholas3ca1e1a2016-02-18 10:22:34 -0800489 fHandlers.push_back(new BreakHandler);
joshualitt483b9012016-02-02 07:16:24 -0800490 }
491
492 ~UrlManager() {
493 for (int i = 0; i < fHandlers.count(); i++) { delete fHandlers[i]; }
joshualittccfdaa52016-01-27 07:40:29 -0800494 }
495
496 // This is clearly not efficient for a large number of urls and handlers
497 int invoke(Request* request, MHD_Connection* connection, const char* url, const char* method,
498 const char* upload_data, size_t* upload_data_size) const {
499 for (int i = 0; i < fHandlers.count(); i++) {
joshualitt483b9012016-02-02 07:16:24 -0800500 if (fHandlers[i]->canHandle(method, url)) {
joshualitt136f5172016-02-02 11:07:39 -0800501 return fHandlers[i]->handle(request, connection, url, method, upload_data,
502 upload_data_size);
joshualittccfdaa52016-01-27 07:40:29 -0800503 }
504 }
505 return MHD_NO;
506 }
507
508private:
joshualitt483b9012016-02-02 07:16:24 -0800509 SkTArray<UrlHandler*> fHandlers;
joshualittccfdaa52016-01-27 07:40:29 -0800510};
511
512const UrlManager kUrlManager;
513
joshualitt7f6a1e02016-01-22 11:21:43 -0800514int answer_to_connection(void* cls, struct MHD_Connection* connection,
515 const char* url, const char* method, const char* version,
516 const char* upload_data, size_t* upload_data_size,
517 void** con_cls) {
joshualitt9a4e1882016-01-27 07:03:29 -0800518 SkDebugf("New %s request for %s using version %s\n", method, url, version);
joshualitt7f6a1e02016-01-22 11:21:43 -0800519
joshualitt9a4e1882016-01-27 07:03:29 -0800520 Request* request = reinterpret_cast<Request*>(cls);
joshualitt483b9012016-02-02 07:16:24 -0800521 int result = kUrlManager.invoke(request, connection, url, method, upload_data,
522 upload_data_size);
523 if (MHD_NO == result) {
joshualitt873d6242016-02-08 13:57:44 -0800524 fprintf(stderr, "Invalid method and / or url: %s %s\n", method, url);
joshualitt483b9012016-02-02 07:16:24 -0800525 }
526 return result;
joshualitt7f6a1e02016-01-22 11:21:43 -0800527}
528
529int skiaserve_main() {
joshualittcdad12f2016-02-08 07:08:21 -0800530 Request request(SkString("/data")); // This simple server has one request
ethannicholas85fca852016-02-19 08:40:59 -0800531
532 // create surface
533 GrContextOptions grContextOpts;
534 request.fContextFactory.reset(new GrContextFactory(grContextOpts));
joshualitt4dcbe432016-02-25 10:50:28 -0800535 request.fSurface.reset(request.createCPUSurface());
ethannicholas85fca852016-02-19 08:40:59 -0800536
joshualitt7f6a1e02016-01-22 11:21:43 -0800537 struct MHD_Daemon* daemon;
jcgregorio21ab1202016-01-28 06:24:19 -0800538 // TODO Add option to bind this strictly to an address, e.g. localhost, for security.
539 daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, FLAGS_port, nullptr, nullptr,
joshualitt9a4e1882016-01-27 07:03:29 -0800540 &answer_to_connection, &request,
541 MHD_OPTION_END);
joshualitt7f6a1e02016-01-22 11:21:43 -0800542 if (NULL == daemon) {
543 return 1;
544 }
545
546 getchar();
547 MHD_stop_daemon(daemon);
548 return 0;
549}
550
551#if !defined SK_BUILD_FOR_IOS
552int main(int argc, char** argv) {
553 SkCommandLineFlags::Parse(argc, argv);
554 return skiaserve_main();
555}
556#endif