MythTV  master
mythhttpservice.cpp
Go to the documentation of this file.
1 #include <QFileInfo>
2 
3 // MythTV
4 #include "mythlogging.h"
5 #include "mythdate.h"
6 #include "http/mythwsdl.h"
7 #include "http/mythhttpservice.h"
8 #include "http/mythhttprequest.h"
11 #include "http/mythhttpencoding.h"
13 
14 #define LOC QString("HTTPService: ")
15 
17  : m_name(MetaService->m_name),
18  m_staticMetaService(MetaService)
19 {
20 }
21 
28 {
29  QString& method = Request->m_fileName;
30  if (method.isEmpty())
31  return nullptr;
33  // WSDL
34  if (method == "wsdl") {
36  return wsdl.GetWSDL( Request );
37  }
38  if ( method == "xsd" )
39  {
40  MythXSD xsd;
41  if (Request->m_queries.contains( "type" ))
42  return xsd.GetXSD( Request, Request->m_queries.value("type"));
43  // The xsd for enums does not work, so it is commented for now.
44  // else
45  // return xsd.GetEnumXSD( Request, Request->m_queries.value("enum"));
46  }
47  if ( method == "version" )
48  {
49  int nClassIdx = m_staticMetaService->m_meta.indexOfClassInfo( "Version" );
50  if (nClassIdx >=0)
51  {
52  QString sVersion =
53  m_staticMetaService->m_meta.classInfo(nClassIdx).value();
54  auto accept = MythHTTPEncoding::GetMimeTypes(MythHTTP::GetHeader(Request->m_headers, "accept"));
55  HTTPData content = MythSerialiser::Serialise("String", sVersion, accept);
56  content->m_cacheType = HTTPETag | HTTPShortLife;
58  return result;
59  }
60  }
61  // Find the method
62  LOG(VB_HTTP, LOG_DEBUG, LOC + QString("Looking for method '%1'").arg(method));
63  HTTPMethodPtr handler = nullptr;
64  // cppcheck-suppress unassignedVariable
65  for (auto & [path, handle] : m_staticMetaService->m_slots)
66  if (path == method) { handler = handle; break; }
67 
68  if (handler == nullptr)
69  {
70  // Should we just return not found here rather than falling through
71  // to all of the other handlers? Do we need other handlers?
72  LOG(VB_HTTP, LOG_DEBUG, LOC + "Failed to find method");
73  return nullptr;
74  }
75 
76  // Authentication required
77  if (handler->m_protected)
78  {
79  LOG(VB_HTTP, LOG_INFO, LOC + "Authentication required for this call");
80  }
81 
82  // Sanity check type count (handler should have the return type at least)
83  if (handler->m_types.empty())
84  return nullptr;
85 
86  // Handle options
87  Request->m_allowed = handler->m_requestTypes;
89  return options;
90 
91  // Parse the parameters and match against those expected by the method.
92  // As for the old code, this allows parameters to be missing and they will
93  // thus be allocated a default/null/value.
94  size_t typecount = std::min(handler->m_types.size(), static_cast<size_t>(100));
95 
96  // Build parameters list
97  // Note: We allow up to 100 args but anything above Q_METAMETHOD_INVOKE_MAX_ARGS
98  // will be ignored
99  std::array<void*, 100> param { nullptr};
100  std::array<int, 100> types { 0 };
101 
102  // Return type
103 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
104  param[0] = handler->m_types[0] == 0 ? nullptr : QMetaType::create(handler->m_types[0]);
105 #else
106  param[0] = handler->m_types[0] == 0 ? nullptr : QMetaType(handler->m_types[0]).create();
107 #endif
108  types[0] = handler->m_types[0];
109 
110  // Parameters
111  // Iterate over the method's parameters and search for the incoming values...
112  size_t count = 1;
113  QString error;
114  while (count < typecount)
115  {
116  auto name = handler->m_names[count];
117  auto value = Request->m_queries.value(name.toLower(), "");
118  auto type = handler->m_types[count];
119  types[count] = type;
120  // These should be filtered out in MythHTTPMetaMethod
121  if (type == 0)
122  {
123  error = QString("Unknown parameter type '%1'").arg(name);
124  break;
125  }
126 
127 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
128  auto * newparam = QMetaType::create(type);
129 #else
130  auto * newparam = QMetaType(type).create();
131 #endif
132  param[count] = MythHTTPMetaMethod::CreateParameter(newparam, type, value);
133  ++count;
134  }
135 
136  HTTPResponse result = nullptr;
137  if (count == typecount)
138  {
139  // Invoke
140  QVariant returnvalue;
141  try {
142  if (qt_metacall(QMetaObject::InvokeMetaMethod, handler->m_index, param.data()) >= 0)
143  LOG(VB_GENERAL, LOG_ERR, "qt_metacall error");
144  else
145  {
146  // Retrieve result
147  returnvalue = MythHTTPMetaMethod::CreateReturnValue(types[0], param[0]);
148  }
149  }
150  catch( QString &msg ) {
151  LOG(VB_GENERAL, LOG_ERR, "Service Exception: " + msg);
152  Request->m_status = HTTPBadRequest;
154  }
155  catch (V2HttpRedirectException &ex) {
157  }
158 
159  if (!returnvalue.isValid())
160  {
161  if (!result)
162  result = MythHTTPResponse::ErrorResponse(Request, "Unknown Failure");
163  }
164  else if (returnvalue.canConvert<QFileInfo>())
165  {
166  if (!result)
167  {
168  auto info = returnvalue.value<QFileInfo>();
169  QString file = info.absoluteFilePath();
170  if (file.size() == 0)
171  {
172  LOG(VB_HTTP, LOG_WARNING, LOC + QString("Invalid request for unknown file"));
173  Request->m_status = HTTPNotFound;
175  }
176  else
177  {
178  HTTPFile httpfile = MythHTTPFile::Create(info.fileName(),file);
179  if (!httpfile->open(QIODevice::ReadOnly))
180  {
181  LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Failed to open '%1'").arg(file));
182  Request->m_status = HTTPNotFound;
184  }
185  else
186  {
187  httpfile->m_lastModified = info.lastModified();
188  httpfile->m_cacheType = HTTPLastModified | HTTPLongLife;
189  LOG(VB_HTTP, LOG_DEBUG, LOC + QString("Last modified: %2")
190  .arg(MythDate::toString(httpfile->m_lastModified, MythDate::kOverrideUTC | MythDate::kRFC822)));
191  // Create our response
192  result = MythHTTPResponse::FileResponse(Request, httpfile);
193  }
194  }
195  }
196  }
197  else
198  {
199  auto accept = MythHTTPEncoding::GetMimeTypes(MythHTTP::GetHeader(Request->m_headers, "accept"));
200  HTTPData content = MythSerialiser::Serialise(handler->m_returnTypeName, returnvalue, accept);
201  content->m_cacheType = HTTPETag | HTTPShortLife;
203 
204  // If the return type is QObject* we need to cleanup
205  if (returnvalue.canConvert<QObject*>())
206  {
207  LOG(VB_HTTP, LOG_DEBUG, LOC + "Deleting object");
208  auto * object = returnvalue.value<QObject*>();
209  delete object;
210  }
211  }
212  }
213 
214  // Cleanup
215  for (size_t i = 0; i < typecount; ++i)
216  {
217  if ((param[i] != nullptr) && (types[i] != 0))
218  {
219 #if QT_VERSION < QT_VERSION_CHECK(6,0,0)
220  QMetaType::destroy(types[i], param[i]);
221 #else
222  QMetaType(types[i]).destroy(param[i]);
223 #endif
224  }
225  }
226 
227  // Return the previous error
228  if (count != typecount)
229  {
230  LOG(VB_HTTP, LOG_ERR, LOC + error);
231  Request->m_status = HTTPBadRequest;
233  }
234 
235  // Valid result...
236  return result;
237 }
238 
239 
241 {
242  return m_name;
243 }
MythDate::toString
QString toString(const QDateTime &raw_dt, uint format)
Returns formatted string representing the time.
Definition: mythdate.cpp:84
MythWSDL::GetWSDL
HTTPResponse GetWSDL(const HTTPRequest2 &Request)
Definition: mythwsdl.cpp:28
error
static void error(const char *str,...)
Definition: vbi.cpp:37
V2HttpRedirectException
Definition: mythhttpservice.h:40
MythHTTPResponse::FileResponse
static HTTPResponse FileResponse(const HTTPRequest2 &Request, const HTTPFile &File)
Definition: mythhttpresponse.cpp:273
MythWSDL
Definition: mythwsdl.h:34
MythHTTPResponse::DataResponse
static HTTPResponse DataResponse(const HTTPRequest2 &Request, const HTTPData &Data)
Definition: mythhttpresponse.cpp:262
build_compdb.content
content
Definition: build_compdb.py:38
MythHTTPFile::Create
static HTTPFile Create(const QString &ShortName, const QString &FullName)
Definition: mythhttpfile.cpp:14
MythHTTP::GetHeader
static QString GetHeader(const HTTPHeaders &Headers, const QString &Value, const QString &Default="")
Definition: mythhttptypes.h:317
MythDate::kOverrideUTC
@ kOverrideUTC
Present date/time in UTC.
Definition: mythdate.h:31
mythhttpmetaservice.h
MythSerialiser::Serialise
static HTTPData Serialise(const QString &Name, const QVariant &Value, const QStringList &Accept)
Serialise the given data with an encoding suggested by Accept.
Definition: mythserialiser.cpp:27
HTTPETag
@ HTTPETag
Definition: mythhttptypes.h:145
types
static const struct wl_interface * types[]
Definition: idle_inhibit_unstable_v1.c:39
MythXSD
Definition: mythxsd.h:33
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
HTTPLongLife
@ HTTPLongLife
Definition: mythhttptypes.h:149
build_compdb.file
file
Definition: build_compdb.py:55
MythHTTPService::HTTPRequest
virtual HTTPResponse HTTPRequest(const HTTPRequest2 &Request)
Respond to a valid HTTPRequest.
Definition: mythhttpservice.cpp:27
HTTPNotFound
@ HTTPNotFound
Definition: mythhttptypes.h:115
HTTPData
std::shared_ptr< MythHTTPData > HTTPData
Definition: mythhttptypes.h:36
MythHTTPResponse::HandleOptions
static HTTPResponse HandleOptions(const HTTPRequest2 &Request)
Definition: mythhttpresponse.cpp:192
MythHTTPService::m_staticMetaService
MythHTTPMetaService * m_staticMetaService
Definition: mythhttpservice.h:34
mythdate.h
MythXSD::GetXSD
HTTPResponse GetXSD(const HTTPRequest2 &pRequest, QString sTypeName)
Definition: mythxsd.cpp:209
mythlogging.h
MythHTTPMetaMethod::CreateParameter
static void * CreateParameter(void *Parameter, int Type, const QString &Value)
Populate the QMetaType object referenced by Parameter with Value.
Definition: mythhttpmetamethod.cpp:131
MythHTTPMetaService::m_meta
const QMetaObject & m_meta
Definition: mythhttpmetaservice.h:20
LOC
#define LOC
Definition: mythhttpservice.cpp:14
mythwsdl.h
V2HttpRedirectException::m_hostName
QString m_hostName
Definition: mythhttpservice.h:44
MythHTTPResponse::ErrorResponse
static HTTPResponse ErrorResponse(MythHTTPStatus Status, const QString &ServerName)
Definition: mythhttpresponse.cpp:216
mythhttpencoding.h
HTTPLastModified
@ HTTPLastModified
Definition: mythhttptypes.h:146
mythhttpresponse.h
MythHTTPResponse::RedirectionResponse
static HTTPResponse RedirectionResponse(const HTTPRequest2 &Request, const QString &Redirect)
Definition: mythhttpresponse.cpp:233
MythHTTPService::m_name
QString m_name
Definition: mythhttpservice.h:33
mythserialiser.h
HTTPResponse
std::shared_ptr< MythHTTPResponse > HTTPResponse
Definition: mythhttptypes.h:39
hardwareprofile.distros.mythtv_data.request.Request
def Request(url=None)
Definition: request.py:62
mythhttpservice.h
MythHTTPService::Name
QString & Name()
Definition: mythhttpservice.cpp:240
HTTPBadRequest
@ HTTPBadRequest
Definition: mythhttptypes.h:112
MythHTTPMetaService::m_slots
HTTPMethods m_slots
Definition: mythhttpmetaservice.h:24
MythDate::kRFC822
@ kRFC822
HTTP Date format.
Definition: mythdate.h:30
HTTPRequest2
std::shared_ptr< MythHTTPRequest > HTTPRequest2
Definition: mythhttptypes.h:38
MythHTTPMetaMethod::CreateReturnValue
static QVariant CreateReturnValue(int Type, void *Value)
Definition: mythhttpmetamethod.cpp:214
mythhttprequest.h
azlyrics.info
dictionary info
Definition: azlyrics.py:7
MythHTTPService::m_request
HTTPRequest2 m_request
Definition: mythhttpservice.h:35
MythHTTPEncoding::GetMimeTypes
static QStringList GetMimeTypes(const QString &Accept)
Definition: mythhttpencoding.cpp:30
HTTPFile
std::shared_ptr< MythHTTPFile > HTTPFile
Definition: mythhttptypes.h:40
HTTPShortLife
@ HTTPShortLife
Definition: mythhttptypes.h:147
HTTPMethodPtr
std::shared_ptr< MythHTTPMetaMethod > HTTPMethodPtr
Definition: mythhttpmetamethod.h:14
build_compdb.options
options
Definition: build_compdb.py:11
MythHTTPService::MythHTTPService
MythHTTPService(MythHTTPMetaService *MetaService)
Definition: mythhttpservice.cpp:16
MythHTTPMetaService
Definition: mythhttpmetaservice.h:10