]> git.ipfire.org Git - ipfire-2.x.git/blob - src/patches/squid/squid-3.5-14119.patch
squid 3.5.22: latest patches (14119-14122)
[ipfire-2.x.git] / src / patches / squid / squid-3.5-14119.patch
1 ------------------------------------------------------------
2 revno: 14119
3 revision-id: squid3@treenet.co.nz-20161209015833-xm965d5l6u03qhew
4 parent: squid3@treenet.co.nz-20161130233304-lk3q0bx8gn5l3l85
5 fixes bug: http://bugs.squid-cache.org/show_bug.cgi?id=4174
6 author: Christos Tsantilas <chtsanti@users.sourceforge.net>
7 committer: Amos Jeffries <squid3@treenet.co.nz>
8 branch nick: 3.5
9 timestamp: Fri 2016-12-09 14:58:33 +1300
10 message:
11 Bug 4174 partial: fix Write.cc:41 "!ccb->active()" assertion.
12
13 The following sequence of events triggers this assertion:
14 - The server sends an 1xx control message.
15 - http.cc schedules ConnStateData::sendControlMsg call.
16 - Before sendControlMsg is fired, http.cc detects an error (e.g., I/O
17 error or timeout) and starts writing the reply to the user.
18 - The ConnStateData::sendControlMsg is fired, starts writing 1xx, and
19 hits the "no concurrent writes" assertion.
20
21 We could only reproduce this sequence in the lab after changing Squid
22 code to trigger a timeout at the right moment, but the sequence looks
23 plausible. Other event sequences might result in the same outcome.
24
25 To avoid concurrent writes, Squid now drops the control message if
26 Http::One::Server detects that a reply is already being written. Also,
27 ConnStateData delays reply writing until a pending control message write
28 has been completed.
29
30 This is a Measurement Factory project.
31 ------------------------------------------------------------
32 # Bazaar merge directive format 2 (Bazaar 0.90)
33 # revision_id: squid3@treenet.co.nz-20161209015833-xm965d5l6u03qhew
34 # target_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
35 # testament_sha1: 103c6fc1fa45d78ba7f9e85ab3d89fff898ee762
36 # timestamp: 2016-12-09 02:51:06 +0000
37 # source_branch: http://bzr.squid-cache.org/bzr/squid3/3.5
38 # base_revision_id: squid3@treenet.co.nz-20161130233304-\
39 # lk3q0bx8gn5l3l85
40 #
41 # Begin patch
42 === modified file 'src/client_side.cc'
43 --- src/client_side.cc 2016-09-23 20:49:24 +0000
44 +++ src/client_side.cc 2016-12-09 01:58:33 +0000
45 @@ -340,7 +340,21 @@
46 AsyncCall::Pointer call = commCbCall(33, 5, "ClientSocketContext::wroteControlMsg",
47 CommIoCbPtrFun(&WroteControlMsg, this));
48
49 - getConn()->writeControlMsgAndCall(this, rep.getRaw(), call);
50 + if (!getConn()->writeControlMsgAndCall(this, rep.getRaw(), call)) {
51 + // but still inform the caller (so it may resume its operation)
52 + doneWithControlMsg();
53 + }
54 +}
55 +
56 +void
57 +ClientSocketContext::doneWithControlMsg()
58 +{
59 + ScheduleCallHere(cbControlMsgSent);
60 + cbControlMsgSent = NULL;
61 +
62 + debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
63 + ClientSocketContextPushDeferredIfNeeded(this, getConn());
64 +
65 }
66
67 /// called when we wrote the 1xx response
68 @@ -351,7 +365,7 @@
69 return;
70
71 if (errflag == Comm::OK) {
72 - ScheduleCallHere(cbControlMsgSent);
73 + doneWithControlMsg();
74 return;
75 }
76
77 @@ -1455,6 +1469,8 @@
78
79 if (context != http->getConn()->getCurrentContext())
80 context->deferRecipientForLater(node, rep, receivedData);
81 + else if (context->controlMsgIsPending())
82 + context->deferRecipientForLater(node, rep, receivedData);
83 else
84 http->getConn()->handleReply(rep, receivedData);
85
86
87 === modified file 'src/client_side.h'
88 --- src/client_side.h 2016-06-18 13:36:07 +0000
89 +++ src/client_side.h 2016-12-09 01:58:33 +0000
90 @@ -129,9 +129,13 @@
91 /// starts writing 1xx control message to the client
92 void writeControlMsg(HttpControlMsg &msg);
93
94 + /// true if 1xx to the user is pending
95 + bool controlMsgIsPending() {return cbControlMsgSent != NULL;}
96 +
97 protected:
98 static IOCB WroteControlMsg;
99 void wroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, Comm::Flag errflag, int xerrno);
100 + void doneWithControlMsg();
101
102 private:
103 void prepareReply(HttpReply * rep);
104 @@ -387,7 +391,7 @@
105 void connectionTag(const char *aTag) { connectionTag_ = aTag; }
106
107 /// handle a control message received by context from a peer and call back
108 - virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call) = 0;
109 + virtual bool writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call) = 0;
110
111 /// ClientStream calls this to supply response header (once) and data
112 /// for the current ClientSocketContext.
113
114 === modified file 'src/servers/FtpServer.cc'
115 --- src/servers/FtpServer.cc 2016-06-30 21:09:12 +0000
116 +++ src/servers/FtpServer.cc 2016-12-09 01:58:33 +0000
117 @@ -1152,12 +1152,13 @@
118 writeErrorReply(reply, 451);
119 }
120
121 -void
122 +bool
123 Ftp::Server::writeControlMsgAndCall(ClientSocketContext *context, HttpReply *reply, AsyncCall::Pointer &call)
124 {
125 // the caller guarantees that we are dealing with the current context only
126 // the caller should also make sure reply->header.has(HDR_FTP_STATUS)
127 writeForwardedReplyAndCall(reply, call);
128 + return true;
129 }
130
131 void
132
133 === modified file 'src/servers/FtpServer.h'
134 --- src/servers/FtpServer.h 2016-03-15 18:14:15 +0000
135 +++ src/servers/FtpServer.h 2016-12-09 01:58:33 +0000
136 @@ -94,7 +94,7 @@
137 virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
138 virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData);
139 virtual int pipelinePrefetchMax() const;
140 - virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
141 + virtual bool writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
142 virtual time_t idleTimeout() const;
143
144 /* BodyPipe API */
145
146 === modified file 'src/servers/HttpServer.cc'
147 --- src/servers/HttpServer.cc 2016-01-01 00:14:27 +0000
148 +++ src/servers/HttpServer.cc 2016-12-09 01:58:33 +0000
149 @@ -35,7 +35,7 @@
150 virtual ClientSocketContext *parseOneRequest(Http::ProtocolVersion &ver);
151 virtual void processParsedRequest(ClientSocketContext *context, const Http::ProtocolVersion &ver);
152 virtual void handleReply(HttpReply *rep, StoreIOBuffer receivedData);
153 - virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
154 + virtual bool writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
155 virtual time_t idleTimeout() const;
156
157 /* BodyPipe API */
158 @@ -167,9 +167,16 @@
159 context->sendStartOfMessage(rep, receivedData);
160 }
161
162 -void
163 +bool
164 Http::Server::writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call)
165 {
166 + // Ignore this late control message if we have started sending a
167 + // reply to the user already (e.g., after an error).
168 + if (context->reply) {
169 + debugs(11, 2, "drop 1xx made late by " << context->reply);
170 + return false;
171 + }
172 +
173 // apply selected clientReplyContext::buildReplyHeader() mods
174 // it is not clear what headers are required for control messages
175 rep->header.removeHopByHopEntries();
176 @@ -184,6 +191,7 @@
177 Comm::Write(context->clientConnection, mb, call);
178
179 delete mb;
180 + return true;
181 }
182
183 ConnStateData *
184