1//
2// HTTPChunkedStream.cpp
3//
4// Library: Net
5// Package: HTTP
6// Module: HTTPChunkedStream
7//
8// Copyright (c) 2005-2006, Applied Informatics Software Engineering GmbH.
9// and Contributors.
10//
11// SPDX-License-Identifier: BSL-1.0
12//
13
14
15#include "Poco/Net/HTTPChunkedStream.h"
16#include "Poco/Net/HTTPSession.h"
17#include "Poco/NumberFormatter.h"
18#include "Poco/NumberParser.h"
19#include "Poco/Ascii.h"
20
21
22using Poco::NumberFormatter;
23using Poco::NumberParser;
24
25
26namespace Poco {
27namespace Net {
28
29
30//
31// HTTPChunkedStreamBuf
32//
33
34
35HTTPChunkedStreamBuf::HTTPChunkedStreamBuf(HTTPSession& session, openmode mode):
36 HTTPBasicStreamBuf(HTTPBufferAllocator::BUFFER_SIZE, mode),
37 _session(session),
38 _mode(mode),
39 _chunk(0)
40{
41}
42
43
44HTTPChunkedStreamBuf::~HTTPChunkedStreamBuf()
45{
46}
47
48
49void HTTPChunkedStreamBuf::close()
50{
51 if (_mode & std::ios::out)
52 {
53 sync();
54 _session.write("0\r\n\r\n", 5);
55 }
56}
57
58
59int HTTPChunkedStreamBuf::readFromDevice(char* buffer, std::streamsize length)
60{
61 static const int eof = std::char_traits<char>::eof();
62
63 if (_chunk == 0)
64 {
65 int ch = _session.get();
66 while (Poco::Ascii::isSpace(ch)) ch = _session.get();
67 std::string chunkLen;
68 while (Poco::Ascii::isHexDigit(ch) && chunkLen.size() < 8) { chunkLen += (char) ch; ch = _session.get(); }
69 if (ch != eof && !(Poco::Ascii::isSpace(ch) || ch == ';')) return eof;
70 while (ch != eof && ch != '\n') ch = _session.get();
71 unsigned chunk;
72 if (NumberParser::tryParseHex(chunkLen, chunk))
73 _chunk = (std::streamsize) chunk;
74 else
75 return eof;
76 }
77 if (_chunk > 0)
78 {
79 if (length > _chunk) length = _chunk;
80 int n = _session.read(buffer, length);
81 if (n > 0) _chunk -= n;
82 return n;
83 }
84 else
85 {
86 int ch = _session.get();
87 while (ch != eof && ch != '\n') ch = _session.get();
88 return 0;
89 }
90}
91
92
93int HTTPChunkedStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
94{
95 _chunkBuffer.clear();
96 NumberFormatter::appendHex(_chunkBuffer, static_cast<Poco::UInt64>(length));
97 _chunkBuffer.append("\r\n", 2);
98 _chunkBuffer.append(buffer, static_cast<std::string::size_type>(length));
99 _chunkBuffer.append("\r\n", 2);
100 _session.write(_chunkBuffer.data(), static_cast<std::streamsize>(_chunkBuffer.size()));
101 return static_cast<int>(length);
102}
103
104
105//
106// HTTPChunkedIOS
107//
108
109
110HTTPChunkedIOS::HTTPChunkedIOS(HTTPSession& session, HTTPChunkedStreamBuf::openmode mode):
111 _buf(session, mode)
112{
113 poco_ios_init(&_buf);
114}
115
116
117HTTPChunkedIOS::~HTTPChunkedIOS()
118{
119 try
120 {
121 _buf.close();
122 }
123 catch (...)
124 {
125 }
126}
127
128
129HTTPChunkedStreamBuf* HTTPChunkedIOS::rdbuf()
130{
131 return &_buf;
132}
133
134
135//
136// HTTPChunkedInputStream
137//
138
139
140Poco::MemoryPool HTTPChunkedInputStream::_pool(sizeof(HTTPChunkedInputStream));
141
142
143HTTPChunkedInputStream::HTTPChunkedInputStream(HTTPSession& session):
144 HTTPChunkedIOS(session, std::ios::in),
145 std::istream(&_buf)
146{
147}
148
149
150HTTPChunkedInputStream::~HTTPChunkedInputStream()
151{
152}
153
154
155void* HTTPChunkedInputStream::operator new(std::size_t /*size*/)
156{
157 return _pool.get();
158}
159
160
161void HTTPChunkedInputStream::operator delete(void* ptr)
162{
163 try
164 {
165 _pool.release(ptr);
166 }
167 catch (...)
168 {
169 poco_unexpected();
170 }
171}
172
173
174//
175// HTTPChunkedOutputStream
176//
177
178
179Poco::MemoryPool HTTPChunkedOutputStream::_pool(sizeof(HTTPChunkedOutputStream));
180
181
182HTTPChunkedOutputStream::HTTPChunkedOutputStream(HTTPSession& session):
183 HTTPChunkedIOS(session, std::ios::out),
184 std::ostream(&_buf)
185{
186}
187
188
189HTTPChunkedOutputStream::~HTTPChunkedOutputStream()
190{
191}
192
193
194void* HTTPChunkedOutputStream::operator new(std::size_t /*size*/)
195{
196 return _pool.get();
197}
198
199
200void HTTPChunkedOutputStream::operator delete(void* ptr)
201{
202 try
203 {
204 _pool.release(ptr);
205 }
206 catch (...)
207 {
208 poco_unexpected();
209 }
210}
211
212
213} } // namespace Poco::Net
214