]> git.ipfire.org Git - thirdparty/squid.git/blob - src/servers/Server.cc
Merged from trunk rev.14404
[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 "comm.h"
12 #include "comm/Read.h"
13 #include "Debug.h"
14 #include "fd.h"
15 #include "fde.h"
16 #include "MasterXaction.h"
17 #include "servers/Server.h"
18 #include "SquidConfig.h"
19 #include "StatCounters.h"
20 #include "tools.h"
21
22 Server::Server(const MasterXaction::Pointer &xact) :
23 AsyncJob("::Server"), // kids overwrite
24 clientConnection(xact->tcpClient),
25 transferProtocol(xact->squidPort->transport),
26 port(xact->squidPort),
27 receivedFirstByte_(false)
28 {}
29
30 bool
31 Server::doneAll() const
32 {
33 // servers are not done while the connection is open
34 return !Comm::IsConnOpen(clientConnection) &&
35 BodyProducer::doneAll();
36 }
37
38 void
39 Server::start()
40 {
41 // TODO: shuffle activity from ConnStateData
42 }
43
44 void
45 Server::swanSong()
46 {
47 if (Comm::IsConnOpen(clientConnection))
48 clientConnection->close();
49
50 BodyProducer::swanSong();
51 }
52
53 void
54 Server::stopReading()
55 {
56 if (reading()) {
57 Comm::ReadCancel(clientConnection->fd, reader);
58 reader = NULL;
59 }
60 }
61
62 bool
63 Server::maybeMakeSpaceAvailable()
64 {
65 if (inBuf.spaceSize() < 2) {
66 const SBuf::size_type haveCapacity = inBuf.length() + inBuf.spaceSize();
67 if (haveCapacity >= Config.maxRequestBufferSize) {
68 debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize);
69 return false;
70 }
71 if (haveCapacity == 0) {
72 // haveCapacity is based on the SBuf visible window of the MemBlob buffer, which may fill up.
73 // at which point bump the buffer back to default. This allocates a new MemBlob with any un-parsed bytes.
74 inBuf.reserveCapacity(CLIENT_REQ_BUF_SZ);
75 } else {
76 const SBuf::size_type wantCapacity = min(static_cast<SBuf::size_type>(Config.maxRequestBufferSize), haveCapacity*2);
77 inBuf.reserveCapacity(wantCapacity);
78 }
79 debugs(33, 2, "growing request buffer: available=" << inBuf.spaceSize() << " used=" << inBuf.length());
80 }
81 return (inBuf.spaceSize() >= 2);
82 }
83
84 void
85 Server::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
101 void
102 Server::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));
170 notifyAllContexts(rd.xerrno);
171 io.conn->close();
172 return;
173 }
174
175 afterClientRead();
176 }
177
178 void
179 Server::clientWriteDone(const CommIoCbParams &io)
180 {
181 debugs(33,5, io.conn);
182 Must(writer != NULL);
183 writer = NULL;
184
185 /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */
186 if (io.flag == Comm::ERR_CLOSING) {
187 debugs(33,5, io.conn << " closing Bailout.");
188 return;
189 }
190
191 assert(Comm::IsConnOpen(clientConnection));
192 assert(io.conn->fd == clientConnection->fd);
193
194 writeSomeData(); // maybe schedules another write
195 }
196