]> git.ipfire.org Git - thirdparty/squid.git/blob - src/servers/Server.cc
Fixes and improvments
[thirdparty/squid.git] / src / servers / Server.cc
1 /*
2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 #include "squid.h"
10 #include "anyp/PortCfg.h"
11 #include "client_side.h"
12 #include "comm.h"
13 #include "comm/Read.h"
14 #include "Debug.h"
15 #include "fd.h"
16 #include "fde.h"
17 #include "http/Stream.h"
18 #include "MasterXaction.h"
19 #include "servers/Server.h"
20 #include "SquidConfig.h"
21 #include "StatCounters.h"
22 #include "tools.h"
23
24 Server::Server(const MasterXaction::Pointer &xact) :
25 AsyncJob("::Server"), // kids overwrite
26 clientConnection(xact->tcpClient),
27 port(xact->squidPort),
28 receivedFirstByte_(false)
29 {
30 if (xact->squidPort)
31 transferProtocol = xact->squidPort->transport;
32 }
33
34 bool
35 Server::doneAll() const
36 {
37 // servers are not done while the connection is open
38 return !Comm::IsConnOpen(clientConnection) &&
39 BodyProducer::doneAll();
40 }
41
42 void
43 Server::start()
44 {
45 // TODO: shuffle activity from ConnStateData
46 }
47
48 void
49 Server::swanSong()
50 {
51 if (Comm::IsConnOpen(clientConnection))
52 clientConnection->close();
53
54 BodyProducer::swanSong();
55 }
56
57 void
58 Server::stopReading()
59 {
60 if (reading()) {
61 Comm::ReadCancel(clientConnection->fd, reader);
62 reader = NULL;
63 }
64 }
65
66 bool
67 Server::maybeMakeSpaceAvailable()
68 {
69 if (inBuf.spaceSize() < 2) {
70 const SBuf::size_type haveCapacity = inBuf.length() + inBuf.spaceSize();
71 if (haveCapacity >= Config.maxRequestBufferSize) {
72 debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
73 return false;
74 }
75 if (haveCapacity == 0) {
76 // haveCapacity is based on the SBuf visible window of the MemBlob buffer, which may fill up.
77 // at which point bump the buffer back to default. This allocates a new MemBlob with any un-parsed bytes.
78 inBuf.reserveCapacity(CLIENT_REQ_BUF_SZ);
79 } else {
80 const SBuf::size_type wantCapacity = min(static_cast<SBuf::size_type>(Config.maxRequestBufferSize), haveCapacity*2);
81 inBuf.reserveCapacity(wantCapacity);
82 }
83 debugs(33, 2, "growing request buffer: available=" << inBuf.spaceSize() << " used=" << inBuf.length());
84 }
85 return (inBuf.spaceSize() >= 2);
86 }
87
88 void
89 Server::readSomeData()
90 {
91 if (reading())
92 return;
93
94 debugs(33, 4, clientConnection << ": reading request...");
95
96 // we can only read if there is more than 1 byte of space free
97 if (Config.maxRequestBufferSize - inBuf.length() < 2)
98 return;
99
100 typedef CommCbMemFunT<Server, CommIoCbParams> Dialer;
101 reader = JobCallback(33, 5, Dialer, this, Server::doClientRead);
102 Comm::Read(clientConnection, reader);
103 }
104
105 void
106 Server::doClientRead(const CommIoCbParams &io)
107 {
108 debugs(33,5, io.conn);
109 Must(reading());
110 reader = NULL;
111
112 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
113 if (io.flag == Comm::ERR_CLOSING) {
114 debugs(33,5, io.conn << " closing Bailout.");
115 return;
116 }
117
118 assert(Comm::IsConnOpen(clientConnection));
119 assert(io.conn->fd == clientConnection->fd);
120
121 /*
122 * Don't reset the timeout value here. The value should be
123 * counting Config.Timeout.request and applies to the request
124 * as a whole, not individual read() calls.
125 * Plus, it breaks our lame *HalfClosed() detection
126 */
127
128 maybeMakeSpaceAvailable();
129 CommIoCbParams rd(this); // will be expanded with ReadNow results
130 rd.conn = io.conn;
131 switch (Comm::ReadNow(rd, inBuf)) {
132 case Comm::INPROGRESS:
133
134 if (inBuf.isEmpty())
135 debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno));
136 readSomeData();
137 return;
138
139 case Comm::OK:
140 statCounter.client_http.kbytes_in += rd.size;
141 if (!receivedFirstByte_)
142 receivedFirstByte();
143 // may comm_close or setReplyToError
144 if (!handleReadData())
145 return;
146
147 /* Continue to process previously read data */
148 break;
149
150 case Comm::ENDFILE: // close detected by 0-byte read
151 debugs(33, 5, io.conn << " closed?");
152
153 if (connFinishedWithConn(rd.size)) {
154 clientConnection->close();
155 return;
156 }
157
158 /* It might be half-closed, we can't tell */
159 fd_table[io.conn->fd].flags.socket_eof = true;
160 commMarkHalfClosed(io.conn->fd);
161 fd_note(io.conn->fd, "half-closed");
162
163 /* There is one more close check at the end, to detect aborted
164 * (partial) requests. At this point we can't tell if the request
165 * is partial.
166 */
167
168 /* Continue to process previously read data */
169 break;
170
171 // case Comm::COMM_ERROR:
172 default: // no other flags should ever occur
173 debugs(33, 2, io.conn << ": got flag " << rd.flag << "; " << xstrerr(rd.xerrno));
174 pipeline.terminateAll(rd.xerrno);
175 io.conn->close();
176 return;
177 }
178
179 afterClientRead();
180 }
181
182 /** callback handling the Comm::Write completion
183 *
184 * Will call afterClientWrite(size_t) to sync the I/O state.
185 * Then writeSomeData() to initiate any followup writes that
186 * could be immediately done.
187 */
188 void
189 Server::clientWriteDone(const CommIoCbParams &io)
190 {
191 debugs(33,5, io.conn);
192 Must(writer != nullptr);
193 writer = nullptr;
194
195 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
196 if (io.flag == Comm::ERR_CLOSING || !Comm::IsConnOpen(clientConnection)) {
197 debugs(33,5, io.conn << " closing Bailout.");
198 return;
199 }
200
201 Must(io.conn->fd == clientConnection->fd);
202
203 if (io.flag && pipeline.front())
204 pipeline.front()->initiateClose("write failure");
205
206 afterClientWrite(io.size); // update state
207 writeSomeData(); // maybe schedules another write
208 }
209