]>
Commit | Line | Data |
---|---|---|
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 | ||
24 | Server::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 | ||
32 | bool | |
33 | Server::doneAll() const | |
34 | { | |
35 | // servers are not done while the connection is open | |
36 | return !Comm::IsConnOpen(clientConnection) && | |
37 | BodyProducer::doneAll(); | |
38 | } | |
39 | ||
40 | void | |
41 | Server::start() | |
42 | { | |
43 | // TODO: shuffle activity from ConnStateData | |
44 | } | |
45 | ||
46 | void | |
47 | Server::swanSong() | |
48 | { | |
49 | if (Comm::IsConnOpen(clientConnection)) | |
50 | clientConnection->close(); | |
51 | ||
52 | BodyProducer::swanSong(); | |
53 | } | |
54 | ||
55 | void | |
56 | Server::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. | |
69 | void | |
fcc444e3 AJ |
70 | Server::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 | ||
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)); | |
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 |
185 | void |
186 | Server::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 |