]> git.ipfire.org Git - thirdparty/squid.git/blob - src/servers/Server.cc
Source Format Enforcement (#763)
[thirdparty/squid.git] / src / servers / Server.cc
1 /*
2 * Copyright (C) 1996-2021 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 "error/SysErrorDetail.h"
16 #include "fd.h"
17 #include "fde.h"
18 #include "http/Stream.h"
19 #include "LogTags.h"
20 #include "MasterXaction.h"
21 #include "servers/Server.h"
22 #include "SquidConfig.h"
23 #include "StatCounters.h"
24 #include "tools.h"
25
26 Server::Server(const MasterXaction::Pointer &xact) :
27 AsyncJob("::Server"), // kids overwrite
28 clientConnection(xact->tcpClient),
29 transferProtocol(xact->squidPort->transport),
30 port(xact->squidPort),
31 receivedFirstByte_(false)
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 /// Prepare inBuf for I/O. This method balances several conflicting desires:
67 /// 1. Do not read too few bytes at a time.
68 /// 2. Do not waste too much buffer space.
69 /// 3. Do not [re]allocate or memmove the buffer too much.
70 /// 4. Obey Config.maxRequestBufferSize limit.
71 void
72 Server::maybeMakeSpaceAvailable()
73 {
74 // The hard-coded parameters are arbitrary but seem reasonable.
75 // A careful study of Squid I/O and parsing patterns is needed to tune them.
76 SBufReservationRequirements requirements;
77 requirements.minSpace = 1024; // smaller I/Os are not worth their overhead
78 requirements.idealSpace = CLIENT_REQ_BUF_SZ; // we expect few larger I/Os
79 requirements.maxCapacity = Config.maxRequestBufferSize;
80 requirements.allowShared = true; // allow because inBuf is used immediately
81 inBuf.reserve(requirements);
82 if (!inBuf.spaceSize())
83 debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
84 }
85
86 void
87 Server::readSomeData()
88 {
89 if (reading())
90 return;
91
92 debugs(33, 4, clientConnection << ": reading request...");
93
94 // we can only read if there is more than 1 byte of space free
95 if (Config.maxRequestBufferSize - inBuf.length() < 2)
96 return;
97
98 typedef CommCbMemFunT<Server, CommIoCbParams> Dialer;
99 reader = JobCallback(33, 5, Dialer, this, Server::doClientRead);
100 Comm::Read(clientConnection, reader);
101 }
102
103 void
104 Server::doClientRead(const CommIoCbParams &io)
105 {
106 debugs(33,5, io.conn);
107 Must(reading());
108 reader = NULL;
109
110 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
111 if (io.flag == Comm::ERR_CLOSING) {
112 debugs(33,5, io.conn << " closing Bailout.");
113 return;
114 }
115
116 assert(Comm::IsConnOpen(clientConnection));
117 assert(io.conn->fd == clientConnection->fd);
118
119 /*
120 * Don't reset the timeout value here. The value should be
121 * counting Config.Timeout.request and applies to the request
122 * as a whole, not individual read() calls.
123 * Plus, it breaks our lame *HalfClosed() detection
124 */
125
126 maybeMakeSpaceAvailable();
127 CommIoCbParams rd(this); // will be expanded with ReadNow results
128 rd.conn = io.conn;
129 switch (Comm::ReadNow(rd, inBuf)) {
130 case Comm::INPROGRESS:
131
132 if (inBuf.isEmpty())
133 debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno));
134 readSomeData();
135 return;
136
137 case Comm::OK:
138 statCounter.client_http.kbytes_in += rd.size;
139 if (!receivedFirstByte_)
140 receivedFirstByte();
141 // may comm_close or setReplyToError
142 if (!handleReadData())
143 return;
144
145 /* Continue to process previously read data */
146 break;
147
148 case Comm::ENDFILE: // close detected by 0-byte read
149 debugs(33, 5, io.conn << " closed?");
150
151 if (shouldCloseOnEof()) {
152 LogTagsErrors lte;
153 lte.aborted = true;
154 terminateAll(ERR_CLIENT_GONE, lte);
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 LogTagsErrors lte;
175 lte.timedout = rd.xerrno == ETIMEDOUT;
176 lte.aborted = !lte.timedout; // intentionally true for zero rd.xerrno
177 terminateAll(Error(ERR_CLIENT_GONE, SysErrorDetail::NewIfAny(rd.xerrno)), lte);
178 return;
179 }
180
181 afterClientRead();
182 }
183
184 /** callback handling the Comm::Write completion
185 *
186 * Will call afterClientWrite(size_t) to sync the I/O state.
187 * Then writeSomeData() to initiate any followup writes that
188 * could be immediately done.
189 */
190 void
191 Server::clientWriteDone(const CommIoCbParams &io)
192 {
193 debugs(33,5, io.conn);
194 Must(writer != nullptr);
195 writer = nullptr;
196
197 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
198 if (io.flag == Comm::ERR_CLOSING || !Comm::IsConnOpen(clientConnection)) {
199 debugs(33,5, io.conn << " closing Bailout.");
200 return;
201 }
202
203 Must(io.conn->fd == clientConnection->fd);
204
205 if (io.flag && pipeline.front())
206 pipeline.front()->initiateClose("write failure");
207
208 afterClientWrite(io.size); // update state
209 writeSomeData(); // maybe schedules another write
210 }
211