| 1125 | } |
| 1126 | |
| 1127 | static Result DoRequest(HClient client, const char* path, const char* method) |
| 1128 | { |
| 1129 | bool use_proxy = strlen(client->m_ProxyURI.m_Hostname) > 0; |
| 1130 | |
| 1131 | // for proxy connections: |
| 1132 | // client -> CONNECT -> proxy |
| 1133 | // proxy -> TCP connect -> server |
| 1134 | // client <- 200 OK <- proxy |
| 1135 | // client -> TCP send -> proxy -> TCP recv -> server |
| 1136 | // client <- TCP recv <- proxy <- TCP send <- server |
| 1137 | // |
| 1138 | // CONNECT requests should be sent to the proxy |
| 1139 | // CONNECT requests are always done using http |
| 1140 | // CONNECT server.com:1234 HTTP/1.1 |
| 1141 | // CONNECT request should respond with a 200 OK without content |
| 1142 | |
| 1143 | // Theoretically we can be in a state where every |
| 1144 | // connections in the pool is closed by the remote peer |
| 1145 | // but not yet closed on the client side (max-keep-alive) |
| 1146 | // Therefore we must loop MAX_POOL_CONNECTIONS + 1 times. |
| 1147 | // The assumption holds only for a single-threaded environment though |
| 1148 | // but as network errors will occur in practice the heuristic is probably |
| 1149 | // "good enough". |
| 1150 | for (uint32_t i = 0; i < MAX_POOL_CONNECTIONS + 1; ++i) |
| 1151 | { |
| 1152 | // One response owns one pooled connection for one physical attempt. |
| 1153 | Response response(client); |
| 1154 | |
| 1155 | client->m_Statistics.m_Responses++; |
| 1156 | |
| 1157 | client->m_SocketResult = dmSocket::RESULT_OK; |
| 1158 | |
| 1159 | // host, port, secure, timeout, cancel |
| 1160 | Result r = response.Connect(use_proxy ? client->m_ProxyURI.m_Hostname : client->m_HostURI.m_Hostname, |
| 1161 | use_proxy ? client->m_ProxyURI.m_Port : client->m_HostURI.m_Port, |
| 1162 | use_proxy ? false : client->m_Secure, |
| 1163 | client->m_RequestTimeout, |
| 1164 | client->m_CancelFlag); |
| 1165 | if (r != RESULT_OK) |
| 1166 | { |
| 1167 | return r; |
| 1168 | } |
| 1169 | |
| 1170 | if( HasRequestTimedOut(client) ) |
| 1171 | { |
| 1172 | return r; |
| 1173 | } |
| 1174 | |
| 1175 | // client, response, path, method |
| 1176 | r = DoDoRequest(client, |
| 1177 | response, |
| 1178 | use_proxy ? client->m_HostURI.m_Location : path, |
| 1179 | use_proxy ? "CONNECT" : method); |
| 1180 | if (r != RESULT_OK && r != RESULT_NOT_200_OK) |
| 1181 | { |
| 1182 | response.m_CloseConnection = 1; |
| 1183 | |
| 1184 | if( HasRequestTimedOut(client) ) |
no test coverage detected