* Callback from the WinHTTP library, called when-ever something changes about the HTTP request status. * * The callback needs to call some WinHttp functions for certain states, so WinHttp continues * to read the request. This also allows us to abort when things go wrong, by simply not calling * those functions. * Comments with "Next step:" mark where WinHttp needs a call to continue. * * @p
| 98 | * @param length The length of the information. |
| 99 | */ |
| 100 | void NetworkHTTPRequest::WinHttpCallback(DWORD code, void *info, DWORD length) |
| 101 | { |
| 102 | if (this->finished) return; |
| 103 | |
| 104 | switch (code) { |
| 105 | case WINHTTP_CALLBACK_STATUS_RESOLVING_NAME: |
| 106 | case WINHTTP_CALLBACK_STATUS_NAME_RESOLVED: |
| 107 | case WINHTTP_CALLBACK_STATUS_CONNECTING_TO_SERVER: |
| 108 | case WINHTTP_CALLBACK_STATUS_CONNECTED_TO_SERVER: |
| 109 | case WINHTTP_CALLBACK_STATUS_SENDING_REQUEST: |
| 110 | case WINHTTP_CALLBACK_STATUS_REQUEST_SENT: |
| 111 | case WINHTTP_CALLBACK_STATUS_RECEIVING_RESPONSE: |
| 112 | case WINHTTP_CALLBACK_STATUS_RESPONSE_RECEIVED: |
| 113 | case WINHTTP_CALLBACK_STATUS_CLOSING_CONNECTION: |
| 114 | case WINHTTP_CALLBACK_STATUS_CONNECTION_CLOSED: |
| 115 | case WINHTTP_CALLBACK_STATUS_HANDLE_CREATED: |
| 116 | case WINHTTP_CALLBACK_STATUS_HANDLE_CLOSING: |
| 117 | /* We don't care about these events, and explicitly ignore them. */ |
| 118 | break; |
| 119 | |
| 120 | case WINHTTP_CALLBACK_STATUS_REDIRECT: |
| 121 | /* Make sure we are not in a redirect loop. */ |
| 122 | if (this->depth++ > 5) { |
| 123 | Debug(net, 0, "HTTP request failed: too many redirects"); |
| 124 | this->callback.OnFailure(); |
| 125 | this->finished = true; |
| 126 | return; |
| 127 | } |
| 128 | break; |
| 129 | |
| 130 | case WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE: |
| 131 | /* Next step: read response. */ |
| 132 | WinHttpReceiveResponse(this->request, nullptr); |
| 133 | break; |
| 134 | |
| 135 | case WINHTTP_CALLBACK_STATUS_HEADERS_AVAILABLE: |
| 136 | { |
| 137 | /* Retrieve the status code. */ |
| 138 | DWORD status_code = 0; |
| 139 | DWORD status_code_size = sizeof(status_code); |
| 140 | WinHttpQueryHeaders(this->request, WINHTTP_QUERY_STATUS_CODE | WINHTTP_QUERY_FLAG_NUMBER, WINHTTP_HEADER_NAME_BY_INDEX, &status_code, &status_code_size, WINHTTP_NO_HEADER_INDEX); |
| 141 | Debug(net, 3, "HTTP request status code: {}", status_code); |
| 142 | |
| 143 | /* If there is any error, we simply abort the request. */ |
| 144 | if (status_code >= 400) { |
| 145 | /* No need to be verbose about rate limiting. */ |
| 146 | Debug(net, status_code == HTTP_429_TOO_MANY_REQUESTS ? 1 : 0, "HTTP request failed: status-code {}", status_code); |
| 147 | this->callback.OnFailure(); |
| 148 | this->finished = true; |
| 149 | return; |
| 150 | } |
| 151 | |
| 152 | /* Next step: query for any data. */ |
| 153 | WinHttpQueryDataAvailable(this->request, nullptr); |
| 154 | } break; |
| 155 | |
| 156 | case WINHTTP_CALLBACK_STATUS_DATA_AVAILABLE: |
| 157 | { |
no test coverage detected