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
21using Poco::TimeoutException;
22
23
24namespace Poco {
25namespace Net {
26
27
28HTTPSession::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
41HTTPSession::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
55HTTPSession::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
69HTTPSession::~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
90void HTTPSession::setKeepAlive(bool keepAlive)
91{
92 _keepAlive = keepAlive;
93}
94
95
96void HTTPSession::setTimeout(const Poco::Timespan& timeout)
97{
98 setTimeout(timeout, timeout, timeout);
99}
100
101void 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
109int 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
121int 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
133int 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
147int 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
161int 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
175void 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
187bool HTTPSession::connected() const
188{
189 return _socket.impl()->initialized();
190}
191
192
193void 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
205void HTTPSession::connect(const SocketAddress& targetAddress, const SocketAddress& sourceAddress)
206{
207 _socket.bind(sourceAddress, true);
208 connect(targetAddress);
209}
210
211
212void HTTPSession::abort()
213{
214 _socket.shutdown();
215 close();
216}
217
218
219void HTTPSession::close()
220{
221 _socket.close();
222}
223
224
225void HTTPSession::setException(const Poco::Exception& exc)
226{
227 delete _pException;
228 _pException = exc.clone();
229}
230
231
232void HTTPSession::clearException()
233{
234 delete _pException;
235 _pException = 0;
236}
237
238
239StreamSocket HTTPSession::detachSocket()
240{
241 StreamSocket oldSocket(_socket);
242 StreamSocket newSocket;
243 _socket = newSocket;
244 return oldSocket;
245}
246
247
248void HTTPSession::attachSocket(const StreamSocket& socket)
249{
250 _socket = socket;
251}
252
253
254void HTTPSession::attachSessionData(const Poco::Any& data)
255{
256 _data = data;
257}
258
259
260void 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