|
19 | 19 | #include <algorithm> |
20 | 20 | #include <cassert> |
21 | 21 | #include <thread> |
| 22 | +#include <ostream> |
22 | 23 |
|
23 | 24 | using namespace Aws::Client; |
24 | 25 | using namespace Aws::Http; |
@@ -181,6 +182,27 @@ static int64_t GetContentLengthFromHeader(CURL* connectionHandle, |
181 | 182 | return hasContentLength ? static_cast<int64_t>(contentLength) : -1; |
182 | 183 | } |
183 | 184 |
|
| 185 | +// Best-effort output position probe for diagnostics only. |
| 186 | +// Returns false if the stream does not support positioning. |
| 187 | +static bool TryGetOutputPos(std::ostream& os, |
| 188 | + std::ostream::pos_type& outPos) noexcept |
| 189 | +{ |
| 190 | + std::streambuf* sb = os.rdbuf(); |
| 191 | + if (!sb) |
| 192 | + { |
| 193 | + return false; |
| 194 | + } |
| 195 | + |
| 196 | + const auto pos = sb->pubseekoff(0, std::ios_base::cur, std::ios_base::out); |
| 197 | + if (pos == std::ostream::pos_type(std::ostream::off_type(-1))) |
| 198 | + { |
| 199 | + return false; |
| 200 | + } |
| 201 | + |
| 202 | + outPos = pos; |
| 203 | + return true; |
| 204 | +} |
| 205 | + |
184 | 206 | static size_t WriteData(char* ptr, size_t size, size_t nmemb, void* userdata) |
185 | 207 | { |
186 | 208 | if (ptr) |
@@ -217,38 +239,51 @@ static size_t WriteData(char* ptr, size_t size, size_t nmemb, void* userdata) |
217 | 239 | } |
218 | 240 | } |
219 | 241 |
|
220 | | - if (response->GetResponseBody().fail()) { |
221 | | - const auto& ref = response->GetResponseBody(); |
222 | | - AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Response output stream in bad state (eof: " |
223 | | - << ref.eof() << ", bad: " << ref.bad() << ")"); |
224 | | - return 0; |
225 | | - } |
| 242 | + auto& body = response->GetResponseBody(); |
226 | 243 |
|
227 | | - auto cur = response->GetResponseBody().tellp(); |
228 | | - if (response->GetResponseBody().fail()) { |
229 | | - const auto& ref = response->GetResponseBody(); |
230 | | - AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Unable to query response output position (eof: " |
231 | | - << ref.eof() << ", bad: " << ref.bad() << ")"); |
| 244 | + if (body.fail()) { |
| 245 | + const auto& ref = body; |
| 246 | + AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, |
| 247 | + "Response output stream in bad state (eof: " |
| 248 | + << ref.eof() << ", bad: " << ref.bad() << ")"); |
232 | 249 | return 0; |
233 | 250 | } |
234 | 251 |
|
235 | | - response->GetResponseBody().write(ptr, static_cast<std::streamsize>(sizeToWrite)); |
236 | | - if (response->GetResponseBody().fail()) { |
237 | | - const auto& ref = response->GetResponseBody(); |
238 | | - AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Failed to write " << size << " / " << sizeToWrite << " B response" |
239 | | - << " at " << cur << " (eof: " << ref.eof() << ", bad: " << ref.bad() << ")"); |
| 252 | + body.write(ptr, static_cast<std::streamsize>(sizeToWrite)); |
| 253 | + if (body.fail()) { |
| 254 | + const auto& ref = body; |
| 255 | + |
| 256 | + std::ostream::pos_type pos{}; |
| 257 | + const bool hasPos = TryGetOutputPos(body, pos); |
| 258 | + |
| 259 | + Aws::StringStream ss; |
| 260 | + ss << "Failed to write " << size << " / " << sizeToWrite << " B response"; |
| 261 | + if (hasPos) { |
| 262 | + ss << " at " << pos; |
| 263 | + } else { |
| 264 | + ss << " (output stream not seekable)"; |
| 265 | + } |
| 266 | + ss << " (received so far: " |
| 267 | + << context->m_numBytesResponseReceived |
| 268 | + << " B, eof: " << ref.eof() |
| 269 | + << ", bad: " << ref.bad() << ")"; |
| 270 | + |
| 271 | + AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, ss.str()); |
240 | 272 | return 0; |
241 | 273 | } |
| 274 | + |
242 | 275 | if ((context->m_request->IsEventStreamRequest() || context->m_request->HasEventStreamResponse() ) |
243 | 276 | && !response->HasHeader(Aws::Http::X_AMZN_ERROR_TYPE)) |
244 | 277 | { |
245 | | - response->GetResponseBody().flush(); |
246 | | - if (response->GetResponseBody().fail()) { |
247 | | - const auto& ref = response->GetResponseBody(); |
248 | | - AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, "Failed to flush event response (eof: " |
| 278 | + body.flush(); |
| 279 | + if (body.fail()) { |
| 280 | + const auto& ref = body; |
| 281 | + AWS_LOGSTREAM_ERROR(CURL_HTTP_CLIENT_TAG, |
| 282 | + "Failed to flush event response (eof: " |
249 | 283 | << ref.eof() << ", bad: " << ref.bad() << ")"); |
250 | 284 | return 0; |
251 | 285 | } |
| 286 | + |
252 | 287 | } |
253 | 288 | auto& receivedHandler = context->m_request->GetDataReceivedEventHandler(); |
254 | 289 | if (receivedHandler) |
|
0 commit comments