1 | // |
2 | // HTTPServerConnection.cpp |
3 | // |
4 | // Library: Net |
5 | // Package: HTTPServer |
6 | // Module: HTTPServerConnection |
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/HTTPServerConnection.h" |
16 | #include "Poco/Net/HTTPServerSession.h" |
17 | #include "Poco/Net/HTTPServerRequestImpl.h" |
18 | #include "Poco/Net/HTTPServerResponseImpl.h" |
19 | #include "Poco/Net/HTTPRequestHandler.h" |
20 | #include "Poco/Net/HTTPRequestHandlerFactory.h" |
21 | #include "Poco/Net/NetException.h" |
22 | #include "Poco/NumberFormatter.h" |
23 | #include "Poco/Timestamp.h" |
24 | #include "Poco/Delegate.h" |
25 | #include <memory> |
26 | |
27 | |
28 | namespace Poco { |
29 | namespace Net { |
30 | |
31 | |
32 | HTTPServerConnection::HTTPServerConnection(const StreamSocket& socket, HTTPServerParams::Ptr pParams, HTTPRequestHandlerFactory::Ptr pFactory): |
33 | TCPServerConnection(socket), |
34 | _pParams(pParams), |
35 | _pFactory(pFactory), |
36 | _stopped(false) |
37 | { |
38 | poco_check_ptr (pFactory); |
39 | |
40 | _pFactory->serverStopped += Poco::delegate(this, &HTTPServerConnection::onServerStopped); |
41 | } |
42 | |
43 | |
44 | HTTPServerConnection::~HTTPServerConnection() |
45 | { |
46 | try |
47 | { |
48 | _pFactory->serverStopped -= Poco::delegate(this, &HTTPServerConnection::onServerStopped); |
49 | } |
50 | catch (...) |
51 | { |
52 | poco_unexpected(); |
53 | } |
54 | } |
55 | |
56 | |
57 | void HTTPServerConnection::run() |
58 | { |
59 | std::string server = _pParams->getSoftwareVersion(); |
60 | HTTPServerSession session(socket(), _pParams); |
61 | while (!_stopped && session.hasMoreRequests()) |
62 | { |
63 | try |
64 | { |
65 | Poco::FastMutex::ScopedLock lock(_mutex); |
66 | if (!_stopped) |
67 | { |
68 | HTTPServerResponseImpl response(session); |
69 | HTTPServerRequestImpl request(response, session, _pParams); |
70 | |
71 | Poco::Timestamp now; |
72 | response.setDate(now); |
73 | response.setVersion(request.getVersion()); |
74 | response.setKeepAlive(_pParams->getKeepAlive() && request.getKeepAlive() && session.canKeepAlive()); |
75 | if (!server.empty()) |
76 | response.set("Server" , server); |
77 | try |
78 | { |
79 | std::unique_ptr<HTTPRequestHandler> pHandler(_pFactory->createRequestHandler(request)); |
80 | if (pHandler.get()) |
81 | { |
82 | if (request.getExpectContinue() && response.getStatus() == HTTPResponse::HTTP_OK) |
83 | response.sendContinue(); |
84 | |
85 | pHandler->handleRequest(request, response); |
86 | session.setKeepAlive(_pParams->getKeepAlive() && response.getKeepAlive() && session.canKeepAlive()); |
87 | } |
88 | else sendErrorResponse(session, HTTPResponse::HTTP_NOT_IMPLEMENTED); |
89 | } |
90 | catch (Poco::Exception&) |
91 | { |
92 | if (!response.sent()) |
93 | { |
94 | try |
95 | { |
96 | sendErrorResponse(session, HTTPResponse::HTTP_INTERNAL_SERVER_ERROR); |
97 | } |
98 | catch (...) |
99 | { |
100 | } |
101 | } |
102 | throw; |
103 | } |
104 | } |
105 | } |
106 | catch (NoMessageException&) |
107 | { |
108 | break; |
109 | } |
110 | catch (MessageException&) |
111 | { |
112 | sendErrorResponse(session, HTTPResponse::HTTP_BAD_REQUEST); |
113 | } |
114 | catch (Poco::Exception&) |
115 | { |
116 | if (session.networkException()) |
117 | { |
118 | session.networkException()->rethrow(); |
119 | } |
120 | else throw; |
121 | } |
122 | } |
123 | } |
124 | |
125 | |
126 | void HTTPServerConnection::sendErrorResponse(HTTPServerSession& session, HTTPResponse::HTTPStatus status) |
127 | { |
128 | HTTPServerResponseImpl response(session); |
129 | response.setVersion(HTTPMessage::HTTP_1_1); |
130 | response.setStatusAndReason(status); |
131 | response.setKeepAlive(false); |
132 | response.send(); |
133 | session.setKeepAlive(false); |
134 | } |
135 | |
136 | |
137 | void HTTPServerConnection::onServerStopped(const bool& abortCurrent) |
138 | { |
139 | _stopped = true; |
140 | if (abortCurrent) |
141 | { |
142 | try |
143 | { |
144 | // Note: On Windows, select() will not return if one of its socket is being |
145 | // shut down. Therefore we have to call close(), which works better. |
146 | // On other platforms, we do the more graceful thing. |
147 | #if defined(_WIN32) |
148 | socket().close(); |
149 | #else |
150 | socket().shutdown(); |
151 | #endif |
152 | } |
153 | catch (...) |
154 | { |
155 | } |
156 | } |
157 | else |
158 | { |
159 | Poco::FastMutex::ScopedLock lock(_mutex); |
160 | |
161 | try |
162 | { |
163 | #if defined(_WIN32) |
164 | socket().close(); |
165 | #else |
166 | socket().shutdown(); |
167 | #endif |
168 | } |
169 | catch (...) |
170 | { |
171 | } |
172 | } |
173 | } |
174 | |
175 | |
176 | } } // namespace Poco::Net |
177 | |