Skip to content

Commit bdeefbb

Browse files
committed
Put http related functions together in file
1 parent 88bc293 commit bdeefbb

File tree

6 files changed

+191
-167
lines changed

6 files changed

+191
-167
lines changed

CMakeLists.shared

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ set(FLASHMQ_HEADERS
8383
${RELPATH}fdmanaged.h
8484
${RELPATH}checkedweakptr.h
8585
${RELPATH}mutexowned.h
86+
${RELPATH}http.h
8687
)
8788

8889
set(FLASHMQ_IMPLS
@@ -145,4 +146,5 @@ set(FLASHMQ_IMPLS
145146
${RELPATH}globals.cpp
146147
${RELPATH}nocopy.cpp
147148
${RELPATH}fdmanaged.cpp
149+
${RELPATH}http.cpp
148150
)

http.cpp

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
#include "http.h"
2+
3+
#include <sstream>
4+
5+
#include <openssl/evp.h>
6+
#include <openssl/ssl.h>
7+
#include <openssl/err.h>
8+
9+
#include "utils.h"
10+
#include "exceptions.h"
11+
12+
std::string generateWebsocketAcceptString(const std::string &websocketKey)
13+
{
14+
unsigned char md_value[EVP_MAX_MD_SIZE];
15+
unsigned int md_len;
16+
17+
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();;
18+
const EVP_MD *md = EVP_sha1();
19+
EVP_DigestInit_ex(mdctx, md, NULL);
20+
21+
const std::string keyPlusMagic = websocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
22+
23+
EVP_DigestUpdate(mdctx, keyPlusMagic.c_str(), keyPlusMagic.length());
24+
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
25+
EVP_MD_CTX_free(mdctx);
26+
27+
std::string base64 = base64Encode(md_value, md_len);
28+
return base64;
29+
}
30+
31+
std::string generateInvalidWebsocketVersionHttpHeaders(const int wantedVersion)
32+
{
33+
std::ostringstream oss;
34+
oss << "HTTP/1.1 400 Bad Request\r\n";
35+
oss << "Sec-WebSocket-Version: " << wantedVersion;
36+
oss << "\r\n";
37+
oss.flush();
38+
return oss.str();
39+
}
40+
41+
std::string generateBadHttpRequestReponse(const std::string &msg)
42+
{
43+
std::ostringstream oss;
44+
oss << "HTTP/1.1 400 Bad Request\r\n";
45+
oss << "\r\n";
46+
oss << msg;
47+
oss.flush();
48+
return oss.str();
49+
}
50+
51+
std::string generateWebsocketAnswer(const std::string &acceptString, const std::string &subprotocol)
52+
{
53+
std::ostringstream oss;
54+
oss << "HTTP/1.1 101 Switching Protocols\r\n";
55+
oss << "Upgrade: websocket\r\n";
56+
oss << "Connection: Upgrade\r\n";
57+
oss << "Sec-WebSocket-Accept: " << acceptString << "\r\n";
58+
oss << "Sec-WebSocket-Protocol: " << subprotocol << "\r\n";
59+
oss << "\r\n";
60+
oss.flush();
61+
return oss.str();
62+
}
63+
64+
bool parseHttpHeader(CirBuf &buf, std::string &websocket_key, int &websocket_version, std::string &subprotocol, std::string &xRealIp)
65+
{
66+
std::vector<char> buf_data = buf.peekAllToVector();
67+
68+
const std::string s(buf_data.data(), buf_data.size());
69+
std::istringstream is(s);
70+
bool doubleEmptyLine = false; // meaning, the HTTP header is complete
71+
bool upgradeHeaderSeen = false;
72+
bool connectionHeaderSeen = false;
73+
bool firstLine = true;
74+
bool subprotocol_seen = false;
75+
76+
std::string line;
77+
while (std::getline(is, line))
78+
{
79+
trim(line);
80+
if (firstLine)
81+
{
82+
firstLine = false;
83+
if (!startsWith(line, "GET"))
84+
throw BadHttpRequest("Websocket request should start with GET.");
85+
continue;
86+
}
87+
if (line.empty())
88+
{
89+
doubleEmptyLine = true;
90+
break;
91+
}
92+
93+
std::list<std::string> fields = split(line, ':', 1);
94+
95+
if (fields.size() != 2)
96+
{
97+
throw BadHttpRequest("This does not look like a HTTP request.");
98+
}
99+
100+
const std::vector<std::string> fields2(fields.begin(), fields.end());
101+
std::string name = str_tolower(fields2[0]);
102+
trim(name);
103+
std::string value = fields2[1];
104+
trim(value);
105+
std::string value_lower = str_tolower(value);
106+
107+
if (name == "upgrade")
108+
{
109+
std::vector<std::string> protocols = splitToVector(value_lower, ',');
110+
for (std::string &prot : protocols)
111+
{
112+
trim(prot);
113+
114+
if (prot == "websocket")
115+
{
116+
upgradeHeaderSeen = true;
117+
}
118+
}
119+
}
120+
else if (name == "connection" && strContains(value_lower, "upgrade"))
121+
connectionHeaderSeen = true;
122+
else if (name == "sec-websocket-key")
123+
websocket_key = value;
124+
else if (name == "sec-websocket-version")
125+
websocket_version = stoi(value);
126+
else if (name == "sec-websocket-protocol" && strContains(value_lower, "mqtt"))
127+
{
128+
std::vector<std::string> protocols = splitToVector(value, ',');
129+
130+
for(std::string &prot : protocols)
131+
{
132+
trim(prot);
133+
134+
// Return what is requested, which can be 'mqttv3.1' or 'mqtt', or whatever variant.
135+
if (strContains(str_tolower(prot), "mqtt"))
136+
{
137+
subprotocol = prot;
138+
subprotocol_seen = true;
139+
}
140+
}
141+
}
142+
else if (name == "x-real-ip" && value.length() < 64)
143+
{
144+
xRealIp = value;
145+
}
146+
}
147+
148+
if (doubleEmptyLine)
149+
{
150+
if (!connectionHeaderSeen || !upgradeHeaderSeen)
151+
throw BadHttpRequest("HTTP request is not a websocket upgrade request.");
152+
if (!subprotocol_seen)
153+
throw BadHttpRequest("HTTP header Sec-WebSocket-Protocol with value 'mqtt' must be present.");
154+
}
155+
156+
return doubleEmptyLine;
157+
}
158+
159+
std::string websocketCloseCodeToString(uint16_t code)
160+
{
161+
switch (code) {
162+
case 1000:
163+
return "Normal websocket close";
164+
case 1001:
165+
return "Browser navigating away from page";
166+
default:
167+
return formatString("Websocket status code %d", code);
168+
}
169+
}
170+
171+

http.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#ifndef HTTP_H
2+
#define HTTP_H
3+
4+
#include <string>
5+
6+
#include "cirbuf.h"
7+
#include "types.h"
8+
9+
std::string generateWebsocketAcceptString(const std::string &websocketKey);
10+
std::string generateInvalidWebsocketVersionHttpHeaders(const int wantedVersion);
11+
std::string generateBadHttpRequestReponse(const std::string &msg);
12+
std::string generateWebsocketAnswer(const std::string &acceptString, const std::string &subprotocol);
13+
bool parseHttpHeader(CirBuf &buf, std::string &websocket_key, int &websocket_version, std::string &subprotocol, std::string &xRealIp);
14+
std::string websocketCloseCodeToString(uint16_t code);
15+
std::string protocolVersionString(ProtocolVersion p);
16+
17+
#endif // HTTP_H

iowrapper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ See LICENSE for license details.
2222
#include "exceptions.h"
2323
#include "threadglobals.h"
2424
#include "settings.h"
25+
#include "http.h"
2526

2627
IncompleteSslWrite::IncompleteSslWrite(size_t nbytes) :
2728
valid(true),

utils.cpp

Lines changed: 0 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -272,101 +272,6 @@ bool isPowerOfTwo(int n)
272272
return (n != 0) && (n & (n - 1)) == 0;
273273
}
274274

275-
bool parseHttpHeader(CirBuf &buf, std::string &websocket_key, int &websocket_version, std::string &subprotocol, std::string &xRealIp)
276-
{
277-
std::vector<char> buf_data = buf.peekAllToVector();
278-
279-
const std::string s(buf_data.data(), buf_data.size());
280-
std::istringstream is(s);
281-
bool doubleEmptyLine = false; // meaning, the HTTP header is complete
282-
bool upgradeHeaderSeen = false;
283-
bool connectionHeaderSeen = false;
284-
bool firstLine = true;
285-
bool subprotocol_seen = false;
286-
287-
std::string line;
288-
while (std::getline(is, line))
289-
{
290-
trim(line);
291-
if (firstLine)
292-
{
293-
firstLine = false;
294-
if (!startsWith(line, "GET"))
295-
throw BadHttpRequest("Websocket request should start with GET.");
296-
continue;
297-
}
298-
if (line.empty())
299-
{
300-
doubleEmptyLine = true;
301-
break;
302-
}
303-
304-
std::list<std::string> fields = split(line, ':', 1);
305-
306-
if (fields.size() != 2)
307-
{
308-
throw BadHttpRequest("This does not look like a HTTP request.");
309-
}
310-
311-
const std::vector<std::string> fields2(fields.begin(), fields.end());
312-
std::string name = str_tolower(fields2[0]);
313-
trim(name);
314-
std::string value = fields2[1];
315-
trim(value);
316-
std::string value_lower = str_tolower(value);
317-
318-
if (name == "upgrade")
319-
{
320-
std::vector<std::string> protocols = splitToVector(value_lower, ',');
321-
for (std::string &prot : protocols)
322-
{
323-
trim(prot);
324-
325-
if (prot == "websocket")
326-
{
327-
upgradeHeaderSeen = true;
328-
}
329-
}
330-
}
331-
else if (name == "connection" && strContains(value_lower, "upgrade"))
332-
connectionHeaderSeen = true;
333-
else if (name == "sec-websocket-key")
334-
websocket_key = value;
335-
else if (name == "sec-websocket-version")
336-
websocket_version = stoi(value);
337-
else if (name == "sec-websocket-protocol" && strContains(value_lower, "mqtt"))
338-
{
339-
std::vector<std::string> protocols = splitToVector(value, ',');
340-
341-
for(std::string &prot : protocols)
342-
{
343-
trim(prot);
344-
345-
// Return what is requested, which can be 'mqttv3.1' or 'mqtt', or whatever variant.
346-
if (strContains(str_tolower(prot), "mqtt"))
347-
{
348-
subprotocol = prot;
349-
subprotocol_seen = true;
350-
}
351-
}
352-
}
353-
else if (name == "x-real-ip" && value.length() < 64)
354-
{
355-
xRealIp = value;
356-
}
357-
}
358-
359-
if (doubleEmptyLine)
360-
{
361-
if (!connectionHeaderSeen || !upgradeHeaderSeen)
362-
throw BadHttpRequest("HTTP request is not a websocket upgrade request.");
363-
if (!subprotocol_seen)
364-
throw BadHttpRequest("HTTP header Sec-WebSocket-Protocol with value 'mqtt' must be present.");
365-
}
366-
367-
return doubleEmptyLine;
368-
}
369-
370275
std::vector<char> base64Decode(const std::string &s)
371276
{
372277
if (s.length() % 4 != 0)
@@ -405,58 +310,6 @@ std::string base64Encode(const unsigned char *input, const int length)
405310
return result;
406311
}
407312

408-
std::string generateWebsocketAcceptString(const std::string &websocketKey)
409-
{
410-
unsigned char md_value[EVP_MAX_MD_SIZE];
411-
unsigned int md_len;
412-
413-
EVP_MD_CTX *mdctx = EVP_MD_CTX_new();;
414-
const EVP_MD *md = EVP_sha1();
415-
EVP_DigestInit_ex(mdctx, md, NULL);
416-
417-
const std::string keyPlusMagic = websocketKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11";
418-
419-
EVP_DigestUpdate(mdctx, keyPlusMagic.c_str(), keyPlusMagic.length());
420-
EVP_DigestFinal_ex(mdctx, md_value, &md_len);
421-
EVP_MD_CTX_free(mdctx);
422-
423-
std::string base64 = base64Encode(md_value, md_len);
424-
return base64;
425-
}
426-
427-
std::string generateInvalidWebsocketVersionHttpHeaders(const int wantedVersion)
428-
{
429-
std::ostringstream oss;
430-
oss << "HTTP/1.1 400 Bad Request\r\n";
431-
oss << "Sec-WebSocket-Version: " << wantedVersion;
432-
oss << "\r\n";
433-
oss.flush();
434-
return oss.str();
435-
}
436-
437-
std::string generateBadHttpRequestReponse(const std::string &msg)
438-
{
439-
std::ostringstream oss;
440-
oss << "HTTP/1.1 400 Bad Request\r\n";
441-
oss << "\r\n";
442-
oss << msg;
443-
oss.flush();
444-
return oss.str();
445-
}
446-
447-
std::string generateWebsocketAnswer(const std::string &acceptString, const std::string &subprotocol)
448-
{
449-
std::ostringstream oss;
450-
oss << "HTTP/1.1 101 Switching Protocols\r\n";
451-
oss << "Upgrade: websocket\r\n";
452-
oss << "Connection: Upgrade\r\n";
453-
oss << "Sec-WebSocket-Accept: " << acceptString << "\r\n";
454-
oss << "Sec-WebSocket-Protocol: " << subprotocol << "\r\n";
455-
oss << "\r\n";
456-
oss.flush();
457-
return oss.str();
458-
}
459-
460313
// Using a separate ssl context to test, because it's the easiest way to load certs and key atomitcally.
461314
void testSsl(const std::string &fullchain, const std::string &privkey)
462315
{
@@ -628,18 +481,6 @@ std::string sockaddrToString(const sockaddr *addr)
628481
return "[unknown address]";
629482
}
630483

631-
std::string websocketCloseCodeToString(uint16_t code)
632-
{
633-
switch (code) {
634-
case 1000:
635-
return "Normal websocket close";
636-
case 1001:
637-
return "Browser navigating away from page";
638-
default:
639-
return formatString("Websocket status code %d", code);
640-
}
641-
}
642-
643484
std::string protocolVersionString(ProtocolVersion p)
644485
{
645486
switch (p)

0 commit comments

Comments
 (0)