aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.in1
-rw-r--r--codegenerator.mk1
-rw-r--r--xbmc/interfaces/legacy/wsgi/Makefile12
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp75
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h74
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp182
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiInputStream.h101
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp103
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponse.h65
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp42
-rw-r--r--xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h52
-rw-r--r--xbmc/interfaces/python/Doxyfile2
-rw-r--r--xbmc/interfaces/swig/AddonModuleXbmcwsgi.i62
13 files changed, 771 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index 0c6ad606fa..5a99227c4c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -110,6 +110,7 @@ DIRECTORY_ARCHIVES += xbmc/network/httprequesthandler/httprequesthandlers.a
endif
DIRECTORY_ARCHIVES += xbmc/interfaces/legacy/legacy.a
+DIRECTORY_ARCHIVES += xbmc/interfaces/legacy/wsgi/legacy-wsgi.a
DIRECTORY_ARCHIVES += xbmc/interfaces/python/python_binding.a
ifeq (@USE_OPENGL@,1)
diff --git a/codegenerator.mk b/codegenerator.mk
index 5ecb0c0273..ed24a3fc88 100644
--- a/codegenerator.mk
+++ b/codegenerator.mk
@@ -34,6 +34,7 @@ GENERATED += $(GENDIR)/AddonModuleXbmcgui.cpp
GENERATED += $(GENDIR)/AddonModuleXbmcplugin.cpp
GENERATED += $(GENDIR)/AddonModuleXbmcaddon.cpp
GENERATED += $(GENDIR)/AddonModuleXbmcvfs.cpp
+GENERATED += $(GENDIR)/AddonModuleXbmcwsgi.cpp
GENERATE_DEPS += $(TOPDIR)/xbmc/interfaces/legacy/*.h $(TOPDIR)/xbmc/interfaces/python/typemaps/*.intm $(TOPDIR)/xbmc/interfaces/python/typemaps/*.outtm
diff --git a/xbmc/interfaces/legacy/wsgi/Makefile b/xbmc/interfaces/legacy/wsgi/Makefile
new file mode 100644
index 0000000000..999a9fa965
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/Makefile
@@ -0,0 +1,12 @@
+SRCS = WsgiErrorStream.cpp \
+ WsgiInputStream.cpp \
+ WsgiResponse.cpp \
+ WsgiResponseBody.cpp \
+
+LIB=legacy-wsgi.a
+
+CXXFLAGS+= -DSWIGRUNTIME_DEBUG -DSTATIC_LINKED
+
+include ../../../../Makefile.include
+-include $(patsubst %.cpp,%.P,$(patsubst %.c,%.P,$(SRCS)))
+
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp
new file mode 100644
index 0000000000..d207e67201
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2015 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 "WsgiErrorStream.h"
+#include "interfaces/legacy/AddonUtils.h"
+#include "network/httprequesthandler/python/HTTPPythonRequest.h"
+#include "utils/log.h"
+#include "utils/StringUtils.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiErrorStream::WsgiErrorStream()
+ : m_request(NULL)
+ { }
+
+ WsgiErrorStream::~WsgiErrorStream()
+ {
+ m_request = NULL;
+ }
+
+ void WsgiErrorStream::write(const String& str)
+ {
+ if (str.empty())
+ return;
+
+ String msg = str;
+ // remove a trailing \n
+ if (msg.at(msg.size() - 1) == '\n')
+ msg.erase(msg.size() - 1);
+
+ if (m_request != NULL)
+ CLog::Log(LOGERROR, "WSGI [%s]: %s", m_request->url.c_str(), msg.c_str());
+ else
+ CLog::Log(LOGERROR, "WSGI: %s", msg.c_str());
+ }
+
+ void WsgiErrorStream::writelines(const std::vector<String>& seq)
+ {
+ if (seq.empty())
+ return;
+
+ String msg = StringUtils::Join(seq, "");
+ write(msg);
+ }
+
+#ifndef SWIG
+ void WsgiErrorStream::SetRequest(HTTPPythonRequest* request)
+ {
+ if (m_request != NULL)
+ return;
+
+ m_request = request;
+ }
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h
new file mode 100644
index 0000000000..985f765d5a
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiErrorStream.h
@@ -0,0 +1,74 @@
+#pragma once
+/*
+ * Copyright (C) 2015 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 <vector>
+
+#include "interfaces/legacy/AddonClass.h"
+#include "interfaces/legacy/swighelper.h"
+
+struct HTTPPythonRequest;
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ /**
+ * Represents the wsgi.errors stream to write error messages.
+ *
+ * This implementation writes the error messages to the application's log
+ * file.
+ */
+ class WsgiErrorStream : public AddonClass
+ {
+ public:
+ WsgiErrorStream();
+ virtual ~WsgiErrorStream();
+
+ /**
+ * Since nothing is buffered this is a no-op.
+ */
+ inline void flush() { }
+
+ /**
+ * Writes the given error message to the application's log file.
+ *
+ * A trailing \n is removed.
+ */
+ void write(const String& str);
+
+ /**
+ * Joins the given list of error messages (without any separator) into
+ * a single error message which is written to the application's log file.
+ */
+ void writelines(const std::vector<String>& seq);
+
+#ifndef SWIG
+ /**
+ * Sets the given request.
+ */
+ void SetRequest(HTTPPythonRequest* request);
+
+ HTTPPythonRequest* m_request;
+#endif
+ };
+ }
+}
+
+
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp
new file mode 100644
index 0000000000..eee832f333
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.cpp
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2015 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 "WsgiInputStream.h"
+#include "interfaces/legacy/AddonUtils.h"
+#include "network/httprequesthandler/python/HTTPPythonRequest.h"
+#include "utils/StringUtils.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiInputStreamIterator::WsgiInputStreamIterator()
+ : m_data(),
+ m_offset(0),
+ m_remaining(0),
+ m_line()
+ { }
+
+#ifndef SWIG
+ WsgiInputStreamIterator::WsgiInputStreamIterator(const String& data, bool end /* = false */)
+ : m_data(data),
+ m_offset(0),
+ m_remaining(end ? 0 : data.size()),
+ m_line()
+ { }
+#endif
+
+ WsgiInputStreamIterator::~WsgiInputStreamIterator()
+ { }
+
+ String WsgiInputStreamIterator::read(unsigned long size /* = 0 */) const
+ {
+ // make sure we don't try to read more data than we have
+ if (size <= 0 || size > m_remaining)
+ size = m_remaining;
+
+ // remember the current read offset
+ size_t offset = static_cast<size_t>(m_offset);
+
+ // adjust the read offset and the remaining data length
+ m_offset += size;
+ m_remaining -= size;
+
+ // return the data being requested
+ return m_data.substr(offset, size);
+ }
+
+ String WsgiInputStreamIterator::readline(unsigned long size /* = 0 */) const
+ {
+ // make sure we don't try to read more data than we have
+ if (size <= 0 || size > m_remaining)
+ size = m_remaining;
+
+ size_t offset = static_cast<size_t>(m_offset);
+ size_t pos = m_data.find('\n', offset);
+
+ // make sure pos has a valid value and includes the \n character
+ if (pos == std::string::npos)
+ pos = m_data.size();
+ else
+ pos += 1;
+
+ if (pos - offset < size)
+ size = pos - offset;
+
+ // read the next line
+ String line = read(size);
+
+ // remove any trailing \r\n
+ StringUtils::TrimRight(line, "\r\n");
+
+ return line;
+ }
+
+ std::vector<String> WsgiInputStreamIterator::readlines(unsigned long sizehint /* = 0 */) const
+ {
+ std::vector<String> lines;
+
+ // make sure we don't try to read more data than we have
+ if (sizehint <= 0 || sizehint > m_remaining)
+ sizehint = m_remaining;
+
+ do
+ {
+ // read a full line
+ String line = readline();
+
+ // adjust the sizehint by the number of bytes just read
+ sizehint -= line.length();
+
+ // add it to the list of read lines
+ lines.push_back(line);
+ } while (sizehint > 0);
+
+ return lines;
+ }
+
+#ifndef SWIG
+ WsgiInputStreamIterator& WsgiInputStreamIterator::operator++()
+ {
+ m_line.clear();
+
+ if (!end())
+ {
+ // read the next line
+ m_line = readline();
+ }
+
+ return *this;
+ }
+
+ bool WsgiInputStreamIterator::operator==(const WsgiInputStreamIterator& rhs)
+ {
+ return m_data == rhs.m_data &&
+ m_offset == rhs.m_offset &&
+ m_remaining == rhs.m_remaining;
+ }
+
+ bool WsgiInputStreamIterator::operator!=(const WsgiInputStreamIterator& rhs)
+ {
+ return !(*this == rhs);
+ }
+
+ String& WsgiInputStreamIterator::operator*()
+ {
+ return m_line;
+ }
+#endif
+
+ WsgiInputStream::WsgiInputStream()
+ : m_request(NULL)
+ { }
+
+ WsgiInputStream::~WsgiInputStream()
+ {
+ m_request = NULL;
+ }
+
+#ifndef SWIG
+ WsgiInputStreamIterator* WsgiInputStream::begin()
+ {
+ return new WsgiInputStreamIterator(m_data, false);
+ }
+
+ WsgiInputStreamIterator* WsgiInputStream::end()
+ {
+ return new WsgiInputStreamIterator(m_data, true);
+ }
+
+ void WsgiInputStream::SetRequest(HTTPPythonRequest* request)
+ {
+ if (m_request != NULL)
+ return;
+
+ m_request = request;
+
+ // set the remaining bytes to be read
+ m_data = m_request->requestContent;
+ m_offset = 0;
+ m_remaining = m_data.size();
+ }
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiInputStream.h b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.h
new file mode 100644
index 0000000000..ea7f6730b1
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiInputStream.h
@@ -0,0 +1,101 @@
+#pragma once
+/*
+ * Copyright (C) 2015 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 <vector>
+
+#include "interfaces/legacy/AddonClass.h"
+#include "interfaces/legacy/swighelper.h"
+
+struct HTTPPythonRequest;
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ /**
+ * Iterator for the wsgi.input stream.
+ */
+ class WsgiInputStreamIterator : public AddonClass
+ {
+ public:
+ WsgiInputStreamIterator();
+ virtual ~WsgiInputStreamIterator();
+
+ /**
+ * Read a maximum of <size> bytes from the wsgi.input stream.
+ */
+ String read(unsigned long size = 0) const;
+
+ /**
+ * Read a full line up to a maximum of <size> bytes from the wsgi.input
+ * stream.
+ */
+ String readline(unsigned long size = 0) const;
+
+ /**
+ * Read multiple full lines up to at least <sizehint> bytes from the
+ * wsgi.input stream and return them as a list.
+ */
+ std::vector<String> readlines(unsigned long sizehint = 0) const;
+
+#ifndef SWIG
+ WsgiInputStreamIterator(const String& data, bool end = false);
+
+ WsgiInputStreamIterator& operator++();
+ bool operator==(const WsgiInputStreamIterator& rhs);
+ bool operator!=(const WsgiInputStreamIterator& rhs);
+ String& operator*();
+ inline bool end() const { return m_remaining <= 0; }
+
+ protected:
+ String m_data;
+ mutable unsigned long m_offset;
+ mutable unsigned long m_remaining;
+
+ private:
+ String m_line;
+#endif
+ };
+
+ /**
+ * Represents the wsgi.input stream to access data from a HTTP request.
+ */
+ class WsgiInputStream : public WsgiInputStreamIterator
+ {
+ public:
+ WsgiInputStream();
+ virtual ~WsgiInputStream();
+
+#ifndef SWIG
+ WsgiInputStreamIterator* begin();
+ WsgiInputStreamIterator* end();
+
+ /**
+ * Sets the given request.
+ */
+ void SetRequest(HTTPPythonRequest* request);
+
+ HTTPPythonRequest* m_request;
+#endif
+ };
+ }
+}
+
+
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp b/xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp
new file mode 100644
index 0000000000..22a3c406a0
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponse.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2015 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 "WsgiResponse.h"
+#include "network/httprequesthandler/IHTTPRequestHandler.h"
+#include "utils/log.h"
+#include "utils/StringUtils.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiResponse::WsgiResponse()
+ : m_called(false),
+ m_status(MHD_HTTP_INTERNAL_SERVER_ERROR),
+ m_responseHeaders(),
+ m_body()
+ { }
+
+ WsgiResponse::~WsgiResponse()
+ { }
+
+ WsgiResponseBody* WsgiResponse::operator()(const String& status, const std::vector<WsgiHttpHeader>& response_headers, void* exc_info /* = NULL */)
+ {
+ if (m_called)
+ {
+ CLog::Log(LOGWARNING, "WsgiResponse: callable has already been called");
+ return NULL;
+ }
+
+ m_called = true;
+
+ // parse the status
+ if (!status.empty())
+ {
+ std::vector<String> statusParts = StringUtils::Split(status, ' ', 2);
+ if (statusParts.size() == 2 && StringUtils::IsNaturalNumber(statusParts.front()))
+ {
+ int64_t parsedStatus = strtol(statusParts.front().c_str(), NULL, 0);
+ if (parsedStatus >= MHD_HTTP_OK && parsedStatus <= MHD_HTTP_NOT_EXTENDED)
+ m_status = static_cast<int>(parsedStatus);
+ else
+ CLog::Log(LOGWARNING, "WsgiResponse: invalid status number %" PRId64 " in \"%s\" provided", parsedStatus, status.c_str());
+ }
+ else
+ CLog::Log(LOGWARNING, "WsgiResponse: invalid status \"%s\" provided", status.c_str());
+ }
+ else
+ CLog::Log(LOGWARNING, "WsgiResponse: empty status provided");
+
+ // copy the response headers
+ for (std::vector<WsgiHttpHeader>::const_iterator headerIt = response_headers.begin(); headerIt != response_headers.end(); ++headerIt)
+ m_responseHeaders.insert(std::make_pair(headerIt->first(), headerIt->second()));
+
+ return &m_body;
+ }
+
+#ifndef SWIG
+ void WsgiResponse::Append(const std::string& data)
+ {
+ if (!data.empty())
+ m_body.m_data.append(data);
+ }
+
+ bool WsgiResponse::Finalize(HTTPPythonRequest* request) const
+ {
+ if (request == NULL || !m_called)
+ return false;
+
+ // copy the response status
+ request->responseStatus = m_status;
+
+ // copy the response headers
+ if (m_status >= MHD_HTTP_OK && m_status < MHD_HTTP_BAD_REQUEST)
+ request->responseHeaders.insert(m_responseHeaders.begin(), m_responseHeaders.end());
+ else
+ request->responseHeadersError.insert(m_responseHeaders.begin(), m_responseHeaders.end());
+
+ // copy the body
+ request->responseData = m_body.m_data;
+
+ return true;
+ }
+#endif
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponse.h b/xbmc/interfaces/legacy/wsgi/WsgiResponse.h
new file mode 100644
index 0000000000..e74a1e66dc
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponse.h
@@ -0,0 +1,65 @@
+#pragma once
+/*
+ * Copyright (C) 2015 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 "interfaces/legacy/AddonClass.h"
+#include "interfaces/legacy/Tuple.h"
+#include "interfaces/legacy/swighelper.h"
+#include "interfaces/legacy/wsgi/WsgiResponseBody.h"
+#include "network/httprequesthandler/python/HTTPPythonRequest.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ typedef Tuple<String, String> WsgiHttpHeader;
+
+ /**
+ * Represents the start_response callable passed to a WSGI handler.
+ */
+ class WsgiResponse : public AddonClass
+ {
+ public:
+ WsgiResponse();
+ virtual ~WsgiResponse();
+
+ /**
+ * Callable implementation to initialize the response with the given
+ * HTTP status and the HTTP response headers.
+ */
+ WsgiResponseBody* operator()(const String& status, const std::vector<WsgiHttpHeader>& response_headers, void* exc_info = NULL);
+
+#ifndef SWIG
+ void Append(const std::string& data);
+
+ bool Finalize(HTTPPythonRequest* request) const;
+
+ private:
+ bool m_called;
+ int m_status;
+ std::multimap<std::string, std::string> m_responseHeaders;
+
+ WsgiResponseBody m_body;
+#endif
+ };
+ }
+}
+
+
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp
new file mode 100644
index 0000000000..afb9f4668f
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 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 "WsgiResponseBody.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ WsgiResponseBody::WsgiResponseBody()
+ : m_data()
+ { }
+
+ WsgiResponseBody::~WsgiResponseBody()
+ { }
+
+ void WsgiResponseBody::operator()(const String& data)
+ {
+ if (data.empty())
+ return;
+
+ m_data.append(data);
+ }
+ }
+}
diff --git a/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h
new file mode 100644
index 0000000000..2ce5c57b1b
--- /dev/null
+++ b/xbmc/interfaces/legacy/wsgi/WsgiResponseBody.h
@@ -0,0 +1,52 @@
+#pragma once
+/*
+ * Copyright (C) 2015 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 <string>
+
+#include "interfaces/legacy/AddonClass.h"
+#include "interfaces/legacy/swighelper.h"
+
+namespace XBMCAddon
+{
+ namespace xbmcwsgi
+ {
+ /**
+ * Represents the write callable returned by the start_response callable passed to a WSGI handler.
+ */
+ class WsgiResponseBody : public AddonClass
+ {
+ public:
+ WsgiResponseBody();
+ virtual ~WsgiResponseBody();
+
+ /**
+ * Callable implemention to write data to the response.
+ */
+ void operator()(const String& data);
+
+#ifndef SWIG
+ String m_data;
+#endif
+ };
+ }
+}
+
+
diff --git a/xbmc/interfaces/python/Doxyfile b/xbmc/interfaces/python/Doxyfile
index c3bddcd793..d262d6a158 100644
--- a/xbmc/interfaces/python/Doxyfile
+++ b/xbmc/interfaces/python/Doxyfile
@@ -648,7 +648,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
-INPUT = ../legacy
+INPUT = ../legacy ../legacy/wsgi
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
diff --git a/xbmc/interfaces/swig/AddonModuleXbmcwsgi.i b/xbmc/interfaces/swig/AddonModuleXbmcwsgi.i
new file mode 100644
index 0000000000..6d5d520185
--- /dev/null
+++ b/xbmc/interfaces/swig/AddonModuleXbmcwsgi.i
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2015 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 "system.h"
+
+#ifdef HAS_WEB_SERVER
+%}
+
+%module xbmcwsgi
+
+%{
+#include "interfaces/legacy/wsgi/WsgiErrorStream.h"
+#include "interfaces/legacy/wsgi/WsgiInputStream.h"
+#include "interfaces/legacy/wsgi/WsgiResponse.h"
+#include "interfaces/legacy/wsgi/WsgiResponseBody.h"
+
+using namespace XBMCAddon;
+using namespace xbmcwsgi;
+
+#if defined(__GNUG__) && (__GNUC__>4) || (__GNUC__==4 && __GNUC_MINOR__>=2)
+#pragma GCC diagnostic ignored "-Wstrict-aliasing"
+#endif
+
+%}
+
+// This is all about warning suppression. It's OK that these base classes are
+// not part of what swig parses.
+%feature("knownbasetypes") XBMCAddon::xbmcaddon "AddonClass"
+
+%feature("iterator") WsgiInputStreamIterator "std::string"
+%feature("iterable") WsgiInputStream "XBMCAddon::xbmcwsgi::WsgiInputStreamIterator"
+
+%include "interfaces/legacy/swighelper.h"
+%include "interfaces/legacy/AddonString.h"
+
+%include "interfaces/legacy/wsgi/WsgiErrorStream.h"
+%include "interfaces/legacy/wsgi/WsgiInputStream.h"
+%include "interfaces/legacy/wsgi/WsgiResponse.h"
+%include "interfaces/legacy/wsgi/WsgiResponseBody.h"
+
+%{
+#endif
+%}
+