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