1 | // |
2 | // HTTPSession.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: HTTP |
6 | // Module: HTTPSession |
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/HTTPSession.h" |
16 | #include "Poco/Net/HTTPBufferAllocator.h" |
17 | #include "Poco/Net/NetException.h" |
18 | #include <cstring> |
19 | |
20 | |
21 | using Poco::TimeoutException; |
22 | |
23 | |
24 | namespace Poco { |
25 | namespace Net { |
26 | |
27 | |
28 | HTTPSession::HTTPSession(): |
29 | _pBuffer(0), |
30 | _pCurrent(0), |
31 | _pEnd(0), |
32 | _keepAlive(false), |
33 | _connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT), |
34 | _receiveTimeout(HTTP_DEFAULT_TIMEOUT), |
35 | _sendTimeout(HTTP_DEFAULT_TIMEOUT), |
36 | _pException(0) |
37 | { |
38 | } |
39 | |
40 | |
41 | HTTPSession::HTTPSession(const StreamSocket& socket): |
42 | _socket(socket), |
43 | _pBuffer(0), |
44 | _pCurrent(0), |
45 | _pEnd(0), |
46 | _keepAlive(false), |
47 | _connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT), |
48 | _receiveTimeout(HTTP_DEFAULT_TIMEOUT), |
49 | _sendTimeout(HTTP_DEFAULT_TIMEOUT), |
50 | _pException(0) |
51 | { |
52 | } |
53 | |
54 | |
55 | HTTPSession::HTTPSession(const StreamSocket& socket, bool keepAlive): |
56 | _socket(socket), |
57 | _pBuffer(0), |
58 | _pCurrent(0), |
59 | _pEnd(0), |
60 | _keepAlive(keepAlive), |
61 | _connectionTimeout(HTTP_DEFAULT_CONNECTION_TIMEOUT), |
62 | _receiveTimeout(HTTP_DEFAULT_TIMEOUT), |
63 | _sendTimeout(HTTP_DEFAULT_TIMEOUT), |
64 | _pException(0) |
65 | { |
66 | } |
67 | |
68 | |
69 | HTTPSession::~HTTPSession() |
70 | { |
71 | try |
72 | { |
73 | if (_pBuffer) HTTPBufferAllocator::deallocate(_pBuffer, HTTPBufferAllocator::BUFFER_SIZE); |
74 | } |
75 | catch (...) |
76 | { |
77 | poco_unexpected(); |
78 | } |
79 | try |
80 | { |
81 | close(); |
82 | } |
83 | catch (...) |
84 | { |
85 | } |
86 | delete _pException; |
87 | } |
88 | |
89 | |
90 | void HTTPSession::setKeepAlive(bool keepAlive) |
91 | { |
92 | _keepAlive = keepAlive; |
93 | } |
94 | |
95 | |
96 | void HTTPSession::setTimeout(const Poco::Timespan& timeout) |
97 | { |
98 | setTimeout(timeout, timeout, timeout); |
99 | } |
100 | |
101 | void HTTPSession::setTimeout(const Poco::Timespan& connectionTimeout, const Poco::Timespan& sendTimeout, const Poco::Timespan& receiveTimeout) |
102 | { |
103 | _connectionTimeout = connectionTimeout; |
104 | _sendTimeout = sendTimeout; |
105 | _receiveTimeout = receiveTimeout; |
106 | } |
107 | |
108 | |
109 | int HTTPSession::get() |
110 | { |
111 | if (_pCurrent == _pEnd) |
112 | refill(); |
113 | |
114 | if (_pCurrent < _pEnd) |
115 | return *_pCurrent++; |
116 | else |
117 | return std::char_traits<char>::eof(); |
118 | } |
119 | |
120 | |
121 | int HTTPSession::peek() |
122 | { |
123 | if (_pCurrent == _pEnd) |
124 | refill(); |
125 | |
126 | if (_pCurrent < _pEnd) |
127 | return *_pCurrent; |
128 | else |
129 | return std::char_traits<char>::eof(); |
130 | } |
131 | |
132 | |
133 | int HTTPSession::read(char* buffer, std::streamsize length) |
134 | { |
135 | if (_pCurrent < _pEnd) |
136 | { |
137 | int n = (int) (_pEnd - _pCurrent); |
138 | if (n > length) n = (int) length; |
139 | std::memcpy(buffer, _pCurrent, n); |
140 | _pCurrent += n; |
141 | return n; |
142 | } |
143 | else return receive(buffer, (int) length); |
144 | } |
145 | |
146 | |
147 | int HTTPSession::write(const char* buffer, std::streamsize length) |
148 | { |
149 | try |
150 | { |
151 | return _socket.sendBytes(buffer, (int) length); |
152 | } |
153 | catch (Poco::Exception& exc) |
154 | { |
155 | setException(exc); |
156 | throw; |
157 | } |
158 | } |
159 | |
160 | |
161 | int HTTPSession::receive(char* buffer, int length) |
162 | { |
163 | try |
164 | { |
165 | return _socket.receiveBytes(buffer, length); |
166 | } |
167 | catch (Poco::Exception& exc) |
168 | { |
169 | setException(exc); |
170 | throw; |
171 | } |
172 | } |
173 | |
174 | |
175 | void HTTPSession::refill() |
176 | { |
177 | if (!_pBuffer) |
178 | { |
179 | _pBuffer = HTTPBufferAllocator::allocate(HTTPBufferAllocator::BUFFER_SIZE); |
180 | } |
181 | _pCurrent = _pEnd = _pBuffer; |
182 | int n = receive(_pBuffer, HTTPBufferAllocator::BUFFER_SIZE); |
183 | _pEnd += n; |
184 | } |
185 | |
186 | |
187 | bool HTTPSession::connected() const |
188 | { |
189 | return _socket.impl()->initialized(); |
190 | } |
191 | |
192 | |
193 | void HTTPSession::connect(const SocketAddress& address) |
194 | { |
195 | _socket.connect(address, _connectionTimeout); |
196 | _socket.setReceiveTimeout(_receiveTimeout); |
197 | _socket.setSendTimeout(_sendTimeout); |
198 | _socket.setNoDelay(true); |
199 | // There may be leftover data from a previous (failed) request in the buffer, |
200 | // so we clear it. |
201 | _pCurrent = _pEnd = _pBuffer; |
202 | } |
203 | |
204 | |
205 | void HTTPSession::connect(const SocketAddress& targetAddress, const SocketAddress& sourceAddress) |
206 | { |
207 | _socket.bind(sourceAddress, true); |
208 | connect(targetAddress); |
209 | } |
210 | |
211 | |
212 | void HTTPSession::abort() |
213 | { |
214 | _socket.shutdown(); |
215 | close(); |
216 | } |
217 | |
218 | |
219 | void HTTPSession::close() |
220 | { |
221 | _socket.close(); |
222 | } |
223 | |
224 | |
225 | void HTTPSession::setException(const Poco::Exception& exc) |
226 | { |
227 | delete _pException; |
228 | _pException = exc.clone(); |
229 | } |
230 | |
231 | |
232 | void HTTPSession::clearException() |
233 | { |
234 | delete _pException; |
235 | _pException = 0; |
236 | } |
237 | |
238 | |
239 | StreamSocket HTTPSession::detachSocket() |
240 | { |
241 | StreamSocket oldSocket(_socket); |
242 | StreamSocket newSocket; |
243 | _socket = newSocket; |
244 | return oldSocket; |
245 | } |
246 | |
247 | |
248 | void HTTPSession::attachSocket(const StreamSocket& socket) |
249 | { |
250 | _socket = socket; |
251 | } |
252 | |
253 | |
254 | void HTTPSession::attachSessionData(const Poco::Any& data) |
255 | { |
256 | _data = data; |
257 | } |
258 | |
259 | |
260 | void HTTPSession::drainBuffer(Poco::Buffer<char>& buffer) |
261 | { |
262 | buffer.assign(_pCurrent, static_cast<std::size_t>(_pEnd - _pCurrent)); |
263 | _pCurrent = _pEnd; |
264 | } |
265 | |
266 | |
267 | } } // namespace Poco::Net |
268 | |