| 6 | #include <stdio.h> // snprintf |
| 7 | |
| 8 | SC::Result SC::HttpTestClient::get(AsyncEventLoop& loop, StringSpan url, bool keepOpen) |
| 9 | { |
| 10 | eventLoop = &loop; |
| 11 | keepConnectionOpen = keepOpen; |
| 12 | |
| 13 | // Parse URL |
| 14 | HttpURLParser urlParser; |
| 15 | SC_TRY(urlParser.parse(url)); |
| 16 | SC_TRY_MSG(urlParser.protocol == "http", "Invalid protocol"); |
| 17 | |
| 18 | // Reset state for new request |
| 19 | parser = {}; |
| 20 | parser.type = HttpParser::Type::Response; |
| 21 | receivedBytes = 0; |
| 22 | parsedBytes = 0; |
| 23 | contentLen = 0; |
| 24 | headersReceived = false; |
| 25 | responseHasNoBody = false; |
| 26 | |
| 27 | { |
| 28 | GrowableBuffer<decltype(content)> gb = {content}; |
| 29 | |
| 30 | HttpStringAppend& sb = static_cast<HttpStringAppend&>(static_cast<IGrowableBuffer&>(gb)); |
| 31 | sb.clear(); |
| 32 | SC_TRY(sb.append("GET ")); |
| 33 | SC_TRY(sb.append(urlParser.path)); |
| 34 | SC_TRY(sb.append(" HTTP/1.1\r\n")); |
| 35 | SC_TRY(sb.append("User-agent: SC\r\n")); |
| 36 | SC_TRY(sb.append("Host: 127.0.0.1\r\n")); |
| 37 | if (keepConnectionOpen) |
| 38 | { |
| 39 | SC_TRY(sb.append("Connection: keep-alive\r\n")); |
| 40 | } |
| 41 | SC_TRY(sb.append("\r\n")); |
| 42 | headerBytes = content.size(); |
| 43 | } |
| 44 | |
| 45 | // If we don't have an active connection or we're not keeping connections open, create a new one |
| 46 | if (not hasActiveConnection or not keepConnectionOpen) |
| 47 | { |
| 48 | uint16_t port; |
| 49 | // TODO: Make DNS Resolution asynchronous |
| 50 | char buffer[256]; |
| 51 | Span<char> ipAddress = {buffer}; |
| 52 | SC_TRY(SocketDNS::resolveDNS(urlParser.hostname, ipAddress)) |
| 53 | port = urlParser.port; |
| 54 | SocketIPAddress localHost; |
| 55 | SC_TRY(localHost.fromAddressPort({ipAddress, true, StringEncoding::Ascii}, port)); |
| 56 | SC_TRY(eventLoop->createAsyncTCPSocket(localHost.getAddressFamily(), clientSocket)); |
| 57 | hasActiveConnection = true; |
| 58 | |
| 59 | connectAsync.callback.bind<HttpTestClient, &HttpTestClient::startSendingHeaders>(*this); |
| 60 | return connectAsync.start(*eventLoop, clientSocket, localHost); |
| 61 | } |
| 62 | else |
| 63 | { |
| 64 | // Reuse existing connection - go directly to sending headers |
| 65 | startSendingHeadersOnExistingConnection(); |
no test coverage detected