Skip to content

Loading…

Webserver: add access to special:// URLs #2443

Closed
wants to merge 3 commits into from

9 participants

@wsnipex
Team Kodi member

This adds a new HTTP handler allowing for special:// vfs files.
Access works analog to VFS via http://xbmchost:port/special/special://path/to/file
It also adds a shortcut URL /log for quick and easy xbmc.log downloading.

.log and .xml files are passed through a User/Pass stripper before download:

  • username:pass in URIs
  • pass in XMLs

I added VS2010 project files, but did not test them.
Since Xcode stuff is voodoo to me, I kindly ask someone in the know to help there.

@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/Makefile
@@ -4,6 +4,7 @@ SRCS=HTTPImageHandler.cpp \
HTTPWebinterfaceAddonsHandler.cpp \
HTTPWebinterfaceHandler.cpp \
IHTTPRequestHandler.cpp \
+ HTTPSpecialHandler.cpp \
@Montellese Team Kodi member

This list should be alphabetically ordered so please add your new entry where it belongs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((45 lines not shown))
+ if (request.url.substr(0, 19) == "/special/special://")
+ {
+ m_path = request.url.substr(9);
+ ext = URIUtils::GetExtension(request.url);
+ ext = ext.ToLower();
+ }
+ /* add a shortcut URL /log[?] pointing to xbmc.log */
+ else if (request.url.substr(0, 4) == "/log" && request.url.size() <= 5)
+ {
+ m_path = "special://temp/xbmc.log";
+ ext = ".log";
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: bad request");
+ m_response = "400 Bad Request";
@Montellese Team Kodi member

No need to set a response here as it won't be used anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((37 lines not shown))
+}
+
+int CHTTPSpecialHandler::HandleHTTPRequest(const HTTPRequest &request)
+{
+ CStdString ext;
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: RequestUrl %s", request.url.c_str());
+
+ /* our URL is /special */
+ if (request.url.substr(0, 19) == "/special/special://")
+ {
+ m_path = request.url.substr(9);
+ ext = URIUtils::GetExtension(request.url);
+ ext = ext.ToLower();
+ }
+ /* add a shortcut URL /log[?] pointing to xbmc.log */
+ else if (request.url.substr(0, 4) == "/log" && request.url.size() <= 5)
@Montellese Team Kodi member

So "/log7" is a valid URL for accessing the xbmc log? ;-)

@wsnipex Team Kodi member
wsnipex added a note

yes ;) it was easier then to test if its /log /logs or /log/

@Montellese Team Kodi member

Easier and not 100% correct ;-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.h
((27 lines not shown))
+public:
+ CHTTPSpecialHandler() { };
+
+ virtual IHTTPRequestHandler* GetInstance() { return new CHTTPSpecialHandler(); }
+ virtual bool CheckHTTPRequest(const HTTPRequest &request);
+ virtual int HandleHTTPRequest(const HTTPRequest &request);
+
+ virtual std::string GetHTTPResponseFile() const { return m_path; }
+ static int ResolveUrl(const std::string &url, std::string &path);
+ virtual void* GetHTTPResponseData() const { return (void *)m_response.c_str(); };
+ virtual size_t GetHTTPResonseDataLength() const { return m_response.length(); }
+
+ virtual int GetPriority() const { return 2; }
+
+private:
+ CStdString m_path;
@Montellese Team Kodi member

Any reason why they have to be CStdString objects? Personally I prefer std::string wherever possible (will also save you the StdString.h include) and you're using std::string almost everywhere in the implementation anyways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((61 lines not shown))
+ m_responseCode = MHD_HTTP_BAD_REQUEST;
+ m_responseType = HTTPError;
+ return MHD_YES;
+ }
+
+ XFILE::CFile *file = new XFILE::CFile();
+ if (XFILE::CFile::Exists(m_path) && m_path.substr(m_path.length()-1, 1) != "/" && file->Open(m_path, READ_CACHED))
+ {
+ /* If we have a file that potentially holds user credentials
+ * we want to sanitize them.
+ * Else have the webserver handle the download */
+ if (ext == ".log" || ext == ".xml")
+ {
+ m_response = "";
+ char m_buf[1024];
+ memset(m_buf,'\0',sizeof(m_buf));
@Montellese Team Kodi member

cosmetics: spaces after the commas makes it easier to read.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((7 lines not shown))
+ * 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 "HTTPSpecialHandler.h"
+#include "MediaSource.h"
@Montellese Team Kodi member

I don't think you'll need this include right?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((11 lines not shown))
+ * 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 "HTTPSpecialHandler.h"
+#include "MediaSource.h"
+#include "URL.h"
+#include "filesystem/File.h"
+#include "network/WebServer.h"
+#include "settings/Settings.h"
@Montellese Team Kodi member

You shouldn't need this one either.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((51 lines not shown))
+ /* add a shortcut URL /log[?] pointing to xbmc.log */
+ else if (request.url.substr(0, 4) == "/log" && request.url.size() <= 5)
+ {
+ m_path = "special://temp/xbmc.log";
+ ext = ".log";
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: bad request");
+ m_response = "400 Bad Request";
+ m_responseCode = MHD_HTTP_BAD_REQUEST;
+ m_responseType = HTTPError;
+ return MHD_YES;
+ }
+
+ XFILE::CFile *file = new XFILE::CFile();
@Montellese Team Kodi member

As I already told you I'd prefer if you changed the order of the logic.
1. Check if the file exists (you don't need the CFile instance for that yet). If not, set the error to MHD_HTTP_NOT_FOUND and return.
2. Check if you have a .log or a .xml file. If no, go to #3, otherwise go to #4.
3. As you don't need to run the password removal stuff, save the path of the file and set HTTPFileDownload as the response type and return.
4. As you need to run the password removal stuff, you can now create the CFile instance and open the file for reading and whatever other magic you perform.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((82 lines not shown))
+ /* this replaces the following:
+ * - username:pass in URIs
+ * - <pass>pass</pass> in XMLs
+ */
+ CRegExp regex1, regex2;
+ regex1.RegComp("://(.*):(.*)@");
+ regex2.RegComp("<[^<>]*pass[^<>]*>([^<]+)</.*pass.*>");
+
+ while (file->ReadString(m_buf, 1023))
+ {
+ line = m_buf;
+ if (regex1.RegFind(line))
+ {
+ user = regex1.GetReplaceString("\\1");
+ pass = regex1.GetReplaceString("\\2");
+ replace = string("://") + string(user) + ":" + string(pass) + "@";
@Montellese Team Kodi member

Do you really need the string() around "://" etc? concatenating const char* with string should be possible. Especially "string(user)" and "string(pass)" don't make sense as "user" and "pass" already are of type string.

@wsnipex Team Kodi member
wsnipex added a note

the string around "://" was a hint I got from someone on IRC, to make sure its a string. It might not be needed, but does it hurt? I will remove the other two, as they are certainly not needed and are a remnant of me chasing the cut off string.

@Montellese Team Kodi member

Well it's certainly not wrong but IMO unnecessary and confused me for a second.

@ghost
ghost added a note

char* + string is well defined to you? for me, only string+char* is.

@Montellese Team Kodi member

As long as it compiles, it's well enough defined for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((92 lines not shown))
+ line = m_buf;
+ if (regex1.RegFind(line))
+ {
+ user = regex1.GetReplaceString("\\1");
+ pass = regex1.GetReplaceString("\\2");
+ replace = string("://") + string(user) + ":" + string(pass) + "@";
+ StringUtils::Replace(line, replace, "://xxx:xxx@");
+ }
+ if (regex2.RegFind(line))
+ {
+ replace = regex2.GetReplaceString("\\1");
+ if (replace.length() > 0)
+ StringUtils::Replace(line, replace, "xxx");
+ }
+ m_response += line;
+ memset(m_buf,'\0',sizeof(m_buf));
@Montellese Team Kodi member

cosmetics: spaces after the commas.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((26 lines not shown))
+#include "settings/Settings.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+#include "utils/RegExp.h"
+#include "utils/StringUtils.h"
+
+using namespace std;
+
+bool CHTTPSpecialHandler::CheckHTTPRequest(const HTTPRequest &request)
+{
+ return (request.url.find("/special/") == 0 || request.url.find("/log") == 0);
+}
+
+int CHTTPSpecialHandler::HandleHTTPRequest(const HTTPRequest &request)
+{
+ CStdString ext;
@Montellese Team Kodi member

Could be turned into a std::string by using StringUtils::ToLower() on line 49. Then you/we don't need CStdString in this implementation at all.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese
Team Kodi member

The general implementation looks good and something a lot of people have asked for. Just a few things to improve.

@MartijnKaijser MartijnKaijser commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2011-2013 Team XBMC
@MartijnKaijser Team Kodi member

cosmetics. since it's a new file i think 2011-2013 should just be 2013.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@t-nelson

Aside from easy log access, what do we need this feature for? While it does clean up credentials, there may be URLs/paths you just don't want people having access to (private stuff, porn, etc.). IMO there are still plenty of security and privacy issues at bay here.

@wsnipex
Team Kodi member

implemented the suggested changes. Also added filtering of username in xml tags

@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((43 lines not shown))
+ if (request.url.substr(0, 19) == "/special/special://")
+ {
+ m_path = request.url.substr(9);
+ ext = URIUtils::GetExtension(request.url);
+ StringUtils::ToLower(ext);
+
+ if (! XFILE::CFile::Exists(m_path))
+ {
+ CLog::Log(LOGERROR, "CHTTPSpecialHandler::HandleHTTPRequest: file %s does not exist", m_path.c_str());
+ m_responseCode = MHD_HTTP_NOT_FOUND;
+ m_responseType = HTTPError;
+ return MHD_YES;
+ }
+ }
+ /* add a shortcut URL /log and /log/ pointing to xbmc.log */
+ else if ((request.url.substr(0, 4) == "/log" && request.url.size() == 4)
@Montellese Team Kodi member

Why don't you just do a string comparison against "/log" and "/log/"?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((25 lines not shown))
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+#include "utils/RegExp.h"
+#include "utils/StringUtils.h"
+
+using namespace std;
+
+bool CHTTPSpecialHandler::CheckHTTPRequest(const HTTPRequest &request)
+{
+ return (request.url.find("/special/") == 0 || request.url.find("/log") == 0);
+}
+
+int CHTTPSpecialHandler::HandleHTTPRequest(const HTTPRequest &request)
+{
+ string ext;
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: RequestUrl %s", request.url.c_str());
@Montellese Team Kodi member

We already have a log output for every incoming HTTP request so this one shouldn't be needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese Montellese commented on an outdated diff
xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
((34 lines not shown))
+ return (request.url.find("/special/") == 0 || request.url.find("/log") == 0);
+}
+
+int CHTTPSpecialHandler::HandleHTTPRequest(const HTTPRequest &request)
+{
+ string ext;
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: RequestUrl %s", request.url.c_str());
+
+ /* our URL is /special */
+ if (request.url.substr(0, 19) == "/special/special://")
+ {
+ m_path = request.url.substr(9);
+ ext = URIUtils::GetExtension(request.url);
+ StringUtils::ToLower(ext);
+
+ if (! XFILE::CFile::Exists(m_path))
@Montellese Team Kodi member

small cosmetic between ! and XFILE.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
@Montellese
Team Kodi member

Looks much better. Just a few small things and then the code is good IMO.

I don't really have a strong opinion on what @t-nelson said because I have nothing to hide in my local network.

@Montellese
Team Kodi member

Thanks, code looks good now for me.

@Montellese
Team Kodi member

Looking over the commit order I'm a bit confused. Is it just github showing the commits in the wrong order or are they actually in the wrong order? Shouldn't it be
1. [webserver] add HTTPSpecialHandler
2. register CHTTPSpecialHandler
3. add HTTPSpecialHandler to vcxproj

Actually 1 and 2 could be squashed down. As you'll have to rebase anyway, it would be nice if you could add a "[win32] in front of the "add HTTPSpecialHandler to vcxproj" commit message to make it more obvious.

This will also need some xcode monkeying when merged.

@wsnipex
Team Kodi member

its very possible that I changed the order around while rebasing/squashing the last time. Would it really make a difference though?

I did squash those two down as requested and rebased again.

I'm aware that Xcode stuff is missing, thats why I asked for help with that in the PR description ;)

@Montellese
Team Kodi member

Thanks. Will if the commits are in the wrong order, the code won't compile for each commit. Usually the order wouldn't matter but if you e.g. bisect to find a bug and you end up between those commits you can't really check if that revision works because you can't compile it.

@wsnipex
Team Kodi member
@NedScott

@t-nelson From what I can see, there are multiple troubleshooting situations where accessing files (and more than just xbmc.log) could be useful in this case. More and more, we have situations where it's not entirely clear where users can look at and check these files (android seems to have a few variations for the userdata folder, for example). In that sense, I would say this would be a troubleshooting "mode" for many. I love the idea of being able to do this, and can see it making a lot of situations easier to troubleshoot.

@wsnipex Forgive me, as I'm not a programmer and am not able to tell from the commits, but I assume there's a way to turn special protocol access on or off? One that defaults to off? I also know everyone cringes at GUI settings additions, but if there is a setting for this, I think it should be in the GUI (if you can't find xbmc.log, then you probably can't find advancedsettings.xml).

@t-nelson

@NedScott clearly I'm aware of what it's useful for. My concern is whether it's useful enough to risk a gaping hole in security. My comment was mainly ensure this had been considered.

@wsnipex
Team Kodi member

I don't see a gaping hole. You can always enable user/pass for the webserver. Also most users, me included don't have anything to hide on their own LAN

@arnova
Team Kodi member

Ah so potentionally rendering your router's firewall useless doesn't matter?! It's your first line of defense...

@wsnipex
Team Kodi member

I don't follow. What has xbmcs webserver to do with your router?

@NedScott

I believe the security concern is valid. This needs a switch, and it needs to be off by default.

@wsnipex
Team Kodi member

which security issues are we talking about exactly? If there is more data to be sanitized, I'd be happy to do so, but I won't implement a gui option.

@NedScott

Off the top of my head, addon_data. Some add-ons store plain text passwords for log-ins in various ways. The log file itself tells everyone on the network what you're watching and when, which is more a privacy concern than a computer security concern, but still an issue for some users.

I think this would be a bad idea if there was no way to turn it off.

@wsnipex
Team Kodi member

You can turn it off, turn off the webserver. I really do not understand the issue here. The webserver can be password protected....

edit: @NedScott plz provide concrete examples

@NedScott

I could provide specific examples of add-ons storing passwords in different ways, but we can't predict them all. Password protecting the webserver is a valid point, but I'm still unsure why file access can't be disabled separately. I doubt most people would think to use a password on the webserver, or would be aware of what they are exposing on their local network. I'm certainly no network expert, so maybe it's nothing to be worried about.

@t-nelson
@wsnipex
Team Kodi member

Since depending on "debugging enabled via Gui setting" would defy most of the usefulness, I added a gui setting to enable access to special:// urls

@t-nelson
@arnova
Team Kodi member

A GUI setting for this: no way...

@wsnipex
Team Kodi member

I never enable debugging via Gui setting, only via advancedsettings, because I hate the overlay.
So either "if debug logging is enabled" or a Gui setting for this or always enabled.

You guys were lamenting about the "huge security risk", so a GUI setting is the correct solution.

@elupus
Team Kodi member

I'm for the enablement by the debug gui setting since it shows that you are running in a non standard mode. If we where to accept a GUI setting it would also need to indicate that it's a security risk doing so. User would have no idea that it was with the current title of this setting.

@wsnipex
Team Kodi member

then what do you suggest for the settings text?
again the debug gui setting is useless to me and many users.

@jmarshallnz
Team Kodi member

If the issue is just wanting to expose the log to the network, then why not just expose the log and leave it at that? Is it a security issue to expose only the (stripped) log?

@wsnipex
Team Kodi member

thats the question here. I don't see a security issue in exposing the stripped log(or other files), @t-nelson and others obviously do.

If log only is agreeable, fine for me, but I do not want it dependent on having debugging enabled via GUI setting. This is my only requirement, as it makes my own usecase moot.

@topfs2
Team Kodi member

Would it make sense to add it to JSON-RPC instead? That way we can add it as a special permission?

@Montellese
Team Kodi member

@topfs2: Where would the security be through JSON-RPC? We have permissions but we don't do anything with them at the moment. Furthermore for an average joe user it's much easier to open a browser URL to retrieve the log file from a "remote" machine than having to execute a JSON-RPC request etc.

@topfs2
Team Kodi member

Hehe, I meant that then we have it more under control, even if the permissions aren't used yet :)
And an url we could still create with a webinterface, e.g. http://IP:PORT/logs where that webinterface prettifies the log output from jsonrpc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
View
7 language/English/strings.po
@@ -3264,7 +3264,12 @@ msgctxt "#1051"
msgid "Enter web address"
msgstr ""
-#empty strings from id 1052 to 1179
+#: xbmc/settings/GUISettings.cpp
+msgctxt "#1052"
+msgid "Allow access to special:// URLs"
+msgstr ""
+
+#empty strings from id 1053 to 1179
#: xbmc/settings/GUISettings.cpp
msgctxt "#1180"
View
2 project/VS2010Express/XBMC.vcxproj
@@ -831,6 +831,7 @@
<ClCompile Include="..\..\xbmc\network\GUIDialogNetworkSetup.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPImageHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPJsonRpcHandler.cpp" />
+ <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPSpecialHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPWebinterfaceAddonsHandler.cpp" />
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPWebinterfaceHandler.cpp" />
@@ -1149,6 +1150,7 @@
<ClInclude Include="..\..\xbmc\interfaces\json-rpc\JSONRPCUtils.h" />
<ClInclude Include="..\..\xbmc\interfaces\json-rpc\GUIOperations.h" />
<ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPJsonRpcHandler.h" />
+ <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPSpecialHandler.h" />
<ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.h" />
<ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPWebinterfaceAddonsHandler.h" />
<ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPWebinterfaceHandler.h" />
View
6 project/VS2010Express/XBMC.vcxproj.filters
@@ -2008,6 +2008,9 @@
<ClCompile Include="..\..\xbmc\filesystem\AFPDirectory.cpp">
<Filter>filesystem</Filter>
</ClCompile>
+ <ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPSpecialHandler.cpp">
+ <Filter>network\httprequesthandler</Filter>
+ </ClCompile>
<ClCompile Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.cpp">
<Filter>network\httprequesthandler</Filter>
</ClCompile>
@@ -5322,6 +5325,9 @@
<ClInclude Include="..\..\xbmc\network\httprequesthandler\IHTTPRequestHandler.h">
<Filter>network\httprequesthandler</Filter>
</ClInclude>
+ <ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPSpecialHandler.h">
+ <Filter>network\httprequesthandler</Filter>
+ </ClInclude>
<ClInclude Include="..\..\xbmc\network\httprequesthandler\HTTPVfsHandler.h">
<Filter>network\httprequesthandler</Filter>
</ClInclude>
View
5 xbmc/Application.cpp
@@ -41,6 +41,7 @@
#include "network/WebServer.h"
#include "network/httprequesthandler/HTTPImageHandler.h"
#include "network/httprequesthandler/HTTPVfsHandler.h"
+#include "network/httprequesthandler/HTTPSpecialHandler.h"
#ifdef HAS_JSONRPC
#include "network/httprequesthandler/HTTPJsonRpcHandler.h"
#endif
@@ -379,6 +380,7 @@ CApplication::CApplication(void)
, m_WebServer(*new CWebServer)
, m_httpImageHandler(*new CHTTPImageHandler)
, m_httpVfsHandler(*new CHTTPVfsHandler)
+ , m_httpSpecialHandler(*new CHTTPSpecialHandler)
#ifdef HAS_JSONRPC
, m_httpJsonRpcHandler(*new CHTTPJsonRpcHandler)
#endif
@@ -454,6 +456,7 @@ CApplication::~CApplication(void)
delete &m_WebServer;
delete &m_httpImageHandler;
delete &m_httpVfsHandler;
+ delete &m_httpSpecialHandler;
#ifdef HAS_JSONRPC
delete &m_httpJsonRpcHandler;
#endif
@@ -1262,6 +1265,7 @@ bool CApplication::Initialize()
#ifdef HAS_WEB_SERVER
CWebServer::RegisterRequestHandler(&m_httpImageHandler);
CWebServer::RegisterRequestHandler(&m_httpVfsHandler);
+ CWebServer::RegisterRequestHandler(&m_httpSpecialHandler);
#ifdef HAS_JSONRPC
CWebServer::RegisterRequestHandler(&m_httpJsonRpcHandler);
#endif
@@ -3655,6 +3659,7 @@ void CApplication::Stop(int exitCode)
#ifdef HAS_WEB_SERVER
CWebServer::UnregisterRequestHandler(&m_httpImageHandler);
CWebServer::UnregisterRequestHandler(&m_httpVfsHandler);
+ CWebServer::UnregisterRequestHandler(&m_httpSpecialHandler);
#ifdef HAS_JSONRPC
CWebServer::UnregisterRequestHandler(&m_httpJsonRpcHandler);
CJSONRPC::Cleanup();
View
2 xbmc/Application.h
@@ -75,6 +75,7 @@ class IPlayer;
class CWebServer;
class CHTTPImageHandler;
class CHTTPVfsHandler;
+class CHTTPSpecialHandler;
#ifdef HAS_JSONRPC
class CHTTPJsonRpcHandler;
#endif
@@ -288,6 +289,7 @@ class CApplication : public CXBApplicationEx, public IPlayerCallback, public IMs
CWebServer& m_WebServer;
CHTTPImageHandler& m_httpImageHandler;
CHTTPVfsHandler& m_httpVfsHandler;
+ CHTTPSpecialHandler& m_httpSpecialHandler;
#ifdef HAS_JSONRPC
CHTTPJsonRpcHandler& m_httpJsonRpcHandler;
#endif
View
3 xbmc/network/WebServer.h
@@ -54,6 +54,8 @@ class CWebServer : public JSONRPC::ITransportLayer
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 const char *CreateMimeTypeFromExtension(const char *ext);
+
private:
struct MHD_Daemon* StartMHD(unsigned int flags, int port);
static int AskForAuthentication (struct MHD_Connection *connection);
@@ -101,7 +103,6 @@ class CWebServer : public JSONRPC::ITransportLayer
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 const char *CreateMimeTypeFromExtension(const char *ext);
struct MHD_Daemon *m_daemon;
bool m_running, m_needcredentials;
View
141 xbmc/network/httprequesthandler/HTTPSpecialHandler.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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 "HTTPSpecialHandler.h"
+#include "URL.h"
+#include "filesystem/File.h"
+#include "network/WebServer.h"
+#include "utils/URIUtils.h"
+#include "utils/log.h"
+#include "utils/RegExp.h"
+#include "utils/StringUtils.h"
+#include "settings/GUISettings.h"
+
+using namespace std;
+
+bool CHTTPSpecialHandler::CheckHTTPRequest(const HTTPRequest &request)
+{
+ return (g_guiSettings.GetBool("services.webserverallowspecialurl") &&
+ (request.url.find("/special/") == 0 || request.url.find("/log") == 0)
+ );
+}
+
+int CHTTPSpecialHandler::HandleHTTPRequest(const HTTPRequest &request)
+{
+ string ext;
+
+ /* our URL is /special */
+ if (request.url.substr(0, 19) == "/special/special://")
+ {
+ m_path = request.url.substr(9);
+ ext = URIUtils::GetExtension(request.url);
+ StringUtils::ToLower(ext);
+
+ if (!XFILE::CFile::Exists(m_path))
+ {
+ CLog::Log(LOGERROR, "CHTTPSpecialHandler::HandleHTTPRequest: file %s does not exist", m_path.c_str());
+ m_responseCode = MHD_HTTP_NOT_FOUND;
+ m_responseType = HTTPError;
+ return MHD_YES;
+ }
+ }
+ /* add a shortcut URL /log and /log/ pointing to xbmc.log */
+ else if (request.url.compare("/log") == 0 || request.url.compare("/log/") == 0)
+ {
+ m_path = "special://temp/xbmc.log";
+ ext = ".log";
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: bad request");
+ m_responseCode = MHD_HTTP_BAD_REQUEST;
+ m_responseType = HTTPError;
+ return MHD_YES;
+ }
+
+ /* If we have a file that potentially holds user credentials
+ * we want to sanitize them.
+ * Else have the webserver handle the download */
+ if (ext == ".log" || ext == ".xml")
+ {
+ XFILE::CFile *file = new XFILE::CFile();
+ if (file->Open(m_path, READ_CACHED))
+ {
+ m_response = "";
+ char m_buf[1024];
+ memset(m_buf, '\0', sizeof(m_buf));
+ string line = "";
+ string user;
+ string pass;
+ string replace;
+
+ /* this replaces the following:
+ * - username:pass in URIs
+ * - <pass>pass</pass> in XMLs
+ */
+ CRegExp regex1, regex2;
+ regex1.RegComp("://(.*):(.*)@");
+ regex2.RegComp("<[^<>]*(pass|user)[^<>]*>([^<]+)</.*(pass|user).*>");
+
+ while (file->ReadString(m_buf, 1023))
+ {
+ line = m_buf;
+ if (regex1.RegFind(line))
+ {
+ user = regex1.GetReplaceString("\\1");
+ pass = regex1.GetReplaceString("\\2");
+ replace = "://" + user + ":" + pass + "@";
+ StringUtils::Replace(line, replace, "://xxx:xxx@");
+ }
+ if (regex2.RegFind(line))
+ {
+ replace = regex2.GetReplaceString("\\2");
+ if (replace.length() > 0)
+ StringUtils::Replace(line, replace, "xxx");
+ }
+ m_response += line;
+ memset(m_buf, '\0', sizeof(m_buf));
+ }
+
+ const char *mime = request.webserver->CreateMimeTypeFromExtension(ext.c_str());
+ if (mime)
+ m_responseHeaderFields.insert(pair<string, string>("Content-Type", mime));
+
+ file->Close();
+ delete file;
+ m_request.clear();
+
+ m_responseCode = MHD_HTTP_OK;
+ m_responseType = HTTPMemoryDownloadNoFreeCopy;
+ }
+ else
+ {
+ CLog::Log(LOGDEBUG, "CHTTPSpecialHandler::HandleHTTPRequest: cannot open file %s", m_path.c_str());
+ m_responseCode = MHD_HTTP_NOT_FOUND;
+ m_responseType = HTTPError;
+ }
+ }
+ else
+ {
+ m_responseCode = MHD_HTTP_OK;
+ m_responseType = HTTPFileDownload;
+ }
+ return MHD_YES;
+}
View
44 xbmc/network/httprequesthandler/HTTPSpecialHandler.h
@@ -0,0 +1,44 @@
+#pragma once
+/*
+ * Copyright (C) 2013 Team XBMC
+ * http://www.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 "IHTTPRequestHandler.h"
+
+class CHTTPSpecialHandler : public IHTTPRequestHandler
+{
+public:
+ CHTTPSpecialHandler() { };
+
+ virtual IHTTPRequestHandler* GetInstance() { return new CHTTPSpecialHandler(); }
+ virtual bool CheckHTTPRequest(const HTTPRequest &request);
+ virtual int HandleHTTPRequest(const HTTPRequest &request);
+
+ virtual std::string GetHTTPResponseFile() const { return m_path; }
+ static int ResolveUrl(const std::string &url, std::string &path);
+ virtual void* GetHTTPResponseData() const { return (void *)m_response.c_str(); };
+ virtual size_t GetHTTPResonseDataLength() const { return m_response.length(); }
+
+ virtual int GetPriority() const { return 2; }
+
+private:
+ std::string m_path;
+ std::string m_request;
+ std::string m_response;
+};
View
1 xbmc/network/httprequesthandler/Makefile
@@ -1,5 +1,6 @@
SRCS=HTTPImageHandler.cpp \
HTTPJsonRpcHandler.cpp \
+ HTTPSpecialHandler.cpp \
HTTPVfsHandler.cpp \
HTTPWebinterfaceAddonsHandler.cpp \
HTTPWebinterfaceHandler.cpp \
View
1 xbmc/settings/GUISettings.cpp
@@ -859,6 +859,7 @@ void CGUISettings::Initialize()
AddString(srvWeb,"services.webserverport", 730, CUtil::CanBindPrivileged()?"80":"8080", EDIT_CONTROL_NUMBER_INPUT, false, 730);
AddString(srvWeb,"services.webserverusername",1048, "xbmc", EDIT_CONTROL_INPUT);
AddString(srvWeb,"services.webserverpassword",733, "", EDIT_CONTROL_HIDDEN_INPUT, true, 733);
+ AddBool(srvWeb,"services.webserverallowspecialurl",1052, false);
AddDefaultAddon(srvWeb, "services.webskin",199, DEFAULT_WEB_INTERFACE, ADDON_WEB_INTERFACE);
#endif
#ifdef HAS_EVENT_SERVER
Something went wrong with that request. Please try again.