Skip to content

Commit 1016765

Browse files
Issue-3364: Reproduction + fix(Purposal)
Sign-off: Rajan Y.(rajanyadav0307@gmail.com)
1 parent 6f08e2e commit 1016765

File tree

1 file changed

+96
-1
lines changed

1 file changed

+96
-1
lines changed

tests/aws-cpp-sdk-core-tests/http/HttpClientTest.cpp

Lines changed: 96 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ class HttpClientTest : public Aws::Testing::AwsCppSdkGTestSuite
6767
{
6868
};
6969

70+
class CURLHttpClientTest : public Aws::Testing::AwsCppSdkGTestSuite
71+
{
72+
};
73+
74+
7075
TEST_F(HttpClientTest, TestRandomURLWithNoProxy)
7176
{
7277
auto httpClient = CreateHttpClient(Aws::Client::ClientConfiguration());
@@ -382,7 +387,97 @@ TEST_F(CURLHttpClientTest, TestHttpRequestWorksFine)
382387
EXPECT_EQ(Aws::Http::HttpResponseCode::OK, response->GetResponseCode());
383388
EXPECT_EQ("", response->GetClientErrorMessage());
384389
}
390+
391+
#include <aws/core/utils/memory/stl/AWSVector.h>
392+
#include <streambuf>
393+
394+
// A streambuf that supports writing but does NOT support seeking.
395+
// This reproduces the behavior of many filtering / transforming streams.
396+
class NonSeekableWriteBuf final : public std::streambuf
397+
{
398+
public:
399+
explicit NonSeekableWriteBuf(Aws::Vector<char>& out) : m_out(out) {}
400+
401+
protected:
402+
std::streamsize xsputn(const char* s, std::streamsize n) override
403+
{
404+
if (n > 0)
405+
{
406+
m_out.insert(m_out.end(), s, s + static_cast<size_t>(n));
407+
}
408+
return n;
409+
}
410+
411+
int overflow(int ch) override
412+
{
413+
if (ch == traits_type::eof())
414+
{
415+
return traits_type::not_eof(ch);
416+
}
417+
m_out.push_back(static_cast<char>(ch));
418+
return ch;
419+
}
420+
421+
// Disallow positioning (seek/tell)
422+
pos_type seekoff(off_type, std::ios_base::seekdir, std::ios_base::openmode) override
423+
{
424+
return pos_type(off_type(-1));
425+
}
426+
427+
pos_type seekpos(pos_type, std::ios_base::openmode) override
428+
{
429+
return pos_type(off_type(-1));
430+
}
431+
432+
private:
433+
Aws::Vector<char>& m_out;
434+
};
435+
436+
class NonSeekableIOStream final : public Aws::IOStream
437+
{
438+
public:
439+
NonSeekableIOStream(const Aws::String& /*allocationTag*/, Aws::Vector<char>& out)
440+
: Aws::IOStream(nullptr), m_buf(out)
441+
{
442+
rdbuf(&m_buf);
443+
}
444+
445+
private:
446+
NonSeekableWriteBuf m_buf;
447+
};
448+
449+
// Regression test:
450+
// Ensure CurlHttpClient can write response bodies into a non-seekable output stream.
451+
// Older implementations that call tellp() as part of the write callback may fail here.
452+
TEST_F(CURLHttpClientTest, TestNonSeekableResponseStreamDoesNotAbortTransfer)
453+
{
454+
Aws::Vector<char> captured;
455+
456+
auto request = CreateHttpRequest(
457+
Aws::String("http://127.0.0.1:8778"),
458+
HttpMethod::HTTP_GET,
459+
Aws::Utils::Stream::DefaultResponseStreamFactoryMethod);
460+
461+
request->SetHeaderValue("WaitSeconds", "1");
462+
463+
request->SetResponseStreamFactory([&captured]() -> Aws::IOStream*
464+
{
465+
return Aws::New<NonSeekableIOStream>(ALLOCATION_TAG, ALLOCATION_TAG, captured);
466+
});
467+
468+
Aws::Client::ClientConfiguration config;
469+
config.requestTimeoutMs = 10000;
470+
471+
auto httpClient = CreateHttpClient(config);
472+
auto response = httpClient->MakeRequest(request);
473+
474+
ASSERT_NE(nullptr, response);
475+
476+
ASSERT_FALSE(response->HasClientError()) << response->GetClientErrorMessage();
477+
EXPECT_EQ(Aws::Http::HttpResponseCode::OK, response->GetResponseCode());
478+
479+
}
385480
#endif // ENABLE_CURL_CLIENT
386481
#endif // ENABLE_HTTP_CLIENT_TESTING
387482
#endif // NO_HTTP_CLIENT
388-
#endif // DISABLE_DNS_REQUIRED_TESTS
483+
#endif // DISABLE_DNS_REQUIRED_TESTS

0 commit comments

Comments
 (0)