]> git.ipfire.org Git - thirdparty/squid.git/blame - src/servers/Server.cc
SourceFormat Enforcement
[thirdparty/squid.git] / src / servers / Server.cc
CommitLineData
fcc444e3 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
fcc444e3
AJ
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"
c6ae1627 11#include "client_side.h"
fcc444e3
AJ
12#include "comm.h"
13#include "comm/Read.h"
14#include "Debug.h"
15#include "fd.h"
16#include "fde.h"
d3dddfb5 17#include "http/Stream.h"
fcc444e3
AJ
18#include "MasterXaction.h"
19#include "servers/Server.h"
20#include "SquidConfig.h"
21#include "StatCounters.h"
22#include "tools.h"
23
24Server::Server(const MasterXaction::Pointer &xact) :
25 AsyncJob("::Server"), // kids overwrite
26 clientConnection(xact->tcpClient),
27 transferProtocol(xact->squidPort->transport),
28 port(xact->squidPort),
2c391676 29 receivedFirstByte_(false)
fcc444e3
AJ
30{}
31
32bool
33Server::doneAll() const
34{
35 // servers are not done while the connection is open
36 return !Comm::IsConnOpen(clientConnection) &&
37 BodyProducer::doneAll();
38}
39
40void
41Server::start()
42{
43 // TODO: shuffle activity from ConnStateData
44}
45
46void
47Server::swanSong()
48{
49 if (Comm::IsConnOpen(clientConnection))
50 clientConnection->close();
51
52 BodyProducer::swanSong();
53}
54
55void
56Server::stopReading()
57{
58 if (reading()) {
59 Comm::ReadCancel(clientConnection->fd, reader);
60 reader = NULL;
61 }
62}
63
19e97cf0
AR
64/// Prepare inBuf for I/O. This method balances several conflicting desires:
65/// 1. Do not read too few bytes at a time.
66/// 2. Do not waste too much buffer space.
67/// 3. Do not [re]allocate or memmove the buffer too much.
68/// 4. Obey Config.maxRequestBufferSize limit.
69void
fcc444e3
AJ
70Server::maybeMakeSpaceAvailable()
71{
19e97cf0
AR
72 // The hard-coded parameters are arbitrary but seem reasonable.
73 // A careful study of Squid I/O and parsing patterns is needed to tune them.
74 SBufReservationRequirements requirements;
75 requirements.minSpace = 1024; // smaller I/Os are not worth their overhead
76 requirements.idealSpace = CLIENT_REQ_BUF_SZ; // we expect few larger I/Os
77 requirements.maxCapacity = Config.maxRequestBufferSize;
78 requirements.allowShared = true; // allow because inBuf is used immediately
79 inBuf.reserve(requirements);
80 if (!inBuf.spaceSize())
81 debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
fcc444e3
AJ
82}
83
84void
85Server::readSomeData()
86{
87 if (reading())
88 return;
89
90 debugs(33, 4, clientConnection << ": reading request...");
91
92 // we can only read if there is more than 1 byte of space free
93 if (Config.maxRequestBufferSize - inBuf.length() < 2)
94 return;
95
96 typedef CommCbMemFunT<Server, CommIoCbParams> Dialer;
97 reader = JobCallback(33, 5, Dialer, this, Server::doClientRead);
98 Comm::Read(clientConnection, reader);
99}
100
101void
102Server::doClientRead(const CommIoCbParams &io)
103{
104 debugs(33,5, io.conn);
105 Must(reading());
106 reader = NULL;
107
108 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
109 if (io.flag == Comm::ERR_CLOSING) {
110 debugs(33,5, io.conn << " closing Bailout.");
111 return;
112 }
113
114 assert(Comm::IsConnOpen(clientConnection));
115 assert(io.conn->fd == clientConnection->fd);
116
117 /*
118 * Don't reset the timeout value here. The value should be
119 * counting Config.Timeout.request and applies to the request
120 * as a whole, not individual read() calls.
121 * Plus, it breaks our lame *HalfClosed() detection
122 */
123
124 maybeMakeSpaceAvailable();
125 CommIoCbParams rd(this); // will be expanded with ReadNow results
126 rd.conn = io.conn;
127 switch (Comm::ReadNow(rd, inBuf)) {
128 case Comm::INPROGRESS:
129
130 if (inBuf.isEmpty())
131 debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno));
132 readSomeData();
133 return;
134
135 case Comm::OK:
136 statCounter.client_http.kbytes_in += rd.size;
137 if (!receivedFirstByte_)
138 receivedFirstByte();
139 // may comm_close or setReplyToError
140 if (!handleReadData())
141 return;
142
143 /* Continue to process previously read data */
144 break;
145
146 case Comm::ENDFILE: // close detected by 0-byte read
147 debugs(33, 5, io.conn << " closed?");
148
149 if (connFinishedWithConn(rd.size)) {
150 clientConnection->close();
151 return;
152 }
153
154 /* It might be half-closed, we can't tell */
155 fd_table[io.conn->fd].flags.socket_eof = true;
156 commMarkHalfClosed(io.conn->fd);
157 fd_note(io.conn->fd, "half-closed");
158
159 /* There is one more close check at the end, to detect aborted
160 * (partial) requests. At this point we can't tell if the request
161 * is partial.
162 */
163
164 /* Continue to process previously read data */
165 break;
166
167 // case Comm::COMM_ERROR:
168 default: // no other flags should ever occur
169 debugs(33, 2, io.conn << ": got flag " << rd.flag << "; " << xstrerr(rd.xerrno));
da6dbcd1 170 checkLogging();
08a175bb 171 pipeline.terminateAll(rd.xerrno);
fcc444e3
AJ
172 io.conn->close();
173 return;
174 }
175
176 afterClientRead();
177}
178
21cd3227
AJ
179/** callback handling the Comm::Write completion
180 *
181 * Will call afterClientWrite(size_t) to sync the I/O state.
182 * Then writeSomeData() to initiate any followup writes that
183 * could be immediately done.
184 */
fcc444e3
AJ
185void
186Server::clientWriteDone(const CommIoCbParams &io)
187{
188 debugs(33,5, io.conn);
21cd3227
AJ
189 Must(writer != nullptr);
190 writer = nullptr;
fcc444e3
AJ
191
192 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
21cd3227 193 if (io.flag == Comm::ERR_CLOSING || !Comm::IsConnOpen(clientConnection)) {
fcc444e3
AJ
194 debugs(33,5, io.conn << " closing Bailout.");
195 return;
196 }
197
21cd3227
AJ
198 Must(io.conn->fd == clientConnection->fd);
199
200 if (io.flag && pipeline.front())
201 pipeline.front()->initiateClose("write failure");
fcc444e3 202
21cd3227 203 afterClientWrite(io.size); // update state
fcc444e3
AJ
204 writeSomeData(); // maybe schedules another write
205}
15f8f9eb 206