AsyncCall::Pointer call = commCbCall(33, 5, "ClientSocketContext::wroteControlMsg",
CommIoCbPtrFun(&WroteControlMsg, this));
- getConn()->writeControlMsgAndCall(this, rep.getRaw(), call);
+ if (!getConn()->writeControlMsgAndCall(this, rep.getRaw(), call)) {
+ // but still inform the caller (so it may resume its operation)
+ doneWithControlMsg();
+ }
+}
+
+void
+ClientSocketContext::doneWithControlMsg()
+{
+ ScheduleCallHere(cbControlMsgSent);
+ cbControlMsgSent = NULL;
+
+ debugs(33, 3, clientConnection << ": calling PushDeferredIfNeeded after control msg wrote");
+ ClientSocketContextPushDeferredIfNeeded(this, getConn());
+
}
/// called when we wrote the 1xx response
return;
if (errflag == Comm::OK) {
- ScheduleCallHere(cbControlMsgSent);
+ doneWithControlMsg();
return;
}
if (context != http->getConn()->getCurrentContext())
context->deferRecipientForLater(node, rep, receivedData);
+ else if (context->controlMsgIsPending())
+ context->deferRecipientForLater(node, rep, receivedData);
else
http->getConn()->handleReply(rep, receivedData);
/// starts writing 1xx control message to the client
void writeControlMsg(HttpControlMsg &msg);
+ /// true if 1xx to the user is pending
+ bool controlMsgIsPending() {return cbControlMsgSent != NULL;}
+
protected:
static IOCB WroteControlMsg;
void wroteControlMsg(const Comm::ConnectionPointer &conn, char *bufnotused, size_t size, Comm::Flag errflag, int xerrno);
+ void doneWithControlMsg();
private:
void prepareReply(HttpReply * rep);
void connectionTag(const char *aTag) { connectionTag_ = aTag; }
/// handle a control message received by context from a peer and call back
- virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call) = 0;
+ virtual bool writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call) = 0;
/// ClientStream calls this to supply response header (once) and data
/// for the current ClientSocketContext.
writeErrorReply(reply, 451);
}
-void
+bool
Ftp::Server::writeControlMsgAndCall(ClientSocketContext *context, 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(HDR_FTP_STATUS)
writeForwardedReplyAndCall(reply, call);
+ return true;
}
void
virtual void clientPinnedConnectionClosed(const CommCloseCbParams &io);
virtual void handleReply(HttpReply *header, StoreIOBuffer receivedData);
virtual int pipelinePrefetchMax() const;
- virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
+ virtual bool writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
virtual time_t idleTimeout() const;
/* BodyPipe API */
virtual ClientSocketContext *parseOneRequest(Http::ProtocolVersion &ver);
virtual void processParsedRequest(ClientSocketContext *context, const Http::ProtocolVersion &ver);
virtual void handleReply(HttpReply *rep, StoreIOBuffer receivedData);
- virtual void writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
+ virtual bool writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call);
virtual time_t idleTimeout() const;
/* BodyPipe API */
context->sendStartOfMessage(rep, receivedData);
}
-void
+bool
Http::Server::writeControlMsgAndCall(ClientSocketContext *context, HttpReply *rep, AsyncCall::Pointer &call)
{
+ // 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;
+ }
+
// apply selected clientReplyContext::buildReplyHeader() mods
// it is not clear what headers are required for control messages
rep->header.removeHopByHopEntries();
Comm::Write(context->clientConnection, mb, call);
delete mb;
+ return true;
}
ConnStateData *