aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStefan Saraev <stefansaraev@users.noreply.github.com>2016-05-17 21:07:38 +0300
committerStefan Saraev <stefansaraev@users.noreply.github.com>2016-05-17 21:07:38 +0300
commit7d1fff681ad345e9930e714dc8b3707ea299adeb (patch)
tree0b9dbce14929e94b0f50594c39e7a69e37edc556
parentd1f3e54695f13b0919887b6fc8500c962269a5f6 (diff)
parente9f18d8240b680d409dc1653db5e3fdc9e3e9eb5 (diff)
Merge pull request #9576 from Montellese/webserver_improvements
[network] improvements to the webserver implementation
-rw-r--r--Kodi.xcodeproj/project.pbxproj8
-rw-r--r--addons/resource.language.en_gb/resources/strings.po7
-rw-r--r--project/VS2010Express/XBMC.vcxproj4
-rw-r--r--project/VS2010Express/XBMC.vcxproj.filters10
-rw-r--r--xbmc/commons/ilog.h27
-rw-r--r--xbmc/network/NetworkServices.cpp28
-rw-r--r--xbmc/network/WebServer.cpp449
-rw-r--r--xbmc/network/WebServer.h89
-rw-r--r--xbmc/network/httprequesthandler/CMakeLists.txt2
-rw-r--r--xbmc/network/httprequesthandler/HTTPImageTransformationHandler.cpp5
-rw-r--r--xbmc/network/httprequesthandler/HTTPJsonRpcHandler.cpp40
-rw-r--r--xbmc/network/httprequesthandler/HTTPJsonRpcHandler.h15
-rw-r--r--xbmc/network/httprequesthandler/HTTPPythonHandler.cpp5
-rw-r--r--xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.cpp96
-rw-r--r--xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.h41
-rw-r--r--xbmc/network/httprequesthandler/IHTTPRequestHandler.cpp39
-rw-r--r--xbmc/network/httprequesthandler/IHTTPRequestHandler.h3
-rw-r--r--xbmc/network/httprequesthandler/Makefile1
-rw-r--r--xbmc/network/test/TestWebServer.cpp11
-rw-r--r--xbmc/settings/AdvancedSettings.cpp3
20 files changed, 509 insertions, 374 deletions
diff --git a/Kodi.xcodeproj/project.pbxproj b/Kodi.xcodeproj/project.pbxproj
index ce0e9a740d..e00a88798d 100644
--- a/Kodi.xcodeproj/project.pbxproj
+++ b/Kodi.xcodeproj/project.pbxproj
@@ -139,6 +139,8 @@
228FA65E1C53F9D50023BBF0 /* InfoScanner.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 228FA65C1C53F9D50023BBF0 /* InfoScanner.cpp */; };
2A7B2BDC1BD6F16600044BCD /* PVRSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7B2BDB1BD6F16600044BCD /* PVRSettings.cpp */; };
2A7B2BDD1BD6F16600044BCD /* PVRSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2A7B2BDB1BD6F16600044BCD /* PVRSettings.cpp */; };
+ 2AB491701CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AB4916E1CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp */; };
+ 2AB491711CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AB4916E1CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp */; };
2AC7EB5A1C21F6BA00BDAA95 /* GUIWindowPVRTimerRules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AC7EB561C21F6BA00BDAA95 /* GUIWindowPVRTimerRules.cpp */; };
2AC7EB5B1C21F6BA00BDAA95 /* GUIWindowPVRTimersBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AC7EB581C21F6BA00BDAA95 /* GUIWindowPVRTimersBase.cpp */; };
2AC7EB5C1C2330B300BDAA95 /* GUIWindowPVRTimerRules.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 2AC7EB561C21F6BA00BDAA95 /* GUIWindowPVRTimerRules.cpp */; };
@@ -2580,6 +2582,8 @@
228FA65C1C53F9D50023BBF0 /* InfoScanner.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InfoScanner.cpp; sourceTree = "<group>"; };
2A7B2BDB1BD6F16600044BCD /* PVRSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PVRSettings.cpp; sourceTree = "<group>"; };
2A7B2BDE1BD6F18B00044BCD /* PVRSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PVRSettings.h; sourceTree = "<group>"; };
+ 2AB4916E1CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = HTTPRequestHandlerUtils.cpp; sourceTree = "<group>"; };
+ 2AB4916F1CDDF1920004C263 /* HTTPRequestHandlerUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTTPRequestHandlerUtils.h; sourceTree = "<group>"; };
2AC7EB561C21F6BA00BDAA95 /* GUIWindowPVRTimerRules.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowPVRTimerRules.cpp; sourceTree = "<group>"; };
2AC7EB571C21F6BA00BDAA95 /* GUIWindowPVRTimerRules.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GUIWindowPVRTimerRules.h; sourceTree = "<group>"; };
2AC7EB581C21F6BA00BDAA95 /* GUIWindowPVRTimersBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GUIWindowPVRTimersBase.cpp; sourceTree = "<group>"; };
@@ -7482,6 +7486,8 @@
DFCA6ABC152245CD000BFAAE /* HTTPJsonRpcHandler.h */,
395C29E11A98A15700EBC7AD /* HTTPPythonHandler.cpp */,
395C29E21A98A15700EBC7AD /* HTTPPythonHandler.h */,
+ 2AB4916E1CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp */,
+ 2AB4916F1CDDF1920004C263 /* HTTPRequestHandlerUtils.h */,
DFCA6ABD152245CD000BFAAE /* HTTPVfsHandler.cpp */,
DFCA6ABE152245CD000BFAAE /* HTTPVfsHandler.h */,
DFCA6ABF152245CD000BFAAE /* HTTPWebinterfaceAddonsHandler.cpp */,
@@ -10160,6 +10166,7 @@
18B7C7CD1294222E009E7A26 /* GUIListItemLayout.cpp in Sources */,
18B7C7CE1294222E009E7A26 /* GUIListLabel.cpp in Sources */,
18B7C7CF1294222E009E7A26 /* GUIMessage.cpp in Sources */,
+ 2AB491701CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp in Sources */,
18B7C7D01294222E009E7A26 /* GUIMoverControl.cpp in Sources */,
18B7C7D11294222E009E7A26 /* GUIMultiImage.cpp in Sources */,
18B7C7D21294222E009E7A26 /* GUIMultiSelectText.cpp in Sources */,
@@ -11321,6 +11328,7 @@
E49913B2174E5F3700741B6D /* WebSocket.cpp in Sources */,
E49913B3174E5F3700741B6D /* WebSocketManager.cpp in Sources */,
E49913B4174E5F3700741B6D /* WebSocketV13.cpp in Sources */,
+ 2AB491711CDDF1920004C263 /* HTTPRequestHandlerUtils.cpp in Sources */,
E49913B5174E5F3700741B6D /* WebSocketV8.cpp in Sources */,
E49913B6174E5F3C00741B6D /* AirPlayServer.cpp in Sources */,
E49913B7174E5F3C00741B6D /* AirTunesServer.cpp in Sources */,
diff --git a/addons/resource.language.en_gb/resources/strings.po b/addons/resource.language.en_gb/resources/strings.po
index cc4305a10d..11a42be1b9 100644
--- a/addons/resource.language.en_gb/resources/strings.po
+++ b/addons/resource.language.en_gb/resources/strings.po
@@ -3069,7 +3069,12 @@ msgctxt "#680"
msgid "Verbose logging for the [B]Video[/B] component"
msgstr ""
-#empty strings from id 681 to 699
+#: xbmc/settings/AdvancedSettings.cpp
+msgctxt "#681"
+msgid "Verbose logging for the [B]Webserver[/B] component"
+msgstr ""
+
+#empty strings from id 682 to 699
msgctxt "#700"
msgid "Cleaning up library"
diff --git a/project/VS2010Express/XBMC.vcxproj b/project/VS2010Express/XBMC.vcxproj
index 0c88bc4743..91e937d437 100644
--- a/project/VS2010Express/XBMC.vcxproj
+++ b/project/VS2010Express/XBMC.vcxproj
@@ -714,6 +714,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command>
<ClCompile Include="..\..\xbmc\peripherals\devices\PeripheralJoystick.cpp" />
<ClCompile Include="..\..\xbmc\peripherals\EventScanner.cpp" />
<ClCompile Include="..\..\xbmc\peripherals\EventScanRate.cpp" />
+ <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPRequestHandlerUtils.cpp" />
<ClCompile Include="..\..\xbmc\platform\posix\main.cpp">
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Debug Testsuite|Win32'">true</ExcludedFromBuild>
</ClCompile>
@@ -1267,6 +1268,7 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command>
<ClInclude Include="..\..\xbmc\peripherals\devices\PeripheralJoystick.h" />
<ClInclude Include="..\..\xbmc\peripherals\EventScanner.h" />
<ClInclude Include="..\..\xbmc\peripherals\EventScanRate.h" />
+ <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPRequestHandlerUtils.h" />
<ClInclude Include="..\..\xbmc\platform\MessagePrinter.h" />
<ClInclude Include="..\..\xbmc\media\MediaType.h" />
<ClInclude Include="..\..\xbmc\messaging\ApplicationMessenger.h" />
@@ -3148,4 +3150,4 @@ copy "..\Win32BuildSetup\dependencies\python27.dll" "$(TargetDir)"</Command>
</VisualStudio>
</ProjectExtensions>
<Import Project="$(SolutionDir)\$(ProjectFileName).targets.user" Condition="Exists('$(SolutionDir)\$(ProjectFileName).targets.user')" />
-</Project> \ No newline at end of file
+</Project>
diff --git a/project/VS2010Express/XBMC.vcxproj.filters b/project/VS2010Express/XBMC.vcxproj.filters
index d9458f7a49..79f39c2706 100644
--- a/project/VS2010Express/XBMC.vcxproj.filters
+++ b/project/VS2010Express/XBMC.vcxproj.filters
@@ -2842,6 +2842,11 @@
<ClCompile Include="..\..\xbmc\cores\FFmpeg.cpp">
<Filter>cores</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPRequestHandlerUtils.cpp">
+ <Filter>network\httprequesthandler</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
<ClCompile Include="..\..\xbmc\media\MediaType.cpp">
<Filter>media</Filter>
</ClCompile>
@@ -6723,6 +6728,9 @@
<ClInclude Include="..\..\xbmc\dialogs\GUIDialogKeyboardTouch.h">
<Filter>dialogs</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPRequestHandlerUtils.h">
+ <Filter>network\httprequesthandler</Filter>
+ </ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="..\..\xbmc\win32\XBMC_PC.rc">
@@ -6809,4 +6817,4 @@
<Filter>shaders</Filter>
</FxCompile>
</ItemGroup>
-</Project> \ No newline at end of file
+</Project>
diff --git a/xbmc/commons/ilog.h b/xbmc/commons/ilog.h
index de90359aa6..90cd9a7149 100644
--- a/xbmc/commons/ilog.h
+++ b/xbmc/commons/ilog.h
@@ -39,20 +39,21 @@
#define LOGNONE 7
// extra masks - from bit 5
-#define LOGMASKBIT 5
-#define LOGMASK ((1 << LOGMASKBIT) - 1)
+#define LOGMASKBIT 5
+#define LOGMASK ((1 << LOGMASKBIT) - 1)
-#define LOGSAMBA (1 << (LOGMASKBIT + 0))
-#define LOGCURL (1 << (LOGMASKBIT + 1))
-#define LOGFFMPEG (1 << (LOGMASKBIT + 2))
-#define LOGRTMP (1 << (LOGMASKBIT + 3))
-#define LOGDBUS (1 << (LOGMASKBIT + 4))
-#define LOGJSONRPC (1 << (LOGMASKBIT + 5))
-#define LOGAUDIO (1 << (LOGMASKBIT + 6))
-#define LOGAIRTUNES (1 << (LOGMASKBIT + 7))
-#define LOGUPNP (1 << (LOGMASKBIT + 8))
-#define LOGCEC (1 << (LOGMASKBIT + 9))
-#define LOGVIDEO (1 << (LOGMASKBIT + 10))
+#define LOGSAMBA (1 << (LOGMASKBIT + 0))
+#define LOGCURL (1 << (LOGMASKBIT + 1))
+#define LOGFFMPEG (1 << (LOGMASKBIT + 2))
+#define LOGRTMP (1 << (LOGMASKBIT + 3))
+#define LOGDBUS (1 << (LOGMASKBIT + 4))
+#define LOGJSONRPC (1 << (LOGMASKBIT + 5))
+#define LOGAUDIO (1 << (LOGMASKBIT + 6))
+#define LOGAIRTUNES (1 << (LOGMASKBIT + 7))
+#define LOGUPNP (1 << (LOGMASKBIT + 8))
+#define LOGCEC (1 << (LOGMASKBIT + 9))
+#define LOGVIDEO (1 << (LOGMASKBIT + 10))
+#define LOGWEBSERVER (1 << (LOGMASKBIT + 11))
#include "utils/params_check_macros.h"
diff --git a/xbmc/network/NetworkServices.cpp b/xbmc/network/NetworkServices.cpp
index 1e151960d5..1aa03f8bdf 100644
--- a/xbmc/network/NetworkServices.cpp
+++ b/xbmc/network/NetworkServices.cpp
@@ -119,18 +119,18 @@ CNetworkServices::CNetworkServices()
#endif // HAS_WEB_SERVER
{
#ifdef HAS_WEB_SERVER
- CWebServer::RegisterRequestHandler(&m_httpImageHandler);
- CWebServer::RegisterRequestHandler(&m_httpImageTransformationHandler);
- CWebServer::RegisterRequestHandler(&m_httpVfsHandler);
+ m_webserver.RegisterRequestHandler(&m_httpImageHandler);
+ m_webserver.RegisterRequestHandler(&m_httpImageTransformationHandler);
+ m_webserver.RegisterRequestHandler(&m_httpVfsHandler);
#ifdef HAS_JSONRPC
- CWebServer::RegisterRequestHandler(&m_httpJsonRpcHandler);
+ m_webserver.RegisterRequestHandler(&m_httpJsonRpcHandler);
#endif // HAS_JSONRPC
#ifdef HAS_WEB_INTERFACE
#ifdef HAS_PYTHON
- CWebServer::RegisterRequestHandler(&m_httpPythonHandler);
+ m_webserver.RegisterRequestHandler(&m_httpPythonHandler);
#endif
- CWebServer::RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
- CWebServer::RegisterRequestHandler(&m_httpWebinterfaceHandler);
+ m_webserver.RegisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
+ m_webserver.RegisterRequestHandler(&m_httpWebinterfaceHandler);
#endif // HAS_WEB_INTERFACE
#endif // HAS_WEB_SERVER
}
@@ -138,25 +138,25 @@ CNetworkServices::CNetworkServices()
CNetworkServices::~CNetworkServices()
{
#ifdef HAS_WEB_SERVER
- CWebServer::UnregisterRequestHandler(&m_httpImageHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpImageHandler);
delete &m_httpImageHandler;
- CWebServer::UnregisterRequestHandler(&m_httpImageTransformationHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpImageTransformationHandler);
delete &m_httpImageTransformationHandler;
- CWebServer::UnregisterRequestHandler(&m_httpVfsHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpVfsHandler);
delete &m_httpVfsHandler;
#ifdef HAS_JSONRPC
- CWebServer::UnregisterRequestHandler(&m_httpJsonRpcHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpJsonRpcHandler);
delete &m_httpJsonRpcHandler;
CJSONRPC::Cleanup();
#endif // HAS_JSONRPC
#ifdef HAS_WEB_INTERFACE
#ifdef HAS_PYTHON
- CWebServer::UnregisterRequestHandler(&m_httpPythonHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpPythonHandler);
delete &m_httpPythonHandler;
#endif
- CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpWebinterfaceAddonsHandler);
delete &m_httpWebinterfaceAddonsHandler;
- CWebServer::UnregisterRequestHandler(&m_httpWebinterfaceHandler);
+ m_webserver.UnregisterRequestHandler(&m_httpWebinterfaceHandler);
delete &m_httpWebinterfaceHandler;
#endif // HAS_WEB_INTERFACE
delete &m_webserver;
diff --git a/xbmc/network/WebServer.cpp b/xbmc/network/WebServer.cpp
index 9237621ef2..2f9d1f3420 100644
--- a/xbmc/network/WebServer.cpp
+++ b/xbmc/network/WebServer.cpp
@@ -35,7 +35,9 @@
#endif
#include "filesystem/File.h"
+#include "network/httprequesthandler/HTTPRequestHandlerUtils.h"
#include "network/httprequesthandler/IHTTPRequestHandler.h"
+#include "settings/AdvancedSettings.h"
#include "settings/Settings.h"
#include "threads/SingleLock.h"
#include "URL.h"
@@ -48,8 +50,6 @@
#include "utils/Variant.h"
#include "XBDateTime.h"
-//#define WEBSERVER_DEBUG
-
#ifdef TARGET_WINDOWS
#ifndef _DEBUG
#pragma comment(lib, "libmicrohttpd.lib")
@@ -67,23 +67,6 @@
#define HEADER_NEWLINE "\r\n"
-typedef struct ConnectionHandler
-{
- std::string fullUri;
- bool isNew;
- std::shared_ptr<IHTTPRequestHandler> requestHandler;
- struct MHD_PostProcessor *postprocessor;
- int errorStatus;
-
- ConnectionHandler(const std::string& uri)
- : fullUri(uri)
- , isNew(true)
- , requestHandler(nullptr)
- , postprocessor(nullptr)
- , errorStatus(MHD_HTTP_OK)
- { }
-} ConnectionHandler;
-
typedef struct {
std::shared_ptr<XFILE::CFile> file;
CHttpRanges ranges;
@@ -96,10 +79,9 @@ typedef struct {
uint64_t writePosition;
} HttpFileDownloadContext;
-std::vector<IHTTPRequestHandler *> CWebServer::m_requestHandlers;
-
CWebServer::CWebServer()
- : m_daemon_ip6(nullptr),
+ : m_port(0),
+ m_daemon_ip6(nullptr),
m_daemon_ip4(nullptr),
m_running(false),
m_needcredentials(false),
@@ -120,44 +102,12 @@ CWebServer::CWebServer()
#endif
}
-HTTPMethod CWebServer::GetMethod(const char *method)
-{
- if (strcmp(method, "GET") == 0)
- return GET;
- if (strcmp(method, "POST") == 0)
- return POST;
- if (strcmp(method, "HEAD") == 0)
- return HEAD;
-
- return UNKNOWN;
-}
-
-int CWebServer::FillArgumentMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
-{
- if (cls == nullptr || key == nullptr)
- return MHD_NO;
-
- std::map<std::string, std::string> *arguments = (std::map<std::string, std::string> *)cls;
- arguments->insert(std::make_pair(key, value != nullptr ? value : ""));
- return MHD_YES;
-}
-
-int CWebServer::FillArgumentMultiMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
-{
- if (cls == nullptr || key == nullptr)
- return MHD_NO;
-
- std::multimap<std::string, std::string> *arguments = (std::multimap<std::string, std::string> *)cls;
- arguments->insert(std::make_pair(key, value != nullptr ? value : ""));
- return MHD_YES;
-}
-
-int CWebServer::AskForAuthentication(struct MHD_Connection *connection)
+int CWebServer::AskForAuthentication(struct MHD_Connection *connection) const
{
struct MHD_Response *response = MHD_create_response_from_data(0, nullptr, MHD_NO, MHD_NO);
if (!response)
{
- CLog::Log(LOGERROR, "CWebServer: unable to create HTTP Unauthorized response");
+ CLog::Log(LOGERROR, "CWebServer[%hu]: unable to create HTTP Unauthorized response", m_port);
return MHD_NO;
}
@@ -165,20 +115,21 @@ int CWebServer::AskForAuthentication(struct MHD_Connection *connection)
ret |= AddHeader(response, MHD_HTTP_HEADER_CONNECTION, "close");
if (!ret)
{
- CLog::Log(LOGERROR, "CWebServer: unable to prepare HTTP Unauthorized response");
+ CLog::Log(LOGERROR, "CWebServer[%hu]: unable to prepare HTTP Unauthorized response", m_port);
MHD_destroy_response(response);
return MHD_NO;
}
-#ifdef WEBSERVER_DEBUG
- std::multimap<std::string, std::string> headerValues;
- GetRequestHeaderValues(connection, MHD_RESPONSE_HEADER_KIND, headerValues);
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ {
+ std::multimap<std::string, std::string> headerValues;
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(connection, MHD_RESPONSE_HEADER_KIND, headerValues);
- CLog::Log(LOGDEBUG, "webserver [OUT] HTTP %d", MHD_HTTP_UNAUTHORIZED);
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] HTTP %d", m_port, MHD_HTTP_UNAUTHORIZED);
- for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
- CLog::Log(LOGDEBUG, "webserver [OUT] %s: %s", header->first.c_str(), header->second.c_str());
-#endif
+ for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] %s: %s", m_port, header->first.c_str(), header->second.c_str());
+ }
ret = MHD_queue_response(connection, MHD_HTTP_UNAUTHORIZED, response);
MHD_destroy_response(response);
@@ -186,19 +137,19 @@ int CWebServer::AskForAuthentication(struct MHD_Connection *connection)
return ret;
}
-bool CWebServer::IsAuthenticated(CWebServer *server, struct MHD_Connection *connection)
+bool CWebServer::IsAuthenticated(struct MHD_Connection *connection) const
{
- CSingleLock lock(server->m_critSection);
+ CSingleLock lock(m_critSection);
- if (!server->m_needcredentials)
+ if (!m_needcredentials)
return true;
const char *base = "Basic ";
- std::string authorization = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
+ std::string authorization = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_AUTHORIZATION);
if (authorization.empty() || !StringUtils::StartsWith(authorization, base))
return false;
- return server->m_Credentials64Encoded.compare(StringUtils::Mid(authorization.c_str(), strlen(base))) == 0;
+ return m_Credentials64Encoded.compare(StringUtils::Mid(authorization.c_str(), strlen(base))) == 0;
}
#if (MHD_VERSION >= 0x00040001)
@@ -215,32 +166,29 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
{
if (cls == nullptr || con_cls == nullptr || *con_cls == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: invalid request received");
+ CLog::Log(LOGERROR, "CWebServer[unknown]: invalid request received");
return MHD_NO;
}
- CWebServer *server = reinterpret_cast<CWebServer*>(cls);
- std::unique_ptr<ConnectionHandler> conHandler(reinterpret_cast<ConnectionHandler*>(*con_cls));
- HTTPMethod methodType = GetMethod(method);
- HTTPRequest request = { server, connection, conHandler->fullUri, url, methodType, version };
-
- // remember if the request was new
- bool isNewRequest = conHandler->isNew;
- // because now it isn't anymore
- conHandler->isNew = false;
+ CWebServer *webServer = reinterpret_cast<CWebServer*>(cls);
+ if (webServer == nullptr)
+ {
+ CLog::Log(LOGERROR, "CWebServer[unknown]: invalid request received");
+ return MHD_NO;
+ }
- // reset con_cls and set it if still necessary
- *con_cls = nullptr;
+ ConnectionHandler* connectionHandler = reinterpret_cast<ConnectionHandler*>(*con_cls);
+ HTTPMethod methodType = GetHTTPMethod(method);
+ HTTPRequest request = { webServer, connection, connectionHandler->fullUri, url, methodType, version };
-#ifdef WEBSERVER_DEBUG
- if (isNewRequest)
+ if (connectionHandler->isNew && g_advancedSettings.CanLogComponent(LOGWEBSERVER))
{
std::multimap<std::string, std::string> headerValues;
- GetRequestHeaderValues(connection, MHD_HEADER_KIND, headerValues);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(connection, MHD_HEADER_KIND, headerValues);
std::multimap<std::string, std::string> getValues;
- GetRequestHeaderValues(connection, MHD_GET_ARGUMENT_KIND, getValues);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(connection, MHD_GET_ARGUMENT_KIND, getValues);
- CLog::Log(LOGDEBUG, "webserver [IN] %s %s %s", version, method, request.pathUrlFull.c_str());
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [IN] %s %s %s", webServer->m_port, version, GetHTTPMethod(request.method).c_str(), request.pathUrlFull.c_str());
if (!getValues.empty())
{
std::string tmp;
@@ -250,15 +198,29 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
tmp += "; ";
tmp += get->first + " = " + get->second;
}
- CLog::Log(LOGDEBUG, "webserver [IN] Query arguments: %s", tmp.c_str());
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [IN] Query arguments: %s", webServer->m_port, tmp.c_str());
}
for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
- CLog::Log(LOGDEBUG, "webserver [IN] %s: %s", header->first.c_str(), header->second.c_str());
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [IN] %s: %s", webServer->m_port, header->first.c_str(), header->second.c_str());
}
-#endif
- if (!IsAuthenticated(server, connection))
+ return webServer->HandlePartialRequest(connection, connectionHandler, request, upload_data, upload_data_size, con_cls);
+}
+
+int CWebServer::HandlePartialRequest(struct MHD_Connection *connection, ConnectionHandler* connectionHandler, HTTPRequest request, const char *upload_data, size_t *upload_data_size, void **con_cls)
+{
+ std::unique_ptr<ConnectionHandler> conHandler(connectionHandler);
+
+ // remember if the request was new
+ bool isNewRequest = conHandler->isNew;
+ // because now it isn't anymore
+ conHandler->isNew = false;
+
+ // reset con_cls and set it if still necessary
+ *con_cls = nullptr;
+
+ if (!IsAuthenticated(connection))
return AskForAuthentication(connection);
// check if this is the first call to AnswerToConnection for this request
@@ -266,7 +228,7 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
{
// parse the Range header and store it in the request object
CHttpRanges ranges;
- bool ranged = ranges.Parse(GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE));
+ bool ranged = ranges.Parse(HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE));
// look for a IHTTPRequestHandler which can take care of the current request
for (std::vector<IHTTPRequestHandler *>::const_iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it)
@@ -278,14 +240,14 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
std::shared_ptr<IHTTPRequestHandler> handler(requestHandler->Create(request));
// if we got a GET request we need to check if it should be cached
- if (methodType == GET)
+ if (request.method == GET)
{
if (handler->CanBeCached())
{
bool cacheable = true;
// handle Cache-Control
- std::string cacheControl = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CACHE_CONTROL);
+ std::string cacheControl = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CACHE_CONTROL);
if (!cacheControl.empty())
{
std::vector<std::string> cacheControls = StringUtils::Split(cacheControl, ",");
@@ -303,7 +265,7 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
if (cacheable)
{
// handle Pragma (but only if "Cache-Control: no-cache" hasn't been set)
- std::string pragma = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_PRAGMA);
+ std::string pragma = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_PRAGMA);
if (pragma.compare(HEADER_VALUE_NO_CACHE) == 0)
cacheable = false;
}
@@ -312,8 +274,8 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
if (handler->GetLastModifiedDate(lastModified) && lastModified.IsValid())
{
// handle If-Modified-Since or If-Unmodified-Since
- std::string ifModifiedSince = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_MODIFIED_SINCE);
- std::string ifUnmodifiedSince = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE);
+ std::string ifModifiedSince = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_MODIFIED_SINCE);
+ std::string ifUnmodifiedSince = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_UNMODIFIED_SINCE);
CDateTime ifModifiedSinceDate;
CDateTime ifUnmodifiedSinceDate;
@@ -325,7 +287,7 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
struct MHD_Response *response = MHD_create_response_from_data(0, nullptr, MHD_NO, MHD_NO);
if (response == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP 304 response");
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP 304 response", m_port);
return MHD_NO;
}
@@ -334,13 +296,13 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
// handle If-Unmodified-Since
else if (ifUnmodifiedSinceDate.SetFromRFC1123DateTime(ifUnmodifiedSince) &&
lastModified.GetAsUTCDateTime() > ifUnmodifiedSinceDate)
- return SendErrorResponse(connection, MHD_HTTP_PRECONDITION_FAILED, methodType);
+ return SendErrorResponse(connection, MHD_HTTP_PRECONDITION_FAILED, request.method);
}
// handle If-Range header but only if the Range header is present
if (ranged && lastModified.IsValid())
{
- std::string ifRange = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_RANGE);
+ std::string ifRange = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_IF_RANGE);
if (!ifRange.empty() && lastModified.IsValid())
{
CDateTime ifRangeDate;
@@ -358,12 +320,12 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
}
}
// if we got a POST request we need to take care of the POST data
- else if (methodType == POST)
+ else if (request.method == POST)
{
conHandler->requestHandler = handler;
// get the content-type of the POST data
- std::string contentType = GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
+ std::string contentType = HTTPRequestHandlerUtils::GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
if (!contentType.empty())
{
// if the content-type is application/x-ww-form-urlencoded or multipart/form-data we can use MHD's POST processor
@@ -376,7 +338,7 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
// MHD doesn't seem to be able to handle this post request
if (conHandler->postprocessor == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: unable to create HTTP POST processor for %s", url);
+ CLog::Log(LOGERROR, "CWebServer[%hu]: unable to create HTTP POST processor for %s", m_port, request.pathUrl.c_str());
conHandler->errorStatus = MHD_HTTP_INTERNAL_SERVER_ERROR;
}
}
@@ -397,11 +359,11 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
else
{
// again we need to take special care of the POST data
- if (methodType == POST)
+ if (request.method == POST)
{
if (conHandler->requestHandler == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: cannot handle partial HTTP POST for %s request because there is no valid request handler available", url);
+ CLog::Log(LOGERROR, "CWebServer[%hu]: cannot handle partial HTTP POST for %s request because there is no valid request handler available", m_port, request.pathUrl.c_str());
conHandler->errorStatus = MHD_HTTP_INTERNAL_SERVER_ERROR;
}
@@ -422,7 +384,7 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
// abort if the received POST data couldn't be handled
if (!postDataHandled)
{
- CLog::Log(LOGERROR, "CWebServer: failed to handle HTTP POST data for %s", url);
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to handle HTTP POST data for %s", m_port, request.pathUrl.c_str());
conHandler->errorStatus = MHD_HTTP_REQUEST_ENTITY_TOO_LARGE;
}
}
@@ -444,7 +406,7 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
// check if something went wrong while handling the POST data
if (conHandler->errorStatus != MHD_HTTP_OK)
- return SendErrorResponse(connection, conHandler->errorStatus, methodType);
+ return SendErrorResponse(connection, conHandler->errorStatus, request.method);
return HandleRequest(conHandler->requestHandler);
}
@@ -461,8 +423,8 @@ int CWebServer::AnswerToConnection(void *cls, struct MHD_Connection *connection,
}
}
- CLog::Log(LOGERROR, "CWebServer: couldn't find any request handler for %s", url);
- return SendErrorResponse(connection, MHD_HTTP_NOT_FOUND, methodType);
+ CLog::Log(LOGERROR, "CWebServer[%hu]: couldn't find any request handler for %s", m_port, request.pathUrl.c_str());
+ return SendErrorResponse(connection, MHD_HTTP_NOT_FOUND, request.method);
}
#if (MHD_VERSION >= 0x00040001)
@@ -482,7 +444,7 @@ int CWebServer::HandlePostField(void *cls, enum MHD_ValueKind kind, const char *
if (conHandler == nullptr || conHandler->requestHandler == nullptr ||
key == nullptr || data == nullptr || size == 0)
{
- CLog::Log(LOGERROR, "CWebServer: unable to handle HTTP POST field");
+ CLog::Log(LOGERROR, "CWebServer[%hu]: unable to handle HTTP POST field", reinterpret_cast<CWebServer*>(cls)->m_port);
return MHD_NO;
}
@@ -499,7 +461,7 @@ int CWebServer::HandleRequest(const std::shared_ptr<IHTTPRequestHandler>& handle
int ret = handler->HandleRequest();
if (ret == MHD_NO)
{
- CLog::Log(LOGERROR, "CWebServer: failed to handle HTTP request for %s", request.pathUrl.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to handle HTTP request for %s", m_port, request.pathUrl.c_str());
return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
}
@@ -508,7 +470,7 @@ int CWebServer::HandleRequest(const std::shared_ptr<IHTTPRequestHandler>& handle
switch (responseDetails.type)
{
case HTTPNone:
- CLog::Log(LOGERROR, "CWebServer: HTTP request handler didn't process %s", request.pathUrl.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: HTTP request handler didn't process %s", m_port, request.pathUrl.c_str());
return MHD_NO;
case HTTPRedirect:
@@ -531,13 +493,13 @@ int CWebServer::HandleRequest(const std::shared_ptr<IHTTPRequestHandler>& handle
break;
default:
- CLog::Log(LOGERROR, "CWebServer: internal error while HTTP request handler processed %s", request.pathUrl.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: internal error while HTTP request handler processed %s", m_port, request.pathUrl.c_str());
return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
}
if (ret == MHD_NO)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create HTTP response for %s", request.pathUrl.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create HTTP response for %s", m_port, request.pathUrl.c_str());
return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
}
@@ -609,15 +571,16 @@ int CWebServer::FinalizeRequest(const std::shared_ptr<IHTTPRequestHandler>& hand
for (std::multimap<std::string, std::string>::const_iterator it = responseDetails.headers.begin(); it != responseDetails.headers.end(); ++it)
AddHeader(response, it->first, it->second);
-#ifdef WEBSERVER_DEBUG
- std::multimap<std::string, std::string> headerValues;
- GetRequestHeaderValues(request.connection, MHD_RESPONSE_HEADER_KIND, headerValues);
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ {
+ std::multimap<std::string, std::string> headerValues;
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(request.connection, MHD_RESPONSE_HEADER_KIND, headerValues);
- CLog::Log(LOGDEBUG, "webserver [OUT] %s %d %s", request.version.c_str(), responseStatus, request.pathUrlFull.c_str());
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] %s %d %s", m_port, request.version.c_str(), responseStatus, request.pathUrlFull.c_str());
- for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
- CLog::Log(LOGDEBUG, "webserver [OUT] %s: %s", header->first.c_str(), header->second.c_str());
-#endif
+ for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] %s: %s", m_port, header->first.c_str(), header->second.c_str());
+ }
int ret = MHD_queue_response(request.connection, responseStatus, response);
MHD_destroy_response(response);
@@ -625,7 +588,7 @@ int CWebServer::FinalizeRequest(const std::shared_ptr<IHTTPRequestHandler>& hand
return ret;
}
-int CWebServer::CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response)
+int CWebServer::CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const
{
if (handler == nullptr)
return MHD_NO;
@@ -642,7 +605,7 @@ int CWebServer::CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestH
if ((request.ranges.IsEmpty() && responseRanges.size() > 1) ||
(!request.ranges.IsEmpty() && responseRanges.size() > request.ranges.Size()))
{
- CLog::Log(LOGWARNING, "CWebServer: response contains more ranges (%d) than the request asked for (%d)", (int)responseRanges.size(), (int)request.ranges.Size());
+ CLog::Log(LOGWARNING, "CWebServer[%hu]: response contains more ranges (%d) than the request asked for (%d)", m_port, (int)responseRanges.size(), (int)request.ranges.Size());
return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
}
@@ -654,7 +617,7 @@ int CWebServer::CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestH
// check if the range is valid
if (!responseRange.IsValid())
{
- CLog::Log(LOGWARNING, "CWebServer: invalid response data with range start at %" PRId64 " and end at %" PRId64, responseRange.GetFirstPosition(), responseRange.GetLastPosition());
+ CLog::Log(LOGWARNING, "CWebServer[%hu]: invalid response data with range start at %" PRId64 " and end at %" PRId64, m_port, responseRange.GetFirstPosition(), responseRange.GetLastPosition());
return SendErrorResponse(request.connection, MHD_HTTP_INTERNAL_SERVER_ERROR, request.method);
}
@@ -683,7 +646,7 @@ int CWebServer::CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestH
return CreateRangedMemoryDownloadResponse(handler, response);
}
-int CWebServer::CreateRangedMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response)
+int CWebServer::CreateRangedMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const
{
if (handler == nullptr)
return MHD_NO;
@@ -763,12 +726,12 @@ int CWebServer::CreateRangedMemoryDownloadResponse(const std::shared_ptr<IHTTPRe
return CreateMemoryDownloadResponse(request.connection, result.c_str(), result.size(), false, true, response);
}
-int CWebServer::CreateRedirect(struct MHD_Connection *connection, const std::string &strURL, struct MHD_Response *&response)
+int CWebServer::CreateRedirect(struct MHD_Connection *connection, const std::string &strURL, struct MHD_Response *&response) const
{
response = MHD_create_response_from_data(0, nullptr, MHD_NO, MHD_NO);
if (response == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create HTTP redirect response to %s", strURL.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create HTTP redirect response to %s", m_port, strURL.c_str());
return MHD_NO;
}
@@ -776,7 +739,7 @@ int CWebServer::CreateRedirect(struct MHD_Connection *connection, const std::str
return MHD_YES;
}
-int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response)
+int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const
{
if (handler == nullptr)
return MHD_NO;
@@ -790,7 +753,7 @@ int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHan
if (!file->Open(filePath, XFILE::READ_NO_CACHE))
{
- CLog::Log(LOGERROR, "WebServer: Failed to open %s", filePath.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: Failed to open %s", m_port, filePath.c_str());
return SendErrorResponse(request.connection, MHD_HTTP_NOT_FOUND, request.method);
}
@@ -820,7 +783,7 @@ int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHan
if (!request.ranges.IsEmpty())
context->ranges = request.ranges;
else
- GetRequestedRanges(request.connection, fileLength, context->ranges);
+ HTTPRequestHandlerUtils::GetRequestedRanges(request.connection, fileLength, context->ranges);
}
uint64_t firstPosition = 0;
@@ -880,7 +843,7 @@ int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHan
&CWebServer::ContentReaderFreeCallback);
if (response == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP response for %s to be filled from %s", request.pathUrl.c_str(), filePath.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP response for %s to be filled from %s", m_port, request.pathUrl.c_str(), filePath.c_str());
return MHD_NO;
}
@@ -895,7 +858,7 @@ int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHan
response = MHD_create_response_from_data(0, nullptr, MHD_NO, MHD_NO);
if (response == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP HEAD response for %s", request.pathUrl.c_str());
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP HEAD response for %s", m_port, request.pathUrl.c_str());
return MHD_NO;
}
@@ -909,7 +872,7 @@ int CWebServer::CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHan
return MHD_YES;
}
-int CWebServer::CreateErrorResponse(struct MHD_Connection *connection, int responseType, HTTPMethod method, struct MHD_Response *&response)
+int CWebServer::CreateErrorResponse(struct MHD_Connection *connection, int responseType, HTTPMethod method, struct MHD_Response *&response) const
{
size_t payloadSize = 0;
void *payload = nullptr;
@@ -933,40 +896,41 @@ int CWebServer::CreateErrorResponse(struct MHD_Connection *connection, int respo
response = MHD_create_response_from_data(payloadSize, payload, MHD_NO, MHD_NO);
if (response == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP %d error response", responseType);
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP %d error response", m_port, responseType);
return MHD_NO;
}
return MHD_YES;
}
-int CWebServer::CreateMemoryDownloadResponse(struct MHD_Connection *connection, const void *data, size_t size, bool free, bool copy, struct MHD_Response *&response)
+int CWebServer::CreateMemoryDownloadResponse(struct MHD_Connection *connection, const void *data, size_t size, bool free, bool copy, struct MHD_Response *&response) const
{
response = MHD_create_response_from_data(size, const_cast<void*>(data), free ? MHD_YES : MHD_NO, copy ? MHD_YES : MHD_NO);
if (response == nullptr)
{
- CLog::Log(LOGERROR, "CWebServer: failed to create a HTTP download response");
+ CLog::Log(LOGERROR, "CWebServer[%hu]: failed to create a HTTP download response", m_port);
return MHD_NO;
}
return MHD_YES;
}
-int CWebServer::SendErrorResponse(struct MHD_Connection *connection, int errorType, HTTPMethod method)
+int CWebServer::SendErrorResponse(struct MHD_Connection *connection, int errorType, HTTPMethod method) const
{
struct MHD_Response *response = nullptr;
int ret = CreateErrorResponse(connection, errorType, method, response);
if (ret == MHD_YES)
{
-#ifdef WEBSERVER_DEBUG
- std::multimap<std::string, std::string> headerValues;
- GetRequestHeaderValues(connection, MHD_RESPONSE_HEADER_KIND, headerValues);
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ {
+ std::multimap<std::string, std::string> headerValues;
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(connection, MHD_RESPONSE_HEADER_KIND, headerValues);
- CLog::Log(LOGDEBUG, "webserver [OUT] HTTP %d", errorType);
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] HTTP %d", m_port, errorType);
- for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
- CLog::Log(LOGDEBUG, "webserver [OUT] %s: %s", header->first.c_str(), header->second.c_str());
-#endif
+ for (std::multimap<std::string, std::string>::const_iterator header = headerValues.begin(); header != headerValues.end(); ++header)
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] %s: %s", m_port, header->first.c_str(), header->second.c_str());
+ }
ret = MHD_queue_response(connection, errorType, response);
MHD_destroy_response(response);
@@ -977,13 +941,26 @@ int CWebServer::SendErrorResponse(struct MHD_Connection *connection, int errorTy
void* CWebServer::UriRequestLogger(void *cls, const char *uri)
{
+ CWebServer *webServer = reinterpret_cast<CWebServer*>(cls);
+
// log the full URI
- CLog::Log(LOGDEBUG, "webserver: request received for %s", uri);
+ if (webServer == nullptr)
+ CLog::Log(LOGDEBUG, "CWebServer[unknown]: request received for %s", uri);
+ else
+ webServer->LogRequest(uri);
// create and return a new connection handler
return new ConnectionHandler(uri);
}
+void CWebServer::LogRequest(const char* uri) const
+{
+ if (uri == nullptr)
+ return;
+
+ CLog::Log(LOGDEBUG, "CWebServer[%hu]: request received for %s", m_port, uri);
+}
+
#if (MHD_VERSION >= 0x00090200)
ssize_t CWebServer::ContentReaderCallback(void *cls, uint64_t pos, char *buf, size_t max)
#elif (MHD_VERSION >= 0x00040001)
@@ -996,9 +973,8 @@ int CWebServer::ContentReaderCallback(void *cls, size_t pos, char *buf, int max)
if (context == nullptr || context->file == nullptr)
return -1;
-#ifdef WEBSERVER_DEBUG
- CLog::Log(LOGDEBUG, "webserver [OUT] write maximum %d bytes from %" PRIu64 " (%" PRIu64 ")", max, context->writePosition, pos);
-#endif
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ CLog::Log(LOGDEBUG, "CWebServer [OUT] write maximum %d bytes from %" PRIu64 " (%" PRIu64 ")", max, context->writePosition, pos);
// check if we need to add the end-boundary
if (context->rangeCountTotal > 1 && context->ranges.IsEmpty())
@@ -1066,9 +1042,10 @@ int CWebServer::ContentReaderCallback(void *cls, size_t pos, char *buf, int max)
// add the number of read bytes to the number of written bytes
written += res;
-#ifdef WEBSERVER_DEBUG
- CLog::Log(LOGDEBUG, "webserver [OUT] wrote %d bytes from %" PRIu64 " in range (%" PRIu64 " - %" PRIu64 ")", written, context->writePosition, start, end);
-#endif
+
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ CLog::Log(LOGDEBUG, "CWebServer [OUT] wrote %d bytes from %" PRIu64 " in range (%" PRIu64 " - %" PRIu64 ")", written, context->writePosition, start, end);
+
// update the current write position
context->writePosition += res;
@@ -1088,9 +1065,8 @@ void CWebServer::ContentReaderFreeCallback(void *cls)
HttpFileDownloadContext *context = (HttpFileDownloadContext *)cls;
delete context;
-#ifdef WEBSERVER_DEBUG
- CLog::Log(LOGDEBUG, "webserver [OUT] done");
-#endif
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] done", reinterpret_cast<CWebServer*>(cls)->m_port);
}
// local helper
@@ -1164,7 +1140,7 @@ struct MHD_Daemon* CWebServer::StartMHD(unsigned int flags, int port)
MHD_OPTION_END);
}
-bool CWebServer::Start(int port, const std::string &username, const std::string &password)
+bool CWebServer::Start(uint16_t port, const std::string &username, const std::string &password)
{
SetCredentials(username, password);
if (!m_running)
@@ -1180,9 +1156,12 @@ bool CWebServer::Start(int port, const std::string &username, const std::string
m_running = (m_daemon_ip6 != nullptr) || (m_daemon_ip4 != nullptr);
if (m_running)
- CLog::Log(LOGNOTICE, "WebServer: Started the webserver");
+ {
+ m_port = port;
+ CLog::Log(LOGNOTICE, "CWebServer[%hu]: Started", m_port);
+ }
else
- CLog::Log(LOGERROR, "WebServer: Failed to start the webserver");
+ CLog::Log(LOGERROR, "CWebServer[%hu]: Failed to start", port);
}
return m_running;
@@ -1190,21 +1169,20 @@ bool CWebServer::Start(int port, const std::string &username, const std::string
bool CWebServer::Stop()
{
- if (m_running)
- {
- if (m_daemon_ip6 != nullptr)
- MHD_stop_daemon(m_daemon_ip6);
+ if (!m_running)
+ return true;
+
+ if (m_daemon_ip6 != nullptr)
+ MHD_stop_daemon(m_daemon_ip6);
- if (m_daemon_ip4 != nullptr)
- MHD_stop_daemon(m_daemon_ip4);
+ if (m_daemon_ip4 != nullptr)
+ MHD_stop_daemon(m_daemon_ip4);
- m_running = false;
- CLog::Log(LOGNOTICE, "WebServer: Stopped the webserver");
- }
- else
- CLog::Log(LOGNOTICE, "WebServer: Stopped failed because its not running");
+ m_running = false;
+ CLog::Log(LOGNOTICE, "CWebServer[%hu]: Stopped", m_port);
+ m_port = 0;
- return !m_running;
+ return true;
}
bool CWebServer::IsStarted()
@@ -1220,53 +1198,18 @@ void CWebServer::SetCredentials(const std::string &username, const std::string &
m_needcredentials = !password.empty();
}
-bool CWebServer::PrepareDownload(const char *path, CVariant &details, std::string &protocol)
-{
- if (!XFILE::CFile::Exists(path))
- return false;
-
- protocol = "http";
- std::string url;
- std::string strPath = path;
- if (StringUtils::StartsWith(strPath, "image://") ||
- (StringUtils::StartsWith(strPath, "special://") && StringUtils::EndsWith(strPath, ".tbn")))
- url = "image/";
- else
- url = "vfs/";
- url += CURL::Encode(strPath);
- details["path"] = url;
-
- return true;
-}
-
-bool CWebServer::Download(const char *path, CVariant &result)
-{
- return false;
-}
-
-int CWebServer::GetCapabilities()
-{
- return JSONRPC::Response | JSONRPC::FileDownloadRedirect;
-}
-
void CWebServer::RegisterRequestHandler(IHTTPRequestHandler *handler)
{
if (handler == nullptr)
return;
- for (std::vector<IHTTPRequestHandler *>::iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it)
- {
- if (*it == handler)
- return;
-
- if ((*it)->GetPriority() < handler->GetPriority())
- {
- m_requestHandlers.insert(it, handler);
- return;
- }
- }
+ const auto& it = std::find(m_requestHandlers.cbegin(), m_requestHandlers.cend(), handler);
+ if (it != m_requestHandlers.cend())
+ return;
m_requestHandlers.push_back(handler);
+ std::sort(m_requestHandlers.begin(), m_requestHandlers.end(),
+ [](IHTTPRequestHandler* lhs, IHTTPRequestHandler* rhs) { return rhs->GetPriority() < lhs->GetPriority(); });
}
void CWebServer::UnregisterRequestHandler(IHTTPRequestHandler *handler)
@@ -1274,64 +1217,7 @@ void CWebServer::UnregisterRequestHandler(IHTTPRequestHandler *handler)
if (handler == nullptr)
return;
- for (std::vector<IHTTPRequestHandler *>::iterator it = m_requestHandlers.begin(); it != m_requestHandlers.end(); ++it)
- {
- if (*it == handler)
- {
- m_requestHandlers.erase(it);
- return;
- }
- }
-}
-
-std::string CWebServer::GetRequestHeaderValue(struct MHD_Connection *connection, enum MHD_ValueKind kind, const std::string &key)
-{
- if (connection == nullptr)
- return "";
-
- const char* value = MHD_lookup_connection_value(connection, kind, key.c_str());
- if (value == nullptr)
- return "";
-
- if (StringUtils::EqualsNoCase(key, MHD_HTTP_HEADER_CONTENT_TYPE))
- {
- // Work around a bug in firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=416178)
- // by cutting of anything that follows a ";" in a "Content-Type" header field
- std::string strValue(value);
- size_t pos = strValue.find(';');
- if (pos != std::string::npos)
- strValue = strValue.substr(0, pos);
-
- return strValue;
- }
-
- return value;
-}
-
-int CWebServer::GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::map<std::string, std::string> &headerValues)
-{
- if (connection == nullptr)
- return -1;
-
- return MHD_get_connection_values(connection, kind, FillArgumentMap, &headerValues);
-}
-
-int CWebServer::GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::multimap<std::string, std::string> &headerValues)
-{
- if (connection == nullptr)
- return -1;
-
- return MHD_get_connection_values(connection, kind, FillArgumentMultiMap, &headerValues);
-}
-
-bool CWebServer::GetRequestedRanges(struct MHD_Connection *connection, uint64_t totalLength, CHttpRanges &ranges)
-{
- ranges.Clear();
-
- if (connection == nullptr)
- return false;
-
- return ranges.Parse(GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE), totalLength);
+ m_requestHandlers.erase(std::remove(m_requestHandlers.begin(), m_requestHandlers.end(), handler), m_requestHandlers.end());
}
std::string CWebServer::CreateMimeTypeFromExtension(const char *ext)
@@ -1344,37 +1230,14 @@ std::string CWebServer::CreateMimeTypeFromExtension(const char *ext)
return CMime::GetMimeType(ext);
}
-int CWebServer::AddHeader(struct MHD_Response *response, const std::string &name, const std::string &value)
+int CWebServer::AddHeader(struct MHD_Response *response, const std::string &name, const std::string &value) const
{
if (response == nullptr || name.empty())
return 0;
-#ifdef WEBSERVER_DEBUG
- CLog::Log(LOGDEBUG, "webserver [OUT] %s: %s", name.c_str(), value.c_str());
-#endif
- return MHD_add_response_header(response, name.c_str(), value.c_str());
-}
-
-bool CWebServer::GetLastModifiedDateTime(XFILE::CFile *file, CDateTime &lastModified)
-{
- if (file == nullptr)
- return false;
+ if (g_advancedSettings.CanLogComponent(LOGWEBSERVER))
+ CLog::Log(LOGDEBUG, "CWebServer[%hu] [OUT] %s: %s", m_port, name.c_str(), value.c_str());
- struct __stat64 statBuffer;
- if (file->Stat(&statBuffer) != 0)
- return false;
-
- struct tm *time;
-#ifdef HAVE_LOCALTIME_R
- struct tm result = {};
- time = localtime_r((time_t*)&statBuffer.st_mtime, &result);
-#else
- time = localtime((time_t *)&statBuffer.st_mtime);
-#endif
- if (time == nullptr)
- return false;
-
- lastModified = *time;
- return true;
+ return MHD_add_response_header(response, name.c_str(), value.c_str());
}
#endif
diff --git a/xbmc/network/WebServer.h b/xbmc/network/WebServer.h
index 19a953edaf..2f5faae10d 100644
--- a/xbmc/network/WebServer.h
+++ b/xbmc/network/WebServer.h
@@ -25,7 +25,6 @@
#include <memory>
#include <vector>
-#include "interfaces/json-rpc/ITransportLayer.h"
#include "network/httprequesthandler/IHTTPRequestHandler.h"
#include "threads/CriticalSection.h"
@@ -36,36 +35,66 @@ namespace XFILE
class CDateTime;
class CVariant;
-class CWebServer : public JSONRPC::ITransportLayer
+class CWebServer
{
public:
CWebServer();
virtual ~CWebServer() { }
- // implementation of JSONRPC::ITransportLayer
- virtual bool PrepareDownload(const char *path, CVariant &details, std::string &protocol);
- virtual bool Download(const char *path, CVariant &result);
- virtual int GetCapabilities();
-
- bool Start(int port, const std::string &username, const std::string &password);
+ bool Start(uint16_t port, const std::string &username, const std::string &password);
bool Stop();
bool IsStarted();
void SetCredentials(const std::string &username, const std::string &password);
- static void RegisterRequestHandler(IHTTPRequestHandler *handler);
- static void UnregisterRequestHandler(IHTTPRequestHandler *handler);
-
- static std::string GetRequestHeaderValue(struct MHD_Connection *connection, enum MHD_ValueKind kind, const std::string &key);
- static int GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::map<std::string, std::string> &headerValues);
- static int GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::multimap<std::string, std::string> &headerValues);
-
- static bool GetRequestedRanges(struct MHD_Connection *connection, uint64_t totalLength, CHttpRanges &ranges);
+ void RegisterRequestHandler(IHTTPRequestHandler *handler);
+ void UnregisterRequestHandler(IHTTPRequestHandler *handler);
+
+protected:
+ typedef struct ConnectionHandler
+ {
+ std::string fullUri;
+ bool isNew;
+ std::shared_ptr<IHTTPRequestHandler> requestHandler;
+ struct MHD_PostProcessor *postprocessor;
+ int errorStatus;
+
+ ConnectionHandler(const std::string& uri)
+ : fullUri(uri)
+ , isNew(true)
+ , requestHandler(nullptr)
+ , postprocessor(nullptr)
+ , errorStatus(MHD_HTTP_OK)
+ { }
+ } ConnectionHandler;
+
+ virtual void LogRequest(const char* uri) const;
+
+ virtual int HandlePartialRequest(struct MHD_Connection *connection, ConnectionHandler* connectionHandler, HTTPRequest request,
+ const char *upload_data, size_t *upload_data_size, void **con_cls);
+ virtual int HandleRequest(const std::shared_ptr<IHTTPRequestHandler>& handler);
+ virtual int FinalizeRequest(const std::shared_ptr<IHTTPRequestHandler>& handler, int responseStatus, struct MHD_Response *response);
private:
struct MHD_Daemon* StartMHD(unsigned int flags, int port);
- static int AskForAuthentication (struct MHD_Connection *connection);
- static bool IsAuthenticated (CWebServer *server, struct MHD_Connection *connection);
+ int AskForAuthentication(struct MHD_Connection *connection) const;
+ bool IsAuthenticated(struct MHD_Connection *connection) const;
+
+ int CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const;
+ int CreateRangedMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const;
+
+ int CreateRedirect(struct MHD_Connection *connection, const std::string &strURL, struct MHD_Response *&response) const;
+ int CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response) const;
+ int CreateErrorResponse(struct MHD_Connection *connection, int responseType, HTTPMethod method, struct MHD_Response *&response) const;
+ int CreateMemoryDownloadResponse(struct MHD_Connection *connection, const void *data, size_t size, bool free, bool copy, struct MHD_Response *&response) const;
+
+ int SendErrorResponse(struct MHD_Connection *connection, int errorType, HTTPMethod method) const;
+
+ int AddHeader(struct MHD_Response *response, const std::string &name, const std::string &value) const;
+
+ static std::string CreateMimeTypeFromExtension(const char *ext);
+
+ // MHD callback implementations
static void* UriRequestLogger(void *cls, const char *uri);
#if (MHD_VERSION >= 0x00090200)
@@ -96,28 +125,8 @@ private:
const char *transfer_encoding, const char *data, uint64_t off,
unsigned int size);
#endif
- static int HandleRequest(const std::shared_ptr<IHTTPRequestHandler>& handler);
- static int FinalizeRequest(const std::shared_ptr<IHTTPRequestHandler>& handler, int responseStatus, struct MHD_Response *response);
-
- static int CreateMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response);
- static int CreateRangedMemoryDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response);
-
- static int CreateRedirect(struct MHD_Connection *connection, const std::string &strURL, struct MHD_Response *&response);
- static int CreateFileDownloadResponse(const std::shared_ptr<IHTTPRequestHandler>& handler, struct MHD_Response *&response);
- static int CreateErrorResponse(struct MHD_Connection *connection, int responseType, HTTPMethod method, struct MHD_Response *&response);
- static int CreateMemoryDownloadResponse(struct MHD_Connection *connection, const void *data, size_t size, bool free, bool copy, struct MHD_Response *&response);
-
- static int SendErrorResponse(struct MHD_Connection *connection, int errorType, HTTPMethod method);
-
- static HTTPMethod GetMethod(const char *method);
- static int FillArgumentMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value);
- static int FillArgumentMultiMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value);
-
- static std::string CreateMimeTypeFromExtension(const char *ext);
-
- static int AddHeader(struct MHD_Response *response, const std::string &name, const std::string &value);
- static bool GetLastModifiedDateTime(XFILE::CFile *file, CDateTime &lastModified);
+ uint16_t m_port;
struct MHD_Daemon *m_daemon_ip6;
struct MHD_Daemon *m_daemon_ip4;
bool m_running;
@@ -125,6 +134,6 @@ private:
size_t m_thread_stacksize;
std::string m_Credentials64Encoded;
CCriticalSection m_critSection;
- static std::vector<IHTTPRequestHandler *> m_requestHandlers;
+ std::vector<IHTTPRequestHandler *> m_requestHandlers;
};
#endif
diff --git a/xbmc/network/httprequesthandler/CMakeLists.txt b/xbmc/network/httprequesthandler/CMakeLists.txt
index eb5523b529..885bf96683 100644
--- a/xbmc/network/httprequesthandler/CMakeLists.txt
+++ b/xbmc/network/httprequesthandler/CMakeLists.txt
@@ -3,6 +3,7 @@ set(SOURCES HTTPFileHandler.cpp
HTTPImageTransformationHandler.cpp
HTTPJsonRpcHandler.cpp
HTTPPythonHandler.cpp
+ HTTPRequestHandlerUtils.cpp
HTTPVfsHandler.cpp
HTTPWebinterfaceAddonsHandler.cpp
HTTPWebinterfaceHandler.cpp
@@ -13,6 +14,7 @@ set(HEADERS HTTPFileHandler.h
HTTPImageTransformationHandler.h
HTTPJsonRpcHandler.h
HTTPPythonHandler.h
+ HTTPRequestHandlerUtils.h
HTTPVfsHandler.h
HTTPWebinterfaceAddonsHandler.h
HTTPWebinterfaceHandler.h
diff --git a/xbmc/network/httprequesthandler/HTTPImageTransformationHandler.cpp b/xbmc/network/httprequesthandler/HTTPImageTransformationHandler.cpp
index b00c760640..51040daa61 100644
--- a/xbmc/network/httprequesthandler/HTTPImageTransformationHandler.cpp
+++ b/xbmc/network/httprequesthandler/HTTPImageTransformationHandler.cpp
@@ -25,6 +25,7 @@
#include "URL.h"
#include "filesystem/ImageFile.h"
#include "network/WebServer.h"
+#include "network/httprequesthandler/HTTPRequestHandlerUtils.h"
#include "utils/Mime.h"
#include "utils/StringUtils.h"
#include "utils/URIUtils.h"
@@ -109,7 +110,7 @@ bool CHTTPImageTransformationHandler::CanHandleRequest(const HTTPRequest &reques
// get the transformation options
std::map<std::string, std::string> options;
- CWebServer::GetRequestHeaderValues(request.connection, MHD_GET_ARGUMENT_KIND, options);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(request.connection, MHD_GET_ARGUMENT_KIND, options);
return (options.find(TRANSFORMATION_OPTION_WIDTH) != options.end() ||
options.find(TRANSFORMATION_OPTION_HEIGHT) != options.end());
@@ -131,7 +132,7 @@ int CHTTPImageTransformationHandler::HandleRequest()
// get the transformation options
std::map<std::string, std::string> options;
- CWebServer::GetRequestHeaderValues(m_request.connection, MHD_GET_ARGUMENT_KIND, options);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(m_request.connection, MHD_GET_ARGUMENT_KIND, options);
std::vector<std::string> urlOptions;
std::map<std::string, std::string>::const_iterator option = options.find(TRANSFORMATION_OPTION_WIDTH);
diff --git a/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.cpp b/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.cpp
index d922ef4191..3a604bc4b3 100644
--- a/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.cpp
+++ b/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.cpp
@@ -19,10 +19,13 @@
*/
#include "HTTPJsonRpcHandler.h"
+#include "URL.h"
+#include "filesystem/File.h"
#include "interfaces/json-rpc/JSONRPC.h"
#include "interfaces/json-rpc/JSONServiceDescription.h"
#include "interfaces/json-rpc/JSONUtils.h"
#include "network/WebServer.h"
+#include "network/httprequesthandler/HTTPRequestHandlerUtils.h"
#include "utils/JSONVariantWriter.h"
#include "utils/log.h"
#include "utils/Variant.h"
@@ -42,11 +45,11 @@ int CHTTPJsonRpcHandler::HandleRequest()
// get all query arguments
std::map<std::string, std::string> arguments;
- CWebServer::GetRequestHeaderValues(m_request.connection, MHD_GET_ARGUMENT_KIND, arguments);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(m_request.connection, MHD_GET_ARGUMENT_KIND, arguments);
if (m_request.method == POST)
{
- std::string contentType = CWebServer::GetRequestHeaderValue(m_request.connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
+ std::string contentType = HTTPRequestHandlerUtils::GetRequestHeaderValue(m_request.connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_CONTENT_TYPE);
// If the content-type of the m_request was specified, it must be application/json-rpc, application/json, or application/jsonrequest
// http://www.jsonrpc.org/historical/json-rpc-over-http.html
if (!contentType.empty() && contentType.compare("application/json-rpc") != 0 &&
@@ -81,7 +84,7 @@ int CHTTPJsonRpcHandler::HandleRequest()
if (isRequest)
{
- m_responseData = JSONRPC::CJSONRPC::MethodCall(m_requestData, m_request.webserver, &client);
+ m_responseData = JSONRPC::CJSONRPC::MethodCall(m_requestData, &m_transportLayer, &client);
if (!jsonpCallback.empty())
m_responseData = jsonpCallback + "(" + m_responseData + ");";
@@ -90,7 +93,7 @@ int CHTTPJsonRpcHandler::HandleRequest()
{
// get the whole output of JSONRPC.Introspect
CVariant result;
- JSONRPC::CJSONServiceDescription::Print(result, m_request.webserver, &client);
+ JSONRPC::CJSONServiceDescription::Print(result, &m_transportLayer, &client);
m_responseData = CJSONVariantWriter::Write(result, false);
}
else
@@ -138,6 +141,35 @@ bool CHTTPJsonRpcHandler::appendPostData(const char *data, unsigned int size)
return true;
}
+bool CHTTPJsonRpcHandler::CHTTPTransportLayer::PrepareDownload(const char *path, CVariant &details, std::string &protocol)
+{
+ if (!XFILE::CFile::Exists(path))
+ return false;
+
+ protocol = "http";
+ std::string url;
+ std::string strPath = path;
+ if (StringUtils::StartsWith(strPath, "image://") ||
+ (StringUtils::StartsWith(strPath, "special://") && StringUtils::EndsWith(strPath, ".tbn")))
+ url = "image/";
+ else
+ url = "vfs/";
+ url += CURL::Encode(strPath);
+ details["path"] = url;
+
+ return true;
+}
+
+bool CHTTPJsonRpcHandler::CHTTPTransportLayer::Download(const char *path, CVariant &result)
+{
+ return false;
+}
+
+int CHTTPJsonRpcHandler::CHTTPTransportLayer::GetCapabilities()
+{
+ return JSONRPC::Response | JSONRPC::FileDownloadRedirect;
+}
+
int CHTTPJsonRpcHandler::CHTTPClient::GetPermissionFlags()
{
return JSONRPC::OPERATION_PERMISSION_ALL;
diff --git a/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.h b/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.h
index c4287eaf1b..273f925b2b 100644
--- a/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.h
+++ b/xbmc/network/httprequesthandler/HTTPJsonRpcHandler.h
@@ -22,6 +22,7 @@
#include <string>
#include "interfaces/json-rpc/IClient.h"
+#include "interfaces/json-rpc/ITransportLayer.h"
#include "network/httprequesthandler/IHTTPRequestHandler.h"
class CHTTPJsonRpcHandler : public IHTTPRequestHandler
@@ -30,6 +31,7 @@ public:
CHTTPJsonRpcHandler() { }
virtual ~CHTTPJsonRpcHandler() { }
+ // implementations of IHTTPRequestHandler
virtual IHTTPRequestHandler* Create(const HTTPRequest &request) { return new CHTTPJsonRpcHandler(request); }
virtual bool CanHandleRequest(const HTTPRequest &request);
@@ -55,6 +57,19 @@ private:
std::string m_responseData;
CHttpResponseRange m_responseRange;
+ class CHTTPTransportLayer : public JSONRPC::ITransportLayer
+ {
+ public:
+ CHTTPTransportLayer() = default;
+ ~CHTTPTransportLayer() = default;
+
+ // implementations of JSONRPC::ITransportLayer
+ bool PrepareDownload(const char *path, CVariant &details, std::string &protocol) override;
+ bool Download(const char *path, CVariant &result) override;
+ int GetCapabilities() override;
+ };
+ CHTTPTransportLayer m_transportLayer;
+
class CHTTPClient : public JSONRPC::IClient
{
public:
diff --git a/xbmc/network/httprequesthandler/HTTPPythonHandler.cpp b/xbmc/network/httprequesthandler/HTTPPythonHandler.cpp
index a37a760d5d..58dc8010bf 100644
--- a/xbmc/network/httprequesthandler/HTTPPythonHandler.cpp
+++ b/xbmc/network/httprequesthandler/HTTPPythonHandler.cpp
@@ -25,6 +25,7 @@
#include "interfaces/python/XBPython.h"
#include "filesystem/File.h"
#include "network/WebServer.h"
+#include "network/httprequesthandler/HTTPRequestHandlerUtils.h"
#include "network/httprequesthandler/HTTPWebinterfaceHandler.h"
#include "network/httprequesthandler/python/HTTPPythonInvoker.h"
#include "network/httprequesthandler/python/HTTPPythonWsgiInvoker.h"
@@ -136,8 +137,8 @@ int CHTTPPythonHandler::HandleRequest()
HTTPPythonRequest* pythonRequest = new HTTPPythonRequest();
pythonRequest->connection = m_request.connection;
pythonRequest->file = URIUtils::GetFileName(m_request.pathUrl);
- CWebServer::GetRequestHeaderValues(m_request.connection, MHD_GET_ARGUMENT_KIND, pythonRequest->getValues);
- CWebServer::GetRequestHeaderValues(m_request.connection, MHD_HEADER_KIND, pythonRequest->headerValues);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(m_request.connection, MHD_GET_ARGUMENT_KIND, pythonRequest->getValues);
+ HTTPRequestHandlerUtils::GetRequestHeaderValues(m_request.connection, MHD_HEADER_KIND, pythonRequest->headerValues);
pythonRequest->method = m_request.method;
pythonRequest->postValues = m_postFields;
pythonRequest->requestContent = m_requestData;
diff --git a/xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.cpp b/xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.cpp
new file mode 100644
index 0000000000..35a031aa10
--- /dev/null
+++ b/xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2016 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <map>
+
+#include "HTTPRequestHandlerUtils.h"
+#include "utils/StringUtils.h"
+
+std::string HTTPRequestHandlerUtils::GetRequestHeaderValue(struct MHD_Connection *connection, enum MHD_ValueKind kind, const std::string &key)
+{
+ if (connection == nullptr)
+ return "";
+
+ const char* value = MHD_lookup_connection_value(connection, kind, key.c_str());
+ if (value == nullptr)
+ return "";
+
+ if (StringUtils::EqualsNoCase(key, MHD_HTTP_HEADER_CONTENT_TYPE))
+ {
+ // Work around a bug in firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=416178)
+ // by cutting of anything that follows a ";" in a "Content-Type" header field
+ std::string strValue(value);
+ size_t pos = strValue.find(';');
+ if (pos != std::string::npos)
+ strValue = strValue.substr(0, pos);
+
+ return strValue;
+ }
+
+ return value;
+}
+
+int HTTPRequestHandlerUtils::GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::map<std::string, std::string> &headerValues)
+{
+ if (connection == nullptr)
+ return -1;
+
+ return MHD_get_connection_values(connection, kind, FillArgumentMap, &headerValues);
+}
+
+int HTTPRequestHandlerUtils::GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::multimap<std::string, std::string> &headerValues)
+{
+ if (connection == nullptr)
+ return -1;
+
+ return MHD_get_connection_values(connection, kind, FillArgumentMultiMap, &headerValues);
+}
+
+bool HTTPRequestHandlerUtils::GetRequestedRanges(struct MHD_Connection *connection, uint64_t totalLength, CHttpRanges &ranges)
+{
+ ranges.Clear();
+
+ if (connection == nullptr)
+ return false;
+
+ return ranges.Parse(GetRequestHeaderValue(connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_RANGE), totalLength);
+}
+
+int HTTPRequestHandlerUtils::FillArgumentMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
+{
+ if (cls == nullptr || key == nullptr)
+ return MHD_NO;
+
+ std::map<std::string, std::string> *arguments = reinterpret_cast<std::map<std::string, std::string>*>(cls);
+ arguments->insert(std::make_pair(key, value != nullptr ? value : ""));
+
+ return MHD_YES;
+}
+
+int HTTPRequestHandlerUtils::FillArgumentMultiMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value)
+{
+ if (cls == nullptr || key == nullptr)
+ return MHD_NO;
+
+ std::multimap<std::string, std::string> *arguments = reinterpret_cast<std::multimap<std::string, std::string>*>(cls);
+ arguments->insert(std::make_pair(key, value != nullptr ? value : ""));
+
+ return MHD_YES;
+}
diff --git a/xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.h b/xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.h
new file mode 100644
index 0000000000..2336f4d706
--- /dev/null
+++ b/xbmc/network/httprequesthandler/HTTPRequestHandlerUtils.h
@@ -0,0 +1,41 @@
+#pragma once
+/*
+ * Copyright (C) 2016 Team XBMC
+ * http://xbmc.org
+ *
+ * This Program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This Program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with XBMC; see the file COPYING. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <stdint.h>
+#include <string>
+
+#include "network/httprequesthandler/IHTTPRequestHandler.h"
+
+class HTTPRequestHandlerUtils
+{
+public:
+ static std::string GetRequestHeaderValue(struct MHD_Connection *connection, enum MHD_ValueKind kind, const std::string &key);
+ static int GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::map<std::string, std::string> &headerValues);
+ static int GetRequestHeaderValues(struct MHD_Connection *connection, enum MHD_ValueKind kind, std::multimap<std::string, std::string> &headerValues);
+
+ static bool GetRequestedRanges(struct MHD_Connection *connection, uint64_t totalLength, CHttpRanges &ranges);
+
+private:
+ HTTPRequestHandlerUtils() = delete;
+
+ static int FillArgumentMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value);
+ static int FillArgumentMultiMap(void *cls, enum MHD_ValueKind kind, const char *key, const char *value);
+};
diff --git a/xbmc/network/httprequesthandler/IHTTPRequestHandler.cpp b/xbmc/network/httprequesthandler/IHTTPRequestHandler.cpp
index 3d3571d429..9b611ad269 100644
--- a/xbmc/network/httprequesthandler/IHTTPRequestHandler.cpp
+++ b/xbmc/network/httprequesthandler/IHTTPRequestHandler.cpp
@@ -19,12 +19,45 @@
*/
#include <limits>
+#include <utility>
#include "IHTTPRequestHandler.h"
#include "network/WebServer.h"
+#include "network/httprequesthandler/HTTPRequestHandlerUtils.h"
#include "utils/StringUtils.h"
-#include <utility>
+static const std::string HTTPMethodHead = "HEAD";
+static const std::string HTTPMethodGet = "GET";
+static const std::string HTTPMethodPost = "POST";
+
+HTTPMethod GetHTTPMethod(const char *method)
+{
+ if (HTTPMethodGet.compare(method) == 0)
+ return GET;
+ if (HTTPMethodPost.compare(method) == 0)
+ return POST;
+ if (HTTPMethodHead.compare(method) == 0)
+ return HEAD;
+
+ return UNKNOWN;
+}
+
+std::string GetHTTPMethod(HTTPMethod method)
+{
+ switch (method)
+ {
+ case HEAD:
+ return HTTPMethodHead;
+
+ case GET:
+ return HTTPMethodGet;
+
+ case POST:
+ return HTTPMethodPost;
+ }
+
+ return "";
+}
IHTTPRequestHandler::IHTTPRequestHandler()
: m_request(),
@@ -97,7 +130,7 @@ bool IHTTPRequestHandler::GetRequestedRanges(uint64_t totalLength)
if (totalLength == 0)
return true;
- return m_request.webserver->GetRequestedRanges(m_request.connection, totalLength, m_request.ranges);
+ return HTTPRequestHandlerUtils::GetRequestedRanges(m_request.connection, totalLength, m_request.ranges);
}
bool IHTTPRequestHandler::GetHostnameAndPort(std::string& hostname, uint16_t &port)
@@ -105,7 +138,7 @@ bool IHTTPRequestHandler::GetHostnameAndPort(std::string& hostname, uint16_t &po
if (m_request.webserver == NULL || m_request.connection == NULL)
return false;
- std::string hostnameAndPort = m_request.webserver->GetRequestHeaderValue(m_request.connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST);
+ std::string hostnameAndPort = HTTPRequestHandlerUtils::GetRequestHeaderValue(m_request.connection, MHD_HEADER_KIND, MHD_HTTP_HEADER_HOST);
if (hostnameAndPort.empty())
return false;
diff --git a/xbmc/network/httprequesthandler/IHTTPRequestHandler.h b/xbmc/network/httprequesthandler/IHTTPRequestHandler.h
index e25dc441a5..40bd7d8c55 100644
--- a/xbmc/network/httprequesthandler/IHTTPRequestHandler.h
+++ b/xbmc/network/httprequesthandler/IHTTPRequestHandler.h
@@ -44,6 +44,9 @@ enum HTTPMethod
HEAD
};
+HTTPMethod GetHTTPMethod(const char *method);
+std::string GetHTTPMethod(HTTPMethod method);
+
typedef enum HTTPResponseType
{
HTTPNone,
diff --git a/xbmc/network/httprequesthandler/Makefile b/xbmc/network/httprequesthandler/Makefile
index f150729e16..bcc57be5b4 100644
--- a/xbmc/network/httprequesthandler/Makefile
+++ b/xbmc/network/httprequesthandler/Makefile
@@ -3,6 +3,7 @@ SRCS=HTTPFileHandler.cpp \
HTTPImageTransformationHandler.cpp \
HTTPJsonRpcHandler.cpp \
HTTPPythonHandler.cpp \
+ HTTPRequestHandlerUtils.cpp \
HTTPVfsHandler.cpp \
HTTPWebinterfaceAddonsHandler.cpp \
HTTPWebinterfaceHandler.cpp \
diff --git a/xbmc/network/test/TestWebServer.cpp b/xbmc/network/test/TestWebServer.cpp
index f27a4030ef..09ff4136d8 100644
--- a/xbmc/network/test/TestWebServer.cpp
+++ b/xbmc/network/test/TestWebServer.cpp
@@ -28,6 +28,10 @@
#include "filesystem/File.h"
#include "interfaces/json-rpc/JSONRPC.h"
#include "network/WebServer.h"
+#include "network/httprequesthandler/HTTPVfsHandler.h"
+#ifdef HAS_JSONRPC
+#include "network/httprequesthandler/HTTPJsonRpcHandler.h"
+#endif // HAS_JSONRPC
#include "settings/MediaSourceSettings.h"
#include "test/TestUtils.h"
#include "utils/JSONVariantParser.h"
@@ -63,6 +67,8 @@ protected:
SetupMediaSources();
webserver.Start(WEBSERVER_PORT, "", "");
+ webserver.RegisterRequestHandler(&m_jsonRpcHandler);
+ webserver.RegisterRequestHandler(&m_vfsHandler);
}
virtual void TearDown()
@@ -70,6 +76,9 @@ protected:
if (webserver.IsStarted())
webserver.Stop();
+ webserver.UnregisterRequestHandler(&m_vfsHandler);
+ webserver.UnregisterRequestHandler(&m_jsonRpcHandler);
+
TearDownMediaSources();
}
@@ -331,6 +340,8 @@ protected:
}
CWebServer webserver;
+ CHTTPJsonRpcHandler m_jsonRpcHandler;
+ CHTTPVfsHandler m_vfsHandler;
std::string baseUrl;
std::string sourcePath;
};
diff --git a/xbmc/settings/AdvancedSettings.cpp b/xbmc/settings/AdvancedSettings.cpp
index 7788f0af03..edd7d3d1e6 100644
--- a/xbmc/settings/AdvancedSettings.cpp
+++ b/xbmc/settings/AdvancedSettings.cpp
@@ -1335,6 +1335,9 @@ void CAdvancedSettings::SettingOptionsLoggingComponentsFiller(const CSetting *se
#ifdef HAS_JSONRPC
list.push_back(std::make_pair(g_localizeStrings.Get(675), LOGJSONRPC));
#endif
+#ifdef HAS_WEB_SERVER
+ list.push_back(std::make_pair(g_localizeStrings.Get(681), LOGWEBSERVER));
+#endif
#ifdef HAS_AIRTUNES
list.push_back(std::make_pair(g_localizeStrings.Get(677), LOGAIRTUNES));
#endif