1 /*
2  *  Copyright (C) 2005-2018 Team Kodi
3  *  This file is part of Kodi - https://kodi.tv
4  *
5  *  SPDX-License-Identifier: GPL-2.0-or-later
6  *  See LICENSES/README.md for more information.
7  */
8 
9 #pragma once
10 
11 #include "network/httprequesthandler/IHTTPRequestHandler.h"
12 #include "threads/CriticalSection.h"
13 #include "utils/logtypes.h"
14 
15 #include <memory>
16 #include <vector>
17 
18 namespace XFILE
19 {
20   class CFile;
21 }
22 class CDateTime;
23 class CVariant;
24 
25 class CWebServer
26 {
27 public:
28   CWebServer();
29   virtual ~CWebServer() = default;
30 
31   bool Start(uint16_t port, const std::string &username, const std::string &password);
32   bool Stop();
33   bool IsStarted();
34   static bool WebServerSupportsSSL();
35   void SetCredentials(const std::string &username, const std::string &password);
36 
37   void RegisterRequestHandler(IHTTPRequestHandler *handler);
38   void UnregisterRequestHandler(IHTTPRequestHandler *handler);
39 
40 protected:
41   typedef struct ConnectionHandler
42   {
43     std::string fullUri;
44     bool isNew;
45     std::shared_ptr<IHTTPRequestHandler> requestHandler;
46     struct MHD_PostProcessor *postprocessor;
47     int errorStatus;
48 
ConnectionHandlerConnectionHandler49     explicit ConnectionHandler(const std::string& uri)
50       : fullUri(uri)
51       , isNew(true)
52       , requestHandler(nullptr)
53       , postprocessor(nullptr)
54       , errorStatus(MHD_HTTP_OK)
55     { }
56   } ConnectionHandler;
57 
58   virtual void LogRequest(const char* uri) const;
59 
60   virtual MHD_RESULT HandlePartialRequest(struct MHD_Connection *connection, ConnectionHandler* connectionHandler, const HTTPRequest& request,
61                                    const char *upload_data, size_t *upload_data_size, void **con_cls);
62   virtual MHD_RESULT HandleRequest(const std::shared_ptr<IHTTPRequestHandler>& handler);
63   virtual MHD_RESULT FinalizeRequest(const std::shared_ptr<IHTTPRequestHandler>& handler, int responseStatus, struct MHD_Response *response);
64 
65 private:
66   struct MHD_Daemon* StartMHD(unsigned int flags, int port);
67 
68   std::shared_ptr<IHTTPRequestHandler> FindRequestHandler(const HTTPRequest& request) const;
69 
70   MHD_RESULT AskForAuthentication(const HTTPRequest& request) const;
71   bool IsAuthenticated(const HTTPRequest& request) const;
72 
73   bool IsRequestCacheable(const HTTPRequest& request) const;
74   bool IsRequestRanged(const HTTPRequest& request, const CDateTime &lastModified) const;
75 
76   void SetupPostDataProcessing(const HTTPRequest& request, ConnectionHandler *connectionHandler, std::shared_ptr<IHTTPRequestHandler> handler, void **con_cls) const;
77   bool ProcessPostData(const HTTPRequest& request, ConnectionHandler *connectionHandler, const char *upload_data, size_t *upload_data_size, void **con_cls) const;
78   void FinalizePostDataProcessing(ConnectionHandler *connectionHandler) const;
79 
80   MHD_RESULT CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const;
81   MHD_RESULT CreateRangedMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const;
82 
83   MHD_RESULT CreateRedirect(struct MHD_Connection *connection, const std::string &strURL, struct MHD_Response *&response) const;
84   MHD_RESULT CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const;
85   MHD_RESULT CreateErrorResponse(struct MHD_Connection *connection, int responseType, HTTPMethod method, struct MHD_Response *&response) const;
86   MHD_RESULT CreateMemoryDownloadResponse(struct MHD_Connection *connection, const void *data, size_t size, bool free, bool copy, struct MHD_Response *&response) const;
87 
88   MHD_RESULT SendResponse(const HTTPRequest& request, int responseStatus, MHD_Response *response) const;
89   MHD_RESULT SendErrorResponse(const HTTPRequest& request, int errorType, HTTPMethod method) const;
90 
91   MHD_RESULT AddHeader(struct MHD_Response *response, const std::string &name, const std::string &value) const;
92 
93   void LogRequest(const HTTPRequest& request) const;
94   void LogResponse(const HTTPRequest& request, int responseStatus) const;
95 
96   static std::string CreateMimeTypeFromExtension(const char *ext);
97 
98   // MHD callback implementations
99   static void* UriRequestLogger(void *cls, const char *uri);
100 
101   static ssize_t ContentReaderCallback (void *cls, uint64_t pos, char *buf, size_t max);
102   static void ContentReaderFreeCallback(void *cls);
103 
104   static MHD_RESULT AnswerToConnection (void *cls, struct MHD_Connection *connection,
105                         const char *url, const char *method,
106                         const char *version, const char *upload_data,
107                         size_t *upload_data_size, void **con_cls);
108   static MHD_RESULT HandlePostField(void *cls, enum MHD_ValueKind kind, const char *key,
109                              const char *filename, const char *content_type,
110                              const char *transfer_encoding, const char *data, uint64_t off,
111                              size_t size);
112 
113   bool LoadCert(std::string &skey, std::string &scert);
114 
115   static Logger GetLogger();
116 
117   uint16_t m_port = 0;
118   struct MHD_Daemon *m_daemon_ip6 = nullptr;
119   struct MHD_Daemon *m_daemon_ip4 = nullptr;
120   bool m_running = false;
121   size_t m_thread_stacksize = 0;
122   bool m_authenticationRequired = false;
123   std::string m_authenticationUsername;
124   std::string m_authenticationPassword;
125   std::string m_key;
126   std::string m_cert;
127   mutable CCriticalSection m_critSection;
128   std::vector<IHTTPRequestHandler *> m_requestHandlers;
129 
130   Logger m_logger;
131 };
132