]>
Commit | Line | Data |
---|---|---|
fcc444e3 | 1 | /* |
ef57eb7b | 2 | * Copyright (C) 1996-2016 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" | |
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 | transferProtocol(xact->squidPort->transport), | |
27 | port(xact->squidPort), | |
28 | receivedFirstByte_(false) | |
29 | {} | |
30 | ||
31 | bool | |
32 | Server::doneAll() const | |
33 | { | |
34 | // servers are not done while the connection is open | |
35 | return !Comm::IsConnOpen(clientConnection) && | |
36 | BodyProducer::doneAll(); | |
37 | } | |
38 | ||
39 | void | |
40 | Server::start() | |
41 | { | |
42 | // TODO: shuffle activity from ConnStateData | |
43 | } | |
44 | ||
45 | void | |
46 | Server::swanSong() | |
47 | { | |
48 | if (Comm::IsConnOpen(clientConnection)) | |
49 | clientConnection->close(); | |
50 | ||
51 | BodyProducer::swanSong(); | |
52 | } | |
53 | ||
54 | void | |
55 | Server::stopReading() | |
56 | { | |
57 | if (reading()) { | |
58 | Comm::ReadCancel(clientConnection->fd, reader); | |
59 | reader = NULL; | |
60 | } | |
61 | } | |
62 | ||
63 | bool | |
64 | Server::maybeMakeSpaceAvailable() | |
65 | { | |
66 | if (inBuf.spaceSize() < 2) { | |
67 | const SBuf::size_type haveCapacity = inBuf.length() + inBuf.spaceSize(); | |
68 | if (haveCapacity >= Config.maxRequestBufferSize) { | |
69 | debugs(33, 4, "request buffer full: client_request_buffer_max_size=" << Config.maxRequestBufferSize); | |
70 | return false; | |
71 | } | |
72 | if (haveCapacity == 0) { | |
73 | // haveCapacity is based on the SBuf visible window of the MemBlob buffer, which may fill up. | |
74 | // at which point bump the buffer back to default. This allocates a new MemBlob with any un-parsed bytes. | |
75 | inBuf.reserveCapacity(CLIENT_REQ_BUF_SZ); | |
76 | } else { | |
77 | const SBuf::size_type wantCapacity = min(static_cast<SBuf::size_type>(Config.maxRequestBufferSize), haveCapacity*2); | |
78 | inBuf.reserveCapacity(wantCapacity); | |
79 | } | |
80 | debugs(33, 2, "growing request buffer: available=" << inBuf.spaceSize() << " used=" << inBuf.length()); | |
81 | } | |
82 | return (inBuf.spaceSize() >= 2); | |
83 | } | |
84 | ||
85 | void | |
86 | Server::readSomeData() | |
87 | { | |
88 | if (reading()) | |
89 | return; | |
90 | ||
91 | debugs(33, 4, clientConnection << ": reading request..."); | |
92 | ||
93 | // we can only read if there is more than 1 byte of space free | |
94 | if (Config.maxRequestBufferSize - inBuf.length() < 2) | |
95 | return; | |
96 | ||
97 | typedef CommCbMemFunT<Server, CommIoCbParams> Dialer; | |
98 | reader = JobCallback(33, 5, Dialer, this, Server::doClientRead); | |
99 | Comm::Read(clientConnection, reader); | |
100 | } | |
101 | ||
102 | void | |
103 | Server::doClientRead(const CommIoCbParams &io) | |
104 | { | |
105 | debugs(33,5, io.conn); | |
106 | Must(reading()); | |
107 | reader = NULL; | |
108 | ||
109 | /* Bail out quickly on Comm::ERR_CLOSING - close handlers will tidy up */ | |
110 | if (io.flag == Comm::ERR_CLOSING) { | |
111 | debugs(33,5, io.conn << " closing Bailout."); | |
112 | return; | |
113 | } | |
114 | ||
115 | assert(Comm::IsConnOpen(clientConnection)); | |
116 | assert(io.conn->fd == clientConnection->fd); | |
117 | ||
118 | /* | |
119 | * Don't reset the timeout value here. The value should be | |
120 | * counting Config.Timeout.request and applies to the request | |
121 | * as a whole, not individual read() calls. | |
122 | * Plus, it breaks our lame *HalfClosed() detection | |
123 | */ | |
124 | ||
125 | maybeMakeSpaceAvailable(); | |
126 | CommIoCbParams rd(this); // will be expanded with ReadNow results | |
127 | rd.conn = io.conn; | |
128 | switch (Comm::ReadNow(rd, inBuf)) { | |
129 | case Comm::INPROGRESS: | |
130 | ||
131 | if (inBuf.isEmpty()) | |
132 | debugs(33, 2, io.conn << ": no data to process, " << xstrerr(rd.xerrno)); | |
133 | readSomeData(); | |
134 | return; | |
135 | ||
136 | case Comm::OK: | |
137 | statCounter.client_http.kbytes_in += rd.size; | |
138 | if (!receivedFirstByte_) | |
139 | receivedFirstByte(); | |
140 | // may comm_close or setReplyToError | |
141 | if (!handleReadData()) | |
142 | return; | |
143 | ||
144 | /* Continue to process previously read data */ | |
145 | break; | |
146 | ||
147 | case Comm::ENDFILE: // close detected by 0-byte read | |
148 | debugs(33, 5, io.conn << " closed?"); | |
149 | ||
150 | if (connFinishedWithConn(rd.size)) { | |
151 | clientConnection->close(); | |
152 | return; | |
153 | } | |
154 | ||
155 | /* It might be half-closed, we can't tell */ | |
156 | fd_table[io.conn->fd].flags.socket_eof = true; | |
157 | commMarkHalfClosed(io.conn->fd); | |
158 | fd_note(io.conn->fd, "half-closed"); | |
159 | ||
160 | /* There is one more close check at the end, to detect aborted | |
161 | * (partial) requests. At this point we can't tell if the request | |
162 | * is partial. | |
163 | */ | |
164 | ||
165 | /* Continue to process previously read data */ | |
166 | break; | |
167 | ||
168 | // case Comm::COMM_ERROR: | |
169 | default: // no other flags should ever occur | |
170 | debugs(33, 2, io.conn << ": got flag " << rd.flag << "; " << xstrerr(rd.xerrno)); | |
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 |