]>
Commit | Line | Data |
---|---|---|
fcc444e3 | 1 | /* |
f70aedc4 | 2 | * Copyright (C) 1996-2021 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" | |
83b053a0 | 15 | #include "error/SysErrorDetail.h" |
fcc444e3 AJ |
16 | #include "fd.h" |
17 | #include "fde.h" | |
d3dddfb5 | 18 | #include "http/Stream.h" |
83b053a0 | 19 | #include "LogTags.h" |
fcc444e3 AJ |
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), | |
2c391676 | 31 | receivedFirstByte_(false) |
fcc444e3 AJ |
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 | ||
19e97cf0 AR |
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 | |
fcc444e3 AJ |
72 | Server::maybeMakeSpaceAvailable() |
73 | { | |
19e97cf0 AR |
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); | |
fcc444e3 AJ |
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 | ||
83b053a0 CT |
151 | if (shouldCloseOnEof()) { |
152 | LogTagsErrors lte; | |
153 | lte.aborted = true; | |
154 | terminateAll(ERR_CLIENT_GONE, lte); | |
fcc444e3 AJ |
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)); | |
83b053a0 CT |
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); | |
fcc444e3 AJ |
178 | return; |
179 | } | |
180 | ||
181 | afterClientRead(); | |
182 | } | |
183 | ||
21cd3227 AJ |
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 | */ | |
fcc444e3 AJ |
190 | void |
191 | Server::clientWriteDone(const CommIoCbParams &io) | |
192 | { | |
193 | debugs(33,5, io.conn); | |
21cd3227 AJ |
194 | Must(writer != nullptr); |
195 | writer = nullptr; | |
fcc444e3 AJ |
196 | |
197 | /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */ | |
21cd3227 | 198 | if (io.flag == Comm::ERR_CLOSING || !Comm::IsConnOpen(clientConnection)) { |
fcc444e3 AJ |
199 | debugs(33,5, io.conn << " closing Bailout."); |
200 | return; | |
201 | } | |
202 | ||
21cd3227 AJ |
203 | Must(io.conn->fd == clientConnection->fd); |
204 | ||
205 | if (io.flag && pipeline.front()) | |
206 | pipeline.front()->initiateClose("write failure"); | |
fcc444e3 | 207 | |
21cd3227 | 208 | afterClientWrite(io.size); // update state |
fcc444e3 AJ |
209 | writeSomeData(); // maybe schedules another write |
210 | } | |
15f8f9eb | 211 |