|
| 1 | +#include "HttpRequest.h" |
| 2 | + |
| 3 | +// Definitions // |
| 4 | + |
| 5 | +HttpRequest::HttpRequest(std::string url, httpTypes::REQUEST_METHOD method) |
| 6 | +{ |
| 7 | + // launch the winsock API on windows machines |
| 8 | +#ifdef _PLATFORM_WINDOWS |
| 9 | + this->startWinsock(); |
| 10 | +#endif |
| 11 | + |
| 12 | + // Store the parameters for further operations |
| 13 | + std::cout << "http request object created!" << std::endl; |
| 14 | + m_url = url; |
| 15 | + m_requestMethod = method; |
| 16 | + m_protocol = "http"; |
| 17 | + m_connected = false; |
| 18 | + |
| 19 | + // Setup a tcp socket |
| 20 | + this->m_tcpSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); |
| 21 | +#ifdef _PLATFORM_WINDOWS |
| 22 | + if (m_tcpSocket == INVALID_SOCKET) |
| 23 | + { |
| 24 | + std::cerr << "Could not create tcp socket!" << std::endl; |
| 25 | + return; |
| 26 | + } |
| 27 | +#else |
| 28 | + if (m_tcpSocket < 0) |
| 29 | + { |
| 30 | + std::cerr << "Could not create tcp socket!" << std::endl; |
| 31 | + return; |
| 32 | + } |
| 33 | +#endif |
| 34 | + |
| 35 | + // Now extract the hostaddress, protocol(http/https) and request path from the URL |
| 36 | + std::vector<std::string> tempStr = this->splitString(this->m_url, '/'); |
| 37 | + this->m_host = tempStr.at(2); |
| 38 | + this->m_protocol = tempStr.at(0); |
| 39 | + for (int i = 3; i < tempStr.size(); i++) |
| 40 | + { |
| 41 | + this->m_requestPath += tempStr.at(i) + "/"; |
| 42 | + } |
| 43 | + std::cout << "Webserver address: " << this->m_host << std::endl; |
| 44 | + std::cout << "Request protocol: " << this->m_protocol << std::endl; |
| 45 | + |
| 46 | + // Choose the corresponding port for the detected protocol |
| 47 | + int port = 80; |
| 48 | + if (this->m_protocol == "https:") { |
| 49 | + port = 443; |
| 50 | + } |
| 51 | + |
| 52 | + std::cout << "Connection port: " << port << std::endl; |
| 53 | + |
| 54 | + // Get the IP Address of the target server and create the connection endpoint |
| 55 | + struct hostent* host = gethostbyname(this->m_host.c_str()); |
| 56 | + std::cout << "Final IP Address: " << inet_ntoa(*((struct in_addr*)host->h_addr_list[0])) << std::endl; |
| 57 | + |
| 58 | + // Create the target webserver endpoint using the |
| 59 | + // struct sockaddr_in address = {}; |
| 60 | + this->m_serverAddr = {}; |
| 61 | + m_serverAddr.sin_port = htons(port); |
| 62 | + m_serverAddr.sin_family = AF_INET; |
| 63 | + m_serverAddr.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr*)host->h_addr_list[0]))); |
| 64 | +} |
| 65 | + |
| 66 | +HttpRequest::~HttpRequest() |
| 67 | +{ |
| 68 | + // close the connection and the tcp socket |
| 69 | +#ifdef _PLATFORM_WINDOWS |
| 70 | + closesocket(m_tcpSocket); |
| 71 | +#else |
| 72 | + close(m_tcpSocket); |
| 73 | +#endif |
| 74 | + |
| 75 | + std::cout << "Connection closed" << std::endl; |
| 76 | + std::cout << "request object released!" << std::endl; |
| 77 | + |
| 78 | + // close the winsock API on windows machines |
| 79 | +#ifdef _PLATFORM_WINDOWS |
| 80 | + this->closeWinsock(); |
| 81 | +#endif |
| 82 | +} |
| 83 | + |
| 84 | +void HttpRequest::sendRequest() |
| 85 | +{ |
| 86 | + |
| 87 | + // Connect to the webserver if it isnt't done already |
| 88 | + if (m_connected == false) |
| 89 | + { |
| 90 | + // Attempt to connect to the webserver |
| 91 | + std::cout << "Connection ..." << std::endl; |
| 92 | + int error = connect(this->m_tcpSocket, (struct sockaddr*)&m_serverAddr, sizeof(m_serverAddr)); |
| 93 | + if (error != 0) |
| 94 | + { |
| 95 | + std::cerr << "Failed to connect to the webserver!" << std::endl; |
| 96 | + return; |
| 97 | + } |
| 98 | + |
| 99 | + std::cout << "Connection established" << std::endl; |
| 100 | + this->m_connected = true; |
| 101 | + } |
| 102 | + |
| 103 | + |
| 104 | + // Now construct the HTTP Request Header text |
| 105 | + std::string requestText = this->constructRequestText(); |
| 106 | + |
| 107 | + |
| 108 | + // Send the http request to the webserver |
| 109 | + std::cout << "Sending " << this->m_protocol << " Request ... "; |
| 110 | + int bytesSent = send(m_tcpSocket, requestText.c_str(), (int)strlen(requestText.c_str()), 0); |
| 111 | + std::cout << " Done" << std::endl; |
| 112 | + |
| 113 | + // Wait for a response message |
| 114 | + const int maxResponseLength = 2048; |
| 115 | + |
| 116 | + std::cout << "Waiting for a response ... "; |
| 117 | + char recvBuffer[maxResponseLength]; |
| 118 | + int bytesReceived = recv(m_tcpSocket, recvBuffer, sizeof(recvBuffer), 0); |
| 119 | + if (bytesReceived < 0) |
| 120 | + { |
| 121 | + std::cerr << "\nNo response from the webserver!" << std::endl; |
| 122 | + } |
| 123 | + else |
| 124 | + { |
| 125 | + std::cout << " Done" << std::endl; |
| 126 | + // Nullterminate and store the response text |
| 127 | + if (bytesReceived < maxResponseLength) |
| 128 | + { |
| 129 | + recvBuffer[bytesReceived] = '\0'; |
| 130 | + } |
| 131 | + this->m_responseText = recvBuffer; |
| 132 | + } |
| 133 | + |
| 134 | + return; |
| 135 | +} |
| 136 | + |
| 137 | +void HttpRequest::addParameter(std::string name, std::string value) |
| 138 | +{ |
| 139 | + // Add the parameter to the list |
| 140 | + httpTypes::REQUEST_PARAM parameter; |
| 141 | + parameter.name = name; |
| 142 | + parameter.value = value; |
| 143 | + |
| 144 | + this->m_parameters.push_back(parameter); |
| 145 | + |
| 146 | + return; |
| 147 | +} |
| 148 | + |
| 149 | +void HttpRequest::removeParameter(std::string paramName) |
| 150 | +{ |
| 151 | + // Remove the parameter with the given name from the list |
| 152 | + for (int i = 0; i < this->m_parameters.size(); i++) |
| 153 | + { |
| 154 | + if (this->m_parameters.at(i).name == paramName) { |
| 155 | + // Remove this one and exit |
| 156 | + this->m_parameters.erase(this->m_parameters.begin() + i); |
| 157 | + break; |
| 158 | + } |
| 159 | + } |
| 160 | + |
| 161 | + return; |
| 162 | +} |
| 163 | + |
| 164 | +void HttpRequest::removeAllParameters() |
| 165 | +{ |
| 166 | + // Empty the list of parameters |
| 167 | + this->m_parameters.clear(); |
| 168 | + return; |
| 169 | +} |
| 170 | + |
| 171 | +httpTypes::HTTP_RESPONSE HttpRequest::getResponse() |
| 172 | +{ |
| 173 | + // create a response |
| 174 | + httpTypes::HTTP_RESPONSE response = {}; |
| 175 | + |
| 176 | + // ... |
| 177 | + // response.statusCode = 200; |
| 178 | + // response.text = "<p> Just a dummy response </p>"; |
| 179 | + response.text = this->m_responseText; |
| 180 | + |
| 181 | + return response; |
| 182 | +} |
| 183 | + |
| 184 | +// Private helper functions // |
| 185 | + |
| 186 | +std::vector<std::string> HttpRequest::splitString(const std::string& s, char delimiter) |
| 187 | +{ |
| 188 | + std::vector<std::string> tokens; |
| 189 | + std::string token; |
| 190 | + std::istringstream tokenStream(s); |
| 191 | + while (std::getline(tokenStream, token, delimiter)) |
| 192 | + { |
| 193 | + tokens.push_back(token); |
| 194 | + } |
| 195 | + return tokens; |
| 196 | +} |
| 197 | + |
| 198 | +std::string HttpRequest::constructRequestText() |
| 199 | +{ |
| 200 | + std::string requestStr = ""; |
| 201 | + |
| 202 | + // estimate all parts of the request string |
| 203 | + std::string methodStr = "GET"; |
| 204 | + if (this->m_requestMethod == httpTypes::REQUEST_METHOD::HTTP_POST) |
| 205 | + { |
| 206 | + methodStr = "POST"; |
| 207 | + } |
| 208 | + std::string httpVersion = "HTTP/1.1"; |
| 209 | + |
| 210 | + // put all together |
| 211 | + requestStr += methodStr + " /" + this->m_requestPath; |
| 212 | + // In case of a GET request, append the parameters here |
| 213 | + if (methodStr == "GET") { |
| 214 | + for (int i = 0; i < this->m_parameters.size(); i++) |
| 215 | + { |
| 216 | + // The first GET parameter must have a ? präfix |
| 217 | + if (i == 0) |
| 218 | + { |
| 219 | + requestStr += "?" + this->m_parameters.at(i).name + "=" + this->m_parameters.at(i).value; |
| 220 | + } |
| 221 | + // All other GET parameters must have a & präfix |
| 222 | + else |
| 223 | + { |
| 224 | + requestStr += "&" + this->m_parameters.at(i).name + "=" + this->m_parameters.at(i).value; |
| 225 | + } |
| 226 | + } |
| 227 | + } |
| 228 | + requestStr += " " + httpVersion + "\r\n"; |
| 229 | + requestStr += "Host: " + this->m_host + "\r\n\r\n"; |
| 230 | + |
| 231 | + // quickly output the constructed text |
| 232 | + std::cout << std::endl; |
| 233 | + std::cout << requestStr; |
| 234 | + std::cout << std::endl; |
| 235 | + |
| 236 | + return requestStr; |
| 237 | +} |
| 238 | + |
| 239 | +// Winsock functions - WINDOWS ONLY |
| 240 | +#ifdef _PLATFORM_WINDOWS |
| 241 | + |
| 242 | +void HttpRequest::startWinsock() |
| 243 | +{ |
| 244 | + // launch the Winsock API |
| 245 | + WSADATA wsa; |
| 246 | + int error = WSAStartup(MAKEWORD(2, 2), &wsa); |
| 247 | + if (error != 0) |
| 248 | + { |
| 249 | + // Error! |
| 250 | + } |
| 251 | + |
| 252 | + return; |
| 253 | +} |
| 254 | + |
| 255 | +void HttpRequest::closeWinsock() |
| 256 | +{ |
| 257 | + // Close the winsock API |
| 258 | + WSACleanup(); |
| 259 | + return; |
| 260 | +} |
| 261 | + |
| 262 | +#endif |
0 commit comments