Commit 9e554815917bfd7671363baec1d88950498b45ea

Authored by Nodeduino
Committed by Moritz Wirger
1 parent f0b19d95

Add crude windows compatability,

- Rename HttpHandler to linHttpHandler
- Add new winHttpHandler for windows
- Export duplicate functions from win/lin-HttpHandler into IHttpHandler
hueplusplus/include/HttpHandler.h deleted
1   -/**
2   - \file HttpHandler.h
3   - Copyright Notice\n
4   - Copyright (C) 2017 Jan Rogall - developer\n
5   - Copyright (C) 2017 Moritz Wirger - developer\n
6   -
7   - This program is free software; you can redistribute it and/or modify
8   - it under the terms of the GNU General Public License as published by
9   - the Free Software Foundation; either version 3 of the License, or
10   - (at your option) any later version.
11   - This program is distributed in the hope that it will be useful,
12   - but WITHOUT ANY WARRANTY; without even the implied warranty of
13   - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   - GNU General Public License for more details.
15   - You should have received a copy of the GNU General Public License
16   - along with this program; if not, write to the Free Software Foundation,
17   - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18   -**/
19   -
20   -#ifndef _HTTPHANDLER_H
21   -#define _HTTPHANDLER_H
22   -
23   -#include <string>
24   -#include <vector>
25   -
26   -#include "IHttpHandler.h"
27   -
28   -#include "json/json.h"
29   -#include "IHttpHandler.h"
30   -
31   -//! Class to handle http requests and multicast requests
32   -class HttpHandler : public IHttpHandler
33   -{
34   -public:
35   - //! \brief Function that sends a given message to the specified host and returns the response.
36   - //!
37   - //! \param msg String that contains the message that is sent to the specified address
38   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
39   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
40   - //! \return String containing the response of the host
41   - std::string send(const std::string &msg, const std::string &adr, int port=80) const;
42   -
43   - //! \brief Function that sends a given message to the specified host and returns the body of the response.
44   - //!
45   - //! Note if no body is found a runtime error is thrown!
46   - //! \param msg String that contains the message that is sent to the specified address
47   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
48   - //! \param port Optional integer that specifies the port to which the request is sent. Default is 80
49   - //! \return String containing the body of the response of the host
50   - std::string sendGetHTTPBody(const std::string &msg, const std::string &adr, int port = 80) const;
51   -
52   - //! \brief Function that sends a multicast request with the specified message.
53   - //!
54   - //! \param msg String that contains the request that is sent to the specified address
55   - //! \param adr Optional String that contains an ip or hostname in dotted decimal notation, default is "239.255.255.250"
56   - //! \param port Optional integer that specifies the port to which the request is sent. Default is 1900
57   - //! \param timeout Optional Integer that specifies the timeout of the request in seconds. Default is 5
58   - //! \return Vector containing strings of each answer received
59   - std::vector<std::string> sendMulticast(const std::string &msg, const std::string &adr = "239.255.255.250", int port = 1900, int timeout = 5) const;
60   -
61   - //! \brief Function that sends a HTTP request with the given method to the specified host and returns the body of the response.
62   - //!
63   - //! Note body can also be left empty!
64   - //! \param method String that contains the HTTP method type e.g. GET, HEAD, POST, PUT, DELETE, ...
65   - //! \param uri String that contains the uniform resource identifier
66   - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ...
67   - //! \param body String that contains the data of the request
68   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
69   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
70   - //! \return String containing the body of the response of the host
71   - std::string sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const;
72   -
73   - //! \brief Function that sends a HTTP GET request to the specified host and returns the body of the response.
74   - //!
75   - //! Note body can also be left empty!
76   - //! \param uri String that contains the uniform resource identifier
77   - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ...
78   - //! \param body String that contains the data of the request
79   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
80   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
81   - //! \return String containing the body of the response of the host
82   - std::string GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const;
83   -
84   - //! \brief Function that sends a HTTP POST request to the specified host and returns the body of the response.
85   - //!
86   - //! Note body can also be left empty!
87   - //! \param uri String that contains the uniform resource identifier
88   - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ...
89   - //! \param body String that contains the data of the request
90   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
91   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
92   - //! \return String containing the body of the response of the host
93   - std::string POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const;
94   -
95   - //! \brief Function that sends a HTTP PUT request to the specified host and returns the body of the response.
96   - //!
97   - //! Note body can also be left empty!
98   - //! \param uri String that contains the uniform resource identifier
99   - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ...
100   - //! \param body String that contains the data of the request
101   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
102   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
103   - //! \return String containing the body of the response of the host
104   - std::string PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const;
105   -
106   - //! \brief Function that sends a HTTP DELETE request to the specified host and returns the body of the response.
107   - //!
108   - //! Note body can also be left empty!
109   - //! \param uri String that contains the uniform resource identifier
110   - //! \param content_type String that contains the type(MIME) of the body data e.g. "text/html", "application/json", ...
111   - //! \param body String that contains the data of the request
112   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
113   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
114   - //! \return String containing the body of the response of the host
115   - std::string DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const;
116   -
117   - //! \brief Function that sends a HTTP GET request to the specified host and returns the body of the response.
118   - //!
119   - //! Note body can also be left empty!
120   - //! \param uri String that contains the uniform resource identifier
121   - //! \param body Json::Value that contains the data of the request
122   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
123   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
124   - //! \return Json::Value containing the parsed body of the response of the host
125   - Json::Value GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const;
126   -
127   - //! \brief Function that sends a HTTP POST request to the specified host and returns the body of the response.
128   - //!
129   - //! Note body can also be left empty!
130   - //! \param uri String that contains the uniform resource identifier
131   - //! \param body Json::Value that contains the data of the request
132   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
133   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
134   - //! \return Json::Value containing the parsed body of the response of the host
135   - Json::Value POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const;
136   -
137   - //! \brief Function that sends a HTTP PUT request to the specified host and returns the body of the response.
138   - //!
139   - //! Note body can also be left empty!
140   - //! \param uri String that contains the uniform resource identifier
141   - //! \param body Json::Value that contains the data of the request
142   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
143   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
144   - //! \return Json::Value containing the parsed body of the response of the host
145   - Json::Value PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const;
146   -
147   - //! \brief Function that sends a HTTP DELETE request to the specified host and returns the body of the response.
148   - //!
149   - //! Note body can also be left empty!
150   - //! \param uri String that contains the uniform resource identifier
151   - //! \param body Json::Value that contains the data of the request
152   - //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
153   - //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
154   - //! \return Json::Value containing the parsed body of the response of the host
155   - Json::Value DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const;
156   -};
157   -
158   -#endif
hueplusplus/include/IHttpHandler.h
... ... @@ -20,6 +20,8 @@
20 20 #ifndef _IHTTPHANDLER_H
21 21 #define _IHTTPHANDLER_H
22 22  
  23 +#include <iostream>
  24 +#include <memory>
23 25 #include <string>
24 26 #include <vector>
25 27  
... ... @@ -48,7 +50,18 @@ public:
48 50 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
49 51 //! \param port Optional integer that specifies the port to which the request should be sent. Default is 80
50 52 //! \return String containing the body of the response of the host
51   - virtual std::string sendGetHTTPBody(const std::string &msg, const std::string &adr, int port = 80) const = 0;
  53 + virtual std::string sendGetHTTPBody(const std::string &msg, const std::string &adr, int port = 80) const
  54 + {
  55 + std::string response = send(msg, adr, port);
  56 + size_t start = response.find("\r\n\r\n");
  57 + if (start == std::string::npos)
  58 + {
  59 + std::cerr << "Failed to find body in response\n";
  60 + throw(std::runtime_error("Failed to find body in response"));
  61 + }
  62 + response.erase(0, start + 4);
  63 + return response;
  64 + };
52 65  
53 66 //! \brief Virtual function that should send a multicast request with a specified message.
54 67 //!
... ... @@ -69,7 +82,31 @@ public:
69 82 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
70 83 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
71 84 //! \return String containing the body of the response of the host
72   - virtual std::string sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0;
  85 + virtual std::string sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const
  86 + {
  87 + std::string request;
  88 + // Protocol reference: https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
  89 + // Request-Line
  90 + request.append(method); // Method
  91 + request.append(" "); // Separation
  92 + request.append(uri); // Request-URI
  93 + request.append(" "); // Separation
  94 + request.append("HTTP/1.0"); // HTTP-Version
  95 + request.append("\r\n"); // Ending
  96 + // Entities
  97 + request.append("Content-Type:"); // entity-header
  98 + request.append(" "); // Separation
  99 + request.append(content_type); // media-type
  100 + request.append("\r\n"); // Entity ending
  101 + request.append("Content-Length:"); // entity-header
  102 + request.append(" "); // Separation
  103 + request.append(std::to_string(body.size())); // length
  104 + request.append("\r\n\r\n"); // Entity ending & Request-Line ending
  105 + request.append(body); // message-body
  106 + request.append("\r\n\r\n"); // Ending
  107 +
  108 + return sendGetHTTPBody(request.c_str(), adr, port);
  109 + };
73 110  
74 111 //! \brief Virtual function that should send a HTTP GET request to the specified host and return the body of the response.
75 112 //!
... ... @@ -80,7 +117,10 @@ public:
80 117 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
81 118 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
82 119 //! \return String containing the body of the response of the host
83   - virtual std::string GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0;
  120 + virtual std::string GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const
  121 + {
  122 + return sendHTTPRequest("GET", uri, content_type, body, adr, port);
  123 + };
84 124  
85 125 //! \brief Virtual function that should send a HTTP POST request to the specified host and returns the body of the response.
86 126 //!
... ... @@ -91,7 +131,10 @@ public:
91 131 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
92 132 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
93 133 //! \return String containing the body of the response of the host
94   - virtual std::string POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0;
  134 + virtual std::string POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const
  135 + {
  136 + return sendHTTPRequest("POST", uri, content_type, body, adr, port);
  137 + };
95 138  
96 139 //! \brief Virtual function that should send a HTTP PUT request to the specified host and return the body of the response.
97 140 //!
... ... @@ -102,7 +145,10 @@ public:
102 145 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
103 146 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
104 147 //! \return String containing the body of the response of the host
105   - virtual std::string PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0;
  148 + virtual std::string PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const
  149 + {
  150 + return sendHTTPRequest("PUT", uri, content_type, body, adr, port);
  151 + };
106 152  
107 153 //! \brief Virtual function that should send a HTTP DELETE request to the specified host and return the body of the response.
108 154 //!
... ... @@ -113,7 +159,10 @@ public:
113 159 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
114 160 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
115 161 //! \return String containing the body of the response of the host
116   - virtual std::string DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const = 0;
  162 + virtual std::string DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port=80) const
  163 + {
  164 + return sendHTTPRequest("DELETE", uri, content_type, body, adr, port);
  165 + };
117 166  
118 167 //! \brief Virtual function that should send a HTTP GET request to the specified host and return the body of the response.
119 168 //!
... ... @@ -123,7 +172,22 @@ public:
123 172 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
124 173 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
125 174 //! \return Json::Value containing the parsed body of the response of the host
126   - virtual Json::Value GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0;
  175 + virtual Json::Value GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const
  176 + {
  177 + std::string response = GETString(uri, "application/json", body.toStyledString(), adr, port);
  178 +
  179 + std::string error;
  180 + Json::Value result;
  181 + Json::CharReaderBuilder builder;
  182 + builder["collectComments"] = false;
  183 + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
  184 + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
  185 + {
  186 + std::cout << "Error while parsing JSON in function GETJson() of linHttpHandler: " << error << std::endl;
  187 + throw(std::runtime_error("Error while parsing JSON in function GETJson() of linHttpHandler"));
  188 + }
  189 + return result;
  190 + };
127 191  
128 192 //! \brief Virtual function that should send a HTTP POST request to the specified host and return the body of the response.
129 193 //!
... ... @@ -133,7 +197,22 @@ public:
133 197 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
134 198 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
135 199 //! \return Json::Value containing the parsed body of the response of the host
136   - virtual Json::Value POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0;
  200 + virtual Json::Value POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const
  201 + {
  202 + std::string response = POSTString(uri, "application/json", body.toStyledString(), adr, port);
  203 +
  204 + std::string error;
  205 + Json::Value result;
  206 + Json::CharReaderBuilder builder;
  207 + builder["collectComments"] = false;
  208 + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
  209 + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
  210 + {
  211 + std::cout << "Error while parsing JSON in function POSTJson() of linHttpHandler: " << error << std::endl;
  212 + throw(std::runtime_error("Error while parsing JSON in function POSTJson() of linHttpHandler"));
  213 + }
  214 + return result;
  215 + }
137 216  
138 217 //! \brief Virtual function that should send a HTTP PUT request to the specified host and return the body of the response.
139 218 //!
... ... @@ -143,7 +222,22 @@ public:
143 222 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
144 223 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
145 224 //! \return Json::Value containing the parsed body of the response of the host
146   - virtual Json::Value PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0;
  225 + virtual Json::Value PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const
  226 + {
  227 + std::string response = PUTString(uri, "application/json", body.toStyledString(), adr, port);
  228 +
  229 + std::string error;
  230 + Json::Value result;
  231 + Json::CharReaderBuilder builder;
  232 + builder["collectComments"] = false;
  233 + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
  234 + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
  235 + {
  236 + std::cout << "Error while parsing JSON in function PUTJson() of linHttpHandler: " << error << std::endl;
  237 + throw(std::runtime_error("Error while parsing JSON in function PUTJson() of linHttpHandler"));
  238 + }
  239 + return result;
  240 + };
147 241  
148 242 //! \brief Virtual function that should send a HTTP DELETE request to the specified host and return the body of the response.
149 243 //!
... ... @@ -153,7 +247,22 @@ public:
153 247 //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
154 248 //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
155 249 //! \return Json::Value containing the parsed body of the response of the host
156   - virtual Json::Value DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const = 0;
  250 + virtual Json::Value DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port=80) const
  251 + {
  252 + std::string response = DELETEString(uri, "application/json", body.toStyledString(), adr, port);
  253 +
  254 + std::string error;
  255 + Json::Value result;
  256 + Json::CharReaderBuilder builder;
  257 + builder["collectComments"] = false;
  258 + std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
  259 + if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
  260 + {
  261 + std::cout << "Error while parsing JSON in function PUTJson() of linHttpHandler: " << error << std::endl;
  262 + throw(std::runtime_error("Error while parsing JSON in function PUTJson() of linHttpHandler"));
  263 + }
  264 + return result;
  265 + };
157 266 };
158 267  
159 268 #endif
... ...
hueplusplus/include/linHttpHandler.h 0 โ†’ 100644
  1 +/**
  2 + \file linHttpHandler.h
  3 + Copyright Notice\n
  4 + Copyright (C) 2017 Jan Rogall - developer\n
  5 + Copyright (C) 2017 Moritz Wirger - developer\n
  6 +
  7 + This program is free software; you can redistribute it and/or modify
  8 + it under the terms of the GNU General Public License as published by
  9 + the Free Software Foundation; either version 3 of the License, or
  10 + (at your option) any later version.
  11 + This program is distributed in the hope that it will be useful,
  12 + but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 + GNU General Public License for more details.
  15 + You should have received a copy of the GNU General Public License
  16 + along with this program; if not, write to the Free Software Foundation,
  17 + Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18 +**/
  19 +
  20 +#ifndef _LINHTTPHANDLER_H
  21 +#define _LINHTTPHANDLER_H
  22 +
  23 +#include <string>
  24 +#include <vector>
  25 +
  26 +#include "IHttpHandler.h"
  27 +
  28 +#include "json/json.h"
  29 +
  30 +//! Class to handle http requests and multicast requests on linux systems
  31 +class linHttpHandler : public IHttpHandler
  32 +{
  33 +public:
  34 + //! \brief Function that sends a given message to the specified host and returns the response.
  35 + //!
  36 + //! \param msg String that contains the message that is sent to the specified address
  37 + //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
  38 + //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
  39 + //! \return String containing the response of the host
  40 + std::string send(const std::string &msg, const std::string &adr, int port=80) const;
  41 +
  42 + //! \brief Function that sends a multicast request with the specified message.
  43 + //!
  44 + //! \param msg String that contains the request that is sent to the specified address
  45 + //! \param adr Optional String that contains an ip or hostname in dotted decimal notation, default is "239.255.255.250"
  46 + //! \param port Optional integer that specifies the port to which the request is sent. Default is 1900
  47 + //! \param timeout Optional Integer that specifies the timeout of the request in seconds. Default is 5
  48 + //! \return Vector containing strings of each answer received
  49 + std::vector<std::string> sendMulticast(const std::string &msg, const std::string &adr = "239.255.255.250", int port = 1900, int timeout = 5) const;
  50 +};
  51 +
  52 +#endif
... ...
hueplusplus/include/winHttpHandler.h 0 โ†’ 100644
  1 +/**
  2 +\file winHttpHandler.h
  3 +Copyright Notice\n
  4 +Copyright (C) 2017 Jan Rogall - developer\n
  5 +Copyright (C) 2017 Moritz Wirger - developer\n
  6 +
  7 +This program is free software; you can redistribute it and/or modify
  8 +it under the terms of the GNU General Public License as published by
  9 +the Free Software Foundation; either version 3 of the License, or
  10 +(at your option) any later version.
  11 +This program is distributed in the hope that it will be useful,
  12 +but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 +GNU General Public License for more details.
  15 +You should have received a copy of the GNU General Public License
  16 +along with this program; if not, write to the Free Software Foundation,
  17 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18 +**/
  19 +
  20 +#ifndef _WINHTTPHANDLER_H
  21 +#define _WINHTTPHANDLER_H
  22 +
  23 +#include <string>
  24 +#include <vector>
  25 +#include <winsock2.h>
  26 +
  27 +#include "IHttpHandler.h"
  28 +
  29 +#include "json/json.h"
  30 +
  31 +//! Class to handle http requests and multicast requests on windows systems
  32 +class winHttpHandler : public IHttpHandler
  33 +{
  34 +public:
  35 + //! \brief Ctor needed for initializing wsaData
  36 + winHttpHandler();
  37 +
  38 + //! \brief Dtor needed for wsaData cleanup
  39 + ~winHttpHandler();
  40 +
  41 + //! \brief Function that sends a given message to the specified host and returns the response.
  42 + //!
  43 + //! \param msg String that contains the message that is sent to the specified address
  44 + //! \param adr String that contains an ip or hostname in dotted decimal notation like "192.168.2.1"
  45 + //! \param port Optional integer that specifies the port to which the request is sent to. Default is 80
  46 + //! \return String containing the response of the host
  47 + std::string send(const std::string &msg, const std::string &adr, int port = 80) const;
  48 +
  49 + //! \brief Function that sends a multicast request with the specified message.
  50 + //!
  51 + //! \param msg String that contains the request that is sent to the specified address
  52 + //! \param adr Optional String that contains an ip or hostname in dotted decimal notation, default is "239.255.255.250"
  53 + //! \param port Optional integer that specifies the port to which the request is sent. Default is 1900
  54 + //! \param timeout Optional Integer that specifies the timeout of the request in seconds. Default is 5
  55 + //! \return Vector containing strings of each answer received
  56 + std::vector<std::string> sendMulticast(const std::string &msg, const std::string &adr = "239.255.255.250", int port = 1900, int timeout = 5) const;
  57 +
  58 +private:
  59 + WSADATA wsaData;
  60 +};
  61 +
  62 +#endif
... ...
hueplusplus/HttpHandler.cpp renamed to hueplusplus/linHttpHandler.cpp 100755 โ†’ 100644
1 1 /**
2   - \file HttpHandler.cpp
  2 + \file linHttpHandler.cpp
3 3 Copyright Notice\n
4 4 Copyright (C) 2017 Jan Rogall - developer\n
5 5 Copyright (C) 2017 Moritz Wirger - developer\n
... ... @@ -17,7 +17,9 @@
17 17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 18 **/
19 19  
20   -#include "include/HttpHandler.h"
  20 +#include "include/linHttpHandler.h"
  21 +
  22 +#ifndef _MSC_VER
21 23  
22 24 #include <chrono>
23 25 #include <netinet/in.h> // struct sockaddr_in, struct sockaddr
... ... @@ -38,7 +40,7 @@ class SocketCloser {
38 40 private: int s;
39 41 };
40 42  
41   -std::string HttpHandler::send(const std::string & msg, const std::string & adr, int port) const
  43 +std::string linHttpHandler::send(const std::string & msg, const std::string & adr, int port) const
42 44 {
43 45 // create socket
44 46 int socketFD = socket(AF_INET, SOCK_STREAM, 0);
... ... @@ -127,20 +129,7 @@ std::string HttpHandler::send(const std::string &amp; msg, const std::string &amp; adr,
127 129 return response;
128 130 }
129 131  
130   -std::string HttpHandler::sendGetHTTPBody(const std::string & msg, const std::string & adr, int port) const
131   -{
132   - std::string response = send(msg, adr, port);
133   - size_t start = response.find("\r\n\r\n");
134   - if (start == std::string::npos)
135   - {
136   - std::cerr << "Failed to find body in response\n";
137   - throw(std::runtime_error("Failed to find body in response"));
138   - }
139   - response.erase(0, start + 4);
140   - return response;
141   -}
142   -
143   -std::vector<std::string> HttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const
  132 +std::vector<std::string> linHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const
144 133 {
145 134 hostent *server; // host information
146 135 sockaddr_in server_addr; // server address
... ... @@ -219,116 +208,4 @@ std::vector&lt;std::string&gt; HttpHandler::sendMulticast(const std::string &amp; msg, con
219 208 return returnString;
220 209 }
221 210  
222   -std::string HttpHandler::sendHTTPRequest(std::string method, std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const
223   -{
224   - std::string request;
225   - // Protocol reference: https://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
226   - // Request-Line
227   - request.append(method); // Method
228   - request.append(" "); // Separation
229   - request.append(uri); // Request-URI
230   - request.append(" "); // Separation
231   - request.append("HTTP/1.0"); // HTTP-Version
232   - request.append("\r\n"); // Ending
233   - // Entities
234   - request.append("Content-Type:"); // entity-header
235   - request.append(" "); // Separation
236   - request.append(content_type); // media-type
237   - request.append("\r\n"); // Entity ending
238   - request.append("Content-Length:"); // entity-header
239   - request.append(" "); // Separation
240   - request.append(std::to_string(body.size())); // length
241   - request.append("\r\n\r\n"); // Entity ending & Request-Line ending
242   - request.append(body); // message-body
243   - request.append("\r\n\r\n"); // Ending
244   -
245   - return sendGetHTTPBody(request.c_str(), adr, port);
246   -}
247   -
248   -std::string HttpHandler::GETString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const
249   -{
250   - return sendHTTPRequest("GET", uri, content_type, body, adr, port);
251   -}
252   -
253   -std::string HttpHandler::POSTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const
254   -{
255   - return sendHTTPRequest("POST", uri, content_type, body, adr, port);
256   -}
257   -
258   -std::string HttpHandler::PUTString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const
259   -{
260   - return sendHTTPRequest("PUT", uri, content_type, body, adr, port);
261   -}
262   -
263   -std::string HttpHandler::DELETEString(std::string uri, std::string content_type, std::string body, const std::string &adr, int port) const
264   -{
265   - return sendHTTPRequest("DELETE", uri, content_type, body, adr, port);
266   -}
267   -
268   -Json::Value HttpHandler::GETJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const
269   -{
270   - std::string response = GETString(uri, "application/json", body.toStyledString(), adr, port);
271   -
272   - std::string error;
273   - Json::Value result;
274   - Json::CharReaderBuilder builder;
275   - builder["collectComments"] = false;
276   - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
277   - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
278   - {
279   - std::cout << "Error while parsing JSON in function GETJson() of HttpHandler: " << error << std::endl;
280   - throw(std::runtime_error("Error while parsing JSON in function GETJson() of HttpHandler"));
281   - }
282   - return result;
283   -}
284   -
285   -Json::Value HttpHandler::POSTJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const
286   -{
287   - std::string response = POSTString(uri, "application/json", body.toStyledString(), adr, port);
288   -
289   - std::string error;
290   - Json::Value result;
291   - Json::CharReaderBuilder builder;
292   - builder["collectComments"] = false;
293   - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
294   - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
295   - {
296   - std::cout << "Error while parsing JSON in function POSTJson() of HttpHandler: " << error << std::endl;
297   - throw(std::runtime_error("Error while parsing JSON in function POSTJson() of HttpHandler"));
298   - }
299   - return result;
300   -}
301   -
302   -Json::Value HttpHandler::PUTJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const
303   -{
304   - std::string response = PUTString(uri, "application/json", body.toStyledString(), adr, port);
305   -
306   - std::string error;
307   - Json::Value result;
308   - Json::CharReaderBuilder builder;
309   - builder["collectComments"] = false;
310   - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
311   - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
312   - {
313   - std::cout << "Error while parsing JSON in function PUTJson() of HttpHandler: " << error << std::endl;
314   - throw(std::runtime_error("Error while parsing JSON in function PUTJson() of HttpHandler"));
315   - }
316   - return result;
317   -}
318   -
319   -Json::Value HttpHandler::DELETEJson(std::string uri, const Json::Value& body, const std::string &adr, int port) const
320   -{
321   - std::string response = DELETEString(uri, "application/json", body.toStyledString(), adr, port);
322   -
323   - std::string error;
324   - Json::Value result;
325   - Json::CharReaderBuilder builder;
326   - builder["collectComments"] = false;
327   - std::unique_ptr<Json::CharReader> reader = std::unique_ptr<Json::CharReader>(builder.newCharReader());
328   - if (!reader->parse(response.c_str(), response.c_str() + response.length(), &result, &error))
329   - {
330   - std::cout << "Error while parsing JSON in function PUTJson() of HttpHandler: " << error << std::endl;
331   - throw(std::runtime_error("Error while parsing JSON in function PUTJson() of HttpHandler"));
332   - }
333   - return result;
334   -}
  211 +#endif
... ...
hueplusplus/winHttpHandler.cpp 0 โ†’ 100644
  1 +/**
  2 +\file winHttpHandler.cpp
  3 +Copyright Notice\n
  4 +Copyright (C) 2017 Jan Rogall - developer\n
  5 +Copyright (C) 2017 Moritz Wirger - developer\n
  6 +
  7 +This program is free software; you can redistribute it and/or modify
  8 +it under the terms of the GNU General Public License as published by
  9 +the Free Software Foundation; either version 3 of the License, or
  10 +(at your option) any later version.
  11 +This program is distributed in the hope that it will be useful,
  12 +but WITHOUT ANY WARRANTY; without even the implied warranty of
  13 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14 +GNU General Public License for more details.
  15 +You should have received a copy of the GNU General Public License
  16 +along with this program; if not, write to the Free Software Foundation,
  17 +Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  18 +**/
  19 +
  20 +#include "include/winHttpHandler.h"
  21 +
  22 +#ifdef _MSC_VER
  23 +
  24 +#include <chrono>
  25 +#include <iostream>
  26 +#include <memory>
  27 +#include <stdio.h>
  28 +#include <ws2tcpip.h>
  29 +
  30 +#pragma comment(lib, "Ws2_32.lib")
  31 +
  32 +winHttpHandler::winHttpHandler()
  33 +{
  34 + // Initialize Winsock
  35 + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
  36 + {
  37 + std::cerr << "Failed to open socket: " << WSAGetLastError() << std::endl;
  38 + throw(std::runtime_error("Failed to open socket"));
  39 + }
  40 +}
  41 +
  42 +winHttpHandler::~winHttpHandler()
  43 +{
  44 + WSACleanup();
  45 +}
  46 +
  47 +std::string winHttpHandler::send(const std::string & msg, const std::string & adr, int port) const
  48 +{
  49 + struct addrinfo *result = nullptr, *ptr = nullptr, hints;
  50 +
  51 + ZeroMemory(&hints, sizeof(hints));
  52 + hints.ai_family = AF_INET;
  53 + hints.ai_socktype = SOCK_STREAM;
  54 + hints.ai_protocol = IPPROTO_TCP;
  55 +
  56 + // Resolve the server address and port
  57 + int res = getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result);
  58 + if (res != 0)
  59 + {
  60 + std::cerr << "getaddrinfo failed: " << res << std::endl;
  61 + throw(std::runtime_error("getaddrinfo failed"));
  62 + }
  63 +
  64 + SOCKET connect_socket = INVALID_SOCKET;
  65 +
  66 +
  67 + // Attempt to connect to the first address returned by
  68 + // the call to getaddrinfo
  69 + ptr = result;
  70 +
  71 + // Create a SOCKET for connecting to server
  72 + connect_socket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
  73 +
  74 + if (connect_socket == INVALID_SOCKET)
  75 + {
  76 + freeaddrinfo(result);
  77 + std::cerr << "Error at socket(): " << WSAGetLastError() << std::endl;
  78 + throw(std::runtime_error("Error at socket()"));
  79 + }
  80 +
  81 + // Connect to server.
  82 + res = connect(connect_socket, ptr->ai_addr, (int)ptr->ai_addrlen);
  83 + if (res == SOCKET_ERROR)
  84 + {
  85 + closesocket(connect_socket);
  86 + connect_socket = INVALID_SOCKET;
  87 + }
  88 +
  89 + // Should really try the next address returned by getaddrinfo
  90 + // if the connect call failed
  91 + // But for this simple example we just free the resources
  92 + // returned by getaddrinfo and print an error message
  93 +
  94 + freeaddrinfo(result);
  95 +
  96 + if (connect_socket == INVALID_SOCKET)
  97 + {
  98 + std::cerr << "Unable to connect to server!" << std::endl;
  99 + throw(std::runtime_error("Unable to connect to server!"));
  100 + }
  101 +
  102 + // Send an initial buffer
  103 + res = ::send(connect_socket, msg.c_str(), msg.size(), 0);
  104 + if (res == SOCKET_ERROR)
  105 + {
  106 + std::cerr << "send failed: " << WSAGetLastError() << std::endl;
  107 + throw(std::runtime_error("send failed"));
  108 + }
  109 +
  110 + // shutdown the connection for sending since no more data will be sent
  111 + // the client can still use the ConnectSocket for receiving data
  112 + res = shutdown(connect_socket, SD_SEND);
  113 + if (res == SOCKET_ERROR)
  114 + {
  115 + closesocket(connect_socket);
  116 + std::cerr << "shutdown failed: " << WSAGetLastError() << std::endl;
  117 + throw(std::runtime_error("shutdown failed"));
  118 + }
  119 +
  120 + const int recvbuflen = 128;
  121 + char recvbuf[recvbuflen];
  122 +
  123 + // Receive data until the server closes the connection
  124 + std::string response;
  125 + int received = 0;
  126 + do
  127 + {
  128 + res = recv(connect_socket, recvbuf, recvbuflen, 0);
  129 + if (res > 0)
  130 + {
  131 + std::cout << "Bytes received: " << res << std::endl;
  132 + response.append(recvbuf, res);
  133 + }
  134 + else if (res == 0)
  135 + {
  136 + std::cout << "Connection closed " << std::endl;
  137 + }
  138 + else
  139 + {
  140 + std::cerr << "recv failed: " << WSAGetLastError() << std::endl;
  141 + throw(std::runtime_error("recv failed"));
  142 + }
  143 + } while (res > 0);
  144 +
  145 + return response;
  146 +}
  147 +
  148 +std::vector<std::string> winHttpHandler::sendMulticast(const std::string & msg, const std::string & adr, int port, int timeout) const
  149 +{
  150 + struct addrinfo *result = nullptr, *ptr = nullptr, hints;
  151 + SOCKADDR_IN source_sin, dest_sin;
  152 +
  153 + ZeroMemory(&hints, sizeof(hints));
  154 + hints.ai_family = AF_INET;
  155 + hints.ai_socktype = SOCK_DGRAM;
  156 + hints.ai_protocol = IPPROTO_TCP;
  157 +
  158 + // Resolve the server address and port
  159 + int res = getaddrinfo(adr.c_str(), std::to_string(port).c_str(), &hints, &result);
  160 + if (res != 0)
  161 + {
  162 + std::cerr << "sendMulticast: getaddrinfo failed: " << res << std::endl;
  163 + throw(std::runtime_error("getaddrinfo failed"));
  164 + }
  165 +
  166 + SOCKET connect_socket = INVALID_SOCKET;
  167 +
  168 +
  169 + // Attempt to connect to the first address returned by
  170 + // the call to getaddrinfo
  171 + ptr = result;
  172 +
  173 + // Create a SOCKET for connecting to server
  174 + if ((connect_socket = socket(ptr->ai_family, ptr->ai_socktype, 0)) == INVALID_SOCKET)
  175 + {
  176 + freeaddrinfo(result);
  177 + std::cerr << "sendMulticast: Error at socket(): " << WSAGetLastError() << std::endl;
  178 + throw(std::runtime_error("Error at socket()"));
  179 + }
  180 +
  181 + // Fill out source socket's address information.
  182 + source_sin.sin_family = AF_INET;
  183 + source_sin.sin_port = htons(0);
  184 + source_sin.sin_addr.s_addr = htonl(INADDR_ANY);
  185 +
  186 + // Associate the source socket's address with the socket, Sock.
  187 + if (bind(connect_socket, (struct sockaddr FAR *) &source_sin, sizeof(source_sin)) == SOCKET_ERROR)
  188 + {
  189 + closesocket(connect_socket);
  190 + std::cerr << "sendMulticast: Binding socket failed: " << WSAGetLastError() << std::endl;
  191 + throw(std::runtime_error("Binding socket failed"));
  192 + }
  193 +
  194 + u_long sock_mode = 1;
  195 + ioctlsocket(connect_socket, FIONBIO, &sock_mode);
  196 +
  197 + BOOL bOptVal = TRUE;
  198 + setsockopt(connect_socket, SOL_SOCKET, SO_BROADCAST, (char *)&bOptVal, sizeof(bOptVal));
  199 +
  200 + // Set the Time-to-Live of the multicast.
  201 + int iOptVal = 64;
  202 + if (setsockopt(connect_socket, IPPROTO_IP, IP_MULTICAST_TTL, (char FAR *)&iOptVal, sizeof(int)) == SOCKET_ERROR)
  203 + {
  204 + closesocket(connect_socket);
  205 + std::cerr << "sendMulticast: setsockopt failed: " << WSAGetLastError() << std::endl;
  206 + throw(std::runtime_error("setsockopt failed"));
  207 + }
  208 +
  209 + // Fill out the desination socket's address information.
  210 + dest_sin.sin_family = AF_INET;
  211 + dest_sin.sin_port = htons(port);
  212 + dest_sin.sin_addr.s_addr = inet_addr((const char*)ptr->ai_addr);
  213 +
  214 + // Send a message to the multicasting address.
  215 + if (sendto(connect_socket, msg.c_str(), msg.size(), 0, (struct sockaddr FAR *) &dest_sin, sizeof(dest_sin)) == SOCKET_ERROR)
  216 + {
  217 + std::cerr << "sendMulticast: sendto failed: " << WSAGetLastError() << std::endl;
  218 + closesocket(connect_socket);
  219 + throw(std::runtime_error("sendto failed"));
  220 + }
  221 +
  222 + // shutdown the connection for sending since no more data will be sent
  223 + // the client can still use the ConnectSocket for receiving data
  224 + res = shutdown(connect_socket, SD_SEND);
  225 + if (res == SOCKET_ERROR)
  226 + {
  227 + closesocket(connect_socket);
  228 + std::cerr << "sendMulticast: shutdown failed: " << WSAGetLastError() << std::endl;
  229 + throw(std::runtime_error("shutdown failed"));
  230 + }
  231 +
  232 + std::string response;
  233 + const int recvbuflen = 2048;
  234 + char recvbuf[recvbuflen] = {};
  235 + std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();
  236 + while (std::chrono::steady_clock::now() - start < std::chrono::seconds(timeout))
  237 + {
  238 + res = recv(connect_socket, recvbuf, recvbuflen, 0);
  239 + if (res > 0)
  240 + {
  241 + std::cout << "sendMulticast: Bytes received: " << res << std::endl;
  242 + response.append(recvbuf, res);
  243 + }
  244 + else if (res == 0)
  245 + {
  246 + std::cout << "sendMulticast: Connection closed " << std::endl;
  247 + }
  248 + else
  249 + {
  250 + // No exception here due to non blocking socket
  251 + //std::cerr << "sendMulticast: recv failed: " << WSAGetLastError() << std::endl;
  252 + //throw(std::runtime_error("recv failed"));
  253 + }
  254 + }
  255 + closesocket(connect_socket); // Is this needed?
  256 +
  257 + // construct return vector
  258 + std::vector<std::string> returnString;
  259 + size_t pos = response.find("\r\n\r\n");
  260 + size_t prevpos = 0;
  261 + while (pos != std::string::npos)
  262 + {
  263 + returnString.push_back(response.substr(prevpos, pos - prevpos));
  264 + pos += 4;
  265 + prevpos = pos;
  266 + pos = response.find("\r\n\r\n", pos);
  267 + }
  268 +
  269 + return returnString;
  270 +}
  271 +
  272 +#endif
... ...