1 /*
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"
10
11 #include "Request.h"
12 #include "Response.h"
13
14 #include "SkCommandLineFlags.h"
15
16 #include "microhttpd.h"
17
18 #include "urlhandlers/UrlHandler.h"
19 #include <sys/socket.h>
20
21 using namespace Response;
22
23 // To get image decoders linked in we have to do the below magic
24 #include "SkForceLinking.h"
25 #include "SkImageDecoder.h"
26 __SK_FORCE_IMAGE_DECODER_LINKING;
27
28 DEFINE_int32(port, 8888, "The port to listen on.");
29
30 class UrlManager {
31 public:
UrlManager()32 UrlManager() {
33 // Register handlers
34 fHandlers.push_back(new RootHandler);
35 fHandlers.push_back(new PostHandler);
36 fHandlers.push_back(new ImgHandler);
37 fHandlers.push_back(new ClipAlphaHandler);
38 fHandlers.push_back(new EnableGPUHandler);
39 fHandlers.push_back(new CmdHandler);
40 fHandlers.push_back(new InfoHandler);
41 fHandlers.push_back(new DownloadHandler);
42 fHandlers.push_back(new DataHandler);
43 fHandlers.push_back(new BreakHandler);
44 }
45
~UrlManager()46 ~UrlManager() {
47 for (int i = 0; i < fHandlers.count(); i++) { delete fHandlers[i]; }
48 }
49
50 // This is clearly not efficient for a large number of urls and handlers
invoke(Request * request,MHD_Connection * connection,const char * url,const char * method,const char * upload_data,size_t * upload_data_size) const51 int invoke(Request* request, MHD_Connection* connection, const char* url, const char* method,
52 const char* upload_data, size_t* upload_data_size) const {
53 for (int i = 0; i < fHandlers.count(); i++) {
54 if (fHandlers[i]->canHandle(method, url)) {
55 return fHandlers[i]->handle(request, connection, url, method, upload_data,
56 upload_data_size);
57 }
58 }
59 return MHD_NO;
60 }
61
62 private:
63 SkTArray<UrlHandler*> fHandlers;
64 };
65
66 const UrlManager kUrlManager;
67
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)68 int answer_to_connection(void* cls, struct MHD_Connection* connection,
69 const char* url, const char* method, const char* version,
70 const char* upload_data, size_t* upload_data_size,
71 void** con_cls) {
72 SkDebugf("New %s request for %s using version %s\n", method, url, version);
73
74 Request* request = reinterpret_cast<Request*>(cls);
75 int result = kUrlManager.invoke(request, connection, url, method, upload_data,
76 upload_data_size);
77 if (MHD_NO == result) {
78 fprintf(stderr, "Invalid method and / or url: %s %s\n", method, url);
79 }
80 return result;
81 }
82
skiaserve_main()83 int skiaserve_main() {
84 Request request(SkString("/data")); // This simple server has one request
85
86 // create surface
87 GrContextOptions grContextOpts;
88 request.fContextFactory.reset(new GrContextFactory(grContextOpts));
89 request.fSurface.reset(request.createCPUSurface());
90
91 struct MHD_Daemon* daemon;
92 // TODO Add option to bind this strictly to an address, e.g. localhost, for security.
93 daemon = MHD_start_daemon(MHD_USE_SELECT_INTERNALLY, FLAGS_port, nullptr, nullptr,
94 &answer_to_connection, &request,
95 MHD_OPTION_END);
96 if (NULL == daemon) {
97 return 1;
98 }
99
100 getchar();
101 MHD_stop_daemon(daemon);
102 return 0;
103 }
104
105 #if !defined SK_BUILD_FOR_IOS
main(int argc,char ** argv)106 int main(int argc, char** argv) {
107 SkCommandLineFlags::Parse(argc, argv);
108 return skiaserve_main();
109 }
110 #endif
111