MythTV master
mythhttpparser.cpp
Go to the documentation of this file.
1// C++
2#include <algorithm>
3
4// Qt
5#include <QTcpSocket>
6
7// MythTV
8#include "mythlogging.h"
9#include "http/mythhttpdata.h"
11#include "http/mythhttpparser.h"
12
13#define LOC QString("HTTPParser: ")
14
15HTTPRequest2 MythHTTPParser::GetRequest(const MythHTTPConfig& Config, QTcpSocket* Socket)
16{
17 // Debug
18 if (VERBOSE_LEVEL_CHECK(VB_HTTP, LOG_DEBUG))
19 {
20 LOG(VB_HTTP, LOG_DEBUG, m_method);
21 for (auto it = m_headers->cbegin(); it != m_headers->cend(); ++it)
22 LOG(VB_HTTP, LOG_DEBUG, it.key() + ": " + it.value());
23 if (m_content.get())
24 LOG(VB_HTTP, LOG_DEBUG, QString("Content:\r\n") + m_content->constData());
25 }
26
27 // Build the request
28 auto result = std::make_shared<MythHTTPRequest>(Config, m_method, m_headers, m_content, Socket);
29
30 // Reset our internal state
31 m_started = false;
32 m_linesRead = 0;
33 m_headersComplete = false;
34 m_method.clear();
36 m_headers = std::make_shared<HTTPMap>();
37 m_content = nullptr;
38
39 return result;
40}
41
42bool MythHTTPParser::Read(QTcpSocket* Socket, bool& Ready)
43{
44 Ready = false;
45
46 // Fail early
47 if (!Socket || (Socket->state() != QAbstractSocket::ConnectedState))
48 return false;
49
50 // Sanity check the number of headers
51 if (!m_headersComplete && m_linesRead > 200)
52 {
53 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Read %1 headers - aborting").arg(m_linesRead));
54 return false;
55 }
56
57 // Filter out non HTTP content quickly. This assumes server side only.
58 if (!m_started && Socket->bytesAvailable() > 2)
59 {
60 QByteArray buf(3, '\0');
61 if (Socket->peek(buf.data(), 3) == 3)
62 {
63 static const std::vector<const char *> s_starters = { "GET", "PUT", "POS", "OPT", "HEA", "DEL" };
64 if (!std::any_of(s_starters.cbegin(), s_starters.cend(), [&](const char * Starter)
65 { return strcmp(Starter, buf.data()) == 0; }))
66 {
67 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Invalid HTTP request start '%1' - quitting").arg(buf.constData()));
68 return false;
69 }
70 }
71 }
72
73 // Read headers
74 while (!m_headersComplete && Socket->canReadLine())
75 {
76 QByteArray line = Socket->readLine().trimmed();
78
79 // A large header suggests an error
80 if (line.size() > 2048)
81 {
82 LOG(VB_GENERAL, LOG_WARNING, LOC + "Unusually long header - quitting");
83 return false;
84 }
85
86 if (line.isEmpty())
87 {
88 m_headersComplete = true;
89 break;
90 }
91
92 if (m_started)
93 {
94 int index = line.indexOf(":");
95 if (index > 0)
96 {
97 QByteArray key = line.left(index).trimmed().toLower();
98 QByteArray value = line.mid(index + 1).trimmed();
99 if (key == "content-length")
100 m_contentLength = value.toLongLong();
101 m_headers->insert(key, value);
102 }
103 else
104 {
105 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Invalid header: '%1'").arg(line.constData()));
106 return false;
107 }
108 }
109 else
110 {
111 m_started = true;
112 m_method = line;
113 }
114 }
115
116 // Need more data...
118 return true;
119
120 // No body?
121 if (m_contentLength < 1)
122 {
123 Ready = true;
124 return true;
125 }
126
127 // Create a buffer for the content if needed
128 if (!m_content)
130
131 // Read contents
132 while ((Socket->state() == QAbstractSocket::ConnectedState) && Socket->bytesAvailable() &&
133 (static_cast<int64_t>(m_content->size()) < m_contentLength))
134 {
135 int64_t want = m_contentLength - m_content->size();
136 int64_t have = Socket->bytesAvailable();
137 m_content->append(Socket->read(std::max({want, HTTP_CHUNKSIZE, have})));
138 }
139
140 // Need more data...
141 if (static_cast<int64_t>(m_content->size()) < m_contentLength)
142 return true;
143
144 Ready = true;
145 return true;
146}
static HTTPData Create()
Definition: mythhttpdata.cpp:4
int64_t m_contentLength
bool Read(QTcpSocket *Socket, bool &Ready)
HTTPRequest2 GetRequest(const MythHTTPConfig &Config, QTcpSocket *Socket)
HTTPData m_content
HTTPHeaders m_headers
#define LOC
std::shared_ptr< MythHTTPRequest > HTTPRequest2
Definition: mythhttptypes.h:39
static bool VERBOSE_LEVEL_CHECK(uint64_t mask, LogLevel_t level)
Definition: mythlogging.h:29
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39