#include "CommCalls.h"
#include "HttpControlMsg.h"
+void
+HttpControlMsgSink::doneWithControlMsg()
+{
+ if (cbControlMsgSent) {
+ ScheduleCallHere(cbControlMsgSent);
+ cbControlMsgSent = nullptr;
+ }
+}
+
/// called when we wrote the 1xx response
void
HttpControlMsgSink::wroteControlMsg(const CommIoCbParams ¶ms)
return;
if (params.flag == Comm::OK) {
- if (cbControlMsgSent)
- ScheduleCallHere(cbControlMsgSent);
+ doneWithControlMsg();
return;
}
/// called to send the 1xx message and notify the Source
virtual void sendControlMsg(HttpControlMsg msg) = 0;
+ virtual void doneWithControlMsg();
+
/// callback to handle Comm::Write completion
void wroteControlMsg(const CommIoCbParams &);
// TODO: enforces HTTP/1 MUST on pipeline order, but is irrelevant to HTTP/2
if (context != http->getConn()->pipeline.front())
context->deferRecipientForLater(node, rep, receivedData);
+ else if (http->getConn()->cbControlMsgSent) // 1xx to the user is pending
+ context->deferRecipientForLater(node, rep, receivedData);
else
http->getConn()->handleReply(rep, receivedData);
typedef CommCbMemFunT<HttpControlMsgSink, CommIoCbParams> Dialer;
AsyncCall::Pointer call = JobCallback(33, 5, Dialer, this, HttpControlMsgSink::wroteControlMsg);
- writeControlMsgAndCall(rep.getRaw(), call);
+ if (!writeControlMsgAndCall(rep.getRaw(), call)) {
+ // but still inform the caller (so it may resume its operation)
+ doneWithControlMsg();
+ }
return;
}
clientConnection->close();
}
+void
+ConnStateData::doneWithControlMsg()
+{
+ HttpControlMsgSink::doneWithControlMsg();
+
+ if (Http::StreamPointer deferredRequest = pipeline.front()) {
+ debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
+ ClientSocketContextPushDeferredIfNeeded(deferredRequest, this);
+ }
+}
+
/// Our close handler called by Comm when the pinned connection is closed
void
ConnStateData::clientPinnedConnectionClosed(const CommCloseCbParams &io)
/* HttpControlMsgSink API */
virtual void sendControlMsg(HttpControlMsg);
+ virtual void doneWithControlMsg();
/// Traffic parsing
bool clientParseRequests();
void connectionTag(const char *aTag) { connectionTag_ = aTag; }
/// handle a control message received by context from a peer and call back
- virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
+ virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) = 0;
/// ClientStream calls this to supply response header (once) and data
/// for the current Http::Stream.
writeErrorReply(reply, 451);
}
-void
+bool
Ftp::Server::writeControlMsgAndCall(HttpReply *reply, AsyncCall::Pointer &call)
{
// the caller guarantees that we are dealing with the current context only
// the caller should also make sure reply->header.has(Http::HdrType::FTP_STATUS)
writeForwardedReplyAndCall(reply, call);
+ return true;
}
void
virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io) override;
virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData) override;
virtual int pipelinePrefetchMax() const override;
- virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) override;
+ virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call) override;
virtual time_t idleTimeout() const override;
/* BodyPipe API */
context->sendStartOfMessage(rep, receivedData);
}
-void
+bool
Http::One::Server::writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call)
{
- const ClientHttpRequest *http = pipeline.front()->http;
+ Http::StreamPointer context = pipeline.front();
+ Must(context != nullptr);
+
+ // Ignore this late control message if we have started sending a
+ // reply to the user already (e.g., after an error).
+ if (context->reply) {
+ debugs(11, 2, "drop 1xx made late by " << context->reply);
+ return false;
+ }
+
+ const ClientHttpRequest *http = context->http;
// apply selected clientReplyContext::buildReplyHeader() mods
// it is not clear what headers are required for control messages
Comm::Write(clientConnection, mb, call);
delete mb;
+ return true;
}
ConnStateData *
virtual Http::Stream *parseOneRequest();
virtual void processParsedRequest(Http::StreamPointer &context);
virtual void handleReply(HttpReply *rep, StoreIOBuffer receivedData);
- virtual void writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call);
+ virtual bool writeControlMsgAndCall(HttpReply *rep, AsyncCall::Pointer &call);
virtual time_t idleTimeout() const;
/* BodyPipe API */
#include "HttpControlMsg.h"
void HttpControlMsgSink::wroteControlMsg(CommIoCbParams const&) STUB
+void HttpControlMsgSink::doneWithControlMsg() STUB