errDetail = aDetail;
}
+void
+HttpRequest::clearError()
+{
+ debugs(11, 7, HERE << "old error details: " << errType << '/' << errDetail);
+ errType = ERR_NONE;
+ errDetail = ERR_DETAIL_NONE;
+}
+
const char *HttpRequest::packableURI(bool full_uri) const
{
if (full_uri)
/// sets error detail if no earlier detail was available
void detailError(err_type aType, int aDetail);
+ /// clear error details, useful for retries/repeats
+ void clearError();
protected:
void clean();
if (entry->isEmpty()) {
debugs(11,9, HERE << "creating ICAP error entry after ICAP failure");
ErrorState *err = new ErrorState(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
- err->xerrno = ERR_DETAIL_ICAP_RESPMOD_EARLY;
+ err->detailError(ERR_DETAIL_ICAP_RESPMOD_EARLY);
fwd->fail(err);
fwd->dontRetry(true);
} else if (request) { // update logged info directly
page_id = ERR_ACCESS_DENIED;
ErrorState *err = new ErrorState(page_id, HTTP_FORBIDDEN, request);
- err->xerrno = ERR_DETAIL_RESPMOD_BLOCK_EARLY;
+ err->detailError(ERR_DETAIL_RESPMOD_BLOCK_EARLY);
fwd->fail(err);
fwd->dontRetry(true);
ServerStateData::sendBodyIsTooLargeError()
{
ErrorState *err = new ErrorState(ERR_TOO_BIG, HTTP_FORBIDDEN, request);
- err->xerrno = errno;
fwd->fail(err);
fwd->dontRetry(true);
abortTransaction("Virgin body too large.");
return;
}
+ HttpRequest *request = dynamic_cast<HttpRequest*>(theMsg);
+ if (!request)
+ request = theCause;
+ assert(request);
+ request->clearError();
+
if (iterations > Adaptation::Config::service_iteration_limit) {
debugs(93,DBG_CRITICAL, "Adaptation iterations limit (" <<
Adaptation::Config::service_iteration_limit << ") exceeded:\n" <<
debugs(93,4, HERE << "launching " << xkind << " xaction #" << theLaunches);
Adaptation::Icap::Xaction *x = createXaction();
x->attempts = theLaunches;
- if (theLaunches > 1)
+ if (theLaunches > 1) {
+ x->clearError();
x->disableRetries();
+ }
if (theLaunches >= TheConfig.repeat_limit)
x->disableRepeats("over icap_retry_limit");
theXaction = initiateAdaptation(x);
request->detailError(ERR_ICAP_FAILURE, errDetail);
}
+void Adaptation::Icap::ModXact::clearError()
+{
+ HttpRequest *request = dynamic_cast<HttpRequest*>(adapted.header);
+ // if no adapted request, update virgin (and inherit its properties later)
+ if (!request)
+ request = const_cast<HttpRequest*>(&virginRequest());
+
+ if (request)
+ request->clearError();
+}
+
/* Adaptation::Icap::ModXactLauncher */
Adaptation::Icap::ModXactLauncher::ModXactLauncher(HttpMsg *virginHeader, HttpRequest *virginCause, Adaptation::ServicePointer aService):
/// record error detail in the virgin request if possible
virtual void detailError(int errDetail);
+ virtual void clearError();
private:
virtual void start();
// custom exception handling and end-of-call checks
virtual void callException(const std::exception &e);
virtual void callEnd();
+ // clear the error details on retries/repeats
+ virtual void clearError() {}
void dnsLookupDone(const ipcache_addrs *ia);
protected:
assert (repContext);
debugs(33, 5, "Connection first has failed for " << http->uri << ". Respond with an error");
repContext->setReplyToStoreEntry(sslServerBump->entry);
+ /*Save the original request for logging purposes*/
+ if (!context->http->al.request)
+ context->http->al.request = HTTPMSGLOCK(http->request);
+ /*Get the error details from the fake request used to retrieve SSL server certificate*/
+ http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail);
context->pullData();
return true;
}
ErrorState *err = new ErrorState(ERR_SECURE_CONNECT_FAIL, HTTP_SERVICE_UNAVAILABLE, request);
err->src_addr = clientConnection->remote;
-#ifdef EPROTO
- err->xerrno = EPROTO;
-#else
- err->xerrno = EACCES;
-#endif
Ssl::ErrorDetail *errDetail = new Ssl::ErrorDetail( SQUID_X509_V_ERR_DOMAIN_MISMATCH, sslServerBump->serverCert.get(), NULL);
err->detail = errDetail;
+ /*Save the original request for logging purposes*/
+ if (!context->http->al.request)
+ context->http->al.request = HTTPMSGLOCK(request);
repContext->setReplyToError(request->method, err);
assert(context->http->out.offset == 0);
context->pullData();
void
ConnStateData::getSslContextStart()
{
+ assert(areAllContextsForThisConnection());
+ freeAllContexts();
+ /* careful: freeAllContexts() above frees request, host, etc. */
+
if (port->generateHostCertificates) {
Ssl::CertificateProperties certProperties;
buildSslCertGenerationParams(certProperties);
sslConnectHostOrIp = host;
sslCommonName = host;
- //HTTPMSGLOCK(currentobject->http->request);
- assert(areAllContextsForThisConnection());
- freeAllContexts();
- //currentobject->connIsFinished();
-
- /* careful: freeAllContexts() above frees request, host, etc. */
-
// We are going to read new request
flags.readMore = true;
debugs(33, 5, HERE << "converting " << clientConnection << " to SSL");
sslCommonName = sslConnectHostOrIp;
else if (sslServerBump->serverCert.get())
sslCommonName = Ssl::CommonHostName(sslServerBump->serverCert.get());
+
+ // copy error detail from bump-server-first request to CONNECT request
+ if (currentobject != NULL && currentobject->http != NULL && currentobject->http->request)
+ currentobject->http->request->detailError(sslServerBump->request->errType, sslServerBump->request->errDetail);
}
getSslContextStart();
calloutContext->error->auth_user_request =
c != NULL && c->auth_user_request != NULL ? c->auth_user_request : request->auth_user_request;
- request->detailError(ERR_ICAP_FAILURE, errDetail);
+ calloutContext->error->detailError(errDetail);
calloutContext->readNextRequest = true;
c->expectNoForwarding();
doCallouts();
callback(NULL),
callback_data(NULL),
request_hdrs(NULL),
- err_msg(NULL)
+ err_msg(NULL),
#if USE_SSL
- , detail(NULL)
+ detail(NULL),
#endif
+ detailCode(ERR_DETAIL_NONE)
{
memset(&flags, 0, sizeof(flags));
memset(&ftp, 0, sizeof(ftp));
if (req != NULL) {
request = HTTPMSGLOCK(req);
src_addr = req->client_addr;
- request->detailError(type, ERR_DETAIL_NONE);
}
}
+void
+ErrorState::detailError(int detailCode)
+{
+ detailCode = detailCode;
+}
+
void
errorAppendEntry(StoreEntry * entry, ErrorState * err)
{
HttpReply *rep;
debugs(4, 3, HERE << conn << ", err=" << err);
assert(Comm::IsConnOpen(conn));
- /*
- * ugh, this is how we make sure error codes get back to
- * the client side for logging and error tracking.
- */
-
- if (err->request)
- err->request->detailError(err->type, err->xerrno);
/* moved in front of errorBuildBuf @?@ */
err->flags.flag_cbdata = 1;
/* do not memBufClean() or delete the content, it was absorbed by httpBody */
}
+ /* Make sure error codes get back to the client side for logging and error tracking */
+ if (request) {
+ int edc = ERR_DETAIL_NONE; // error detail code
+#if USE_SSL
+ if (detail)
+ edc = detail->errorNo();
+ else
+#endif
+ if (detailCode)
+ edc = detailCode;
+ else
+ edc = xerrno;
+ request->detailError(type, edc);
+ }
+
return rep;
}
#endif
#include "cbdata.h"
#include "comm/forward.h"
+#include "err_detail_type.h"
#include "ip/Address.h"
#include "MemBuf.h"
#if USE_SSL
*/
HttpReply *BuildHttpReply(void);
+ /**
+ * Sets the error details
+ */
+ void detailError(int detailCode);
+
private:
/**
* Locates error page template to be used for this error
#if USE_SSL
Ssl::ErrorDetail *detail;
#endif
+ /// type-specific detail about the transaction error;
+ /// overwrites xerrno; overwritten by detail, if any.
+ int detailCode;
private:
CBDATA_CLASS2(ErrorState);
};
// this server link regardless of what happens when connecting to it.
// IF sucessfuly connected this top destination will become the serverConnection().
request->hier.note(serverDestinations[0], request->GetHost());
+ request->clearError();
connectStart();
} else {
debugs(17, 3, HERE << "Connection failed: " << entry->url());
if (!err) {
ErrorState *anErr = new ErrorState(ERR_CANNOT_FORWARD, HTTP_INTERNAL_SERVER_ERROR, request);
- anErr->xerrno = errno;
fail(anErr);
} // else use actual error from last connection attempt
#if USE_SSL
debugs(17, 5, HERE << "pconn race happened");
pconnRace = raceHappened;
}
-
-#if USE_SSL
- if (errorState->type == ERR_SECURE_CONNECT_FAIL && errorState->detail)
- request->detailError(errorState->type, errorState->detail->errorNo());
- else
-#endif
- request->detailError(errorState->type, errorState->xerrno);
}
/**
if ((ssl = SSL_new(sslContext)) == NULL) {
debugs(83, 1, "fwdInitiateSSL: Error allocating handle: " << ERR_error_string(ERR_get_error(), NULL) );
ErrorState *anErr = new ErrorState(ERR_SOCKET_FAILURE, HTTP_INTERNAL_SERVER_ERROR, request);
- anErr->xerrno = errno;
+ // TODO: create Ssl::ErrorDetail with OpenSSL-supplied error code
fail(anErr);
self = NULL; // refcounted
return;
http_code = HTTP_INTERNAL_SERVER_ERROR;
}
- if (ftpState->request)
- ftpState->request->detailError(err_code, code);
-
ErrorState err(err_code, http_code, ftpState->request);
if (ftpState->old_request)
else
err.ftp.reply = xstrdup("");
+ // TODO: interpret as FTP-specific error code
+ err.detailError(code);
+
ftpState->entry->replaceHttpReply( err.BuildHttpReply() );
ftpSendQuit(ftpState);
return;
}
- errno = 0;
#if USE_DELAY_POOLS
read_sz = delayId.bytesWanted(1, read_sz);
#endif
if (flag != COMM_OK) {
debugs(50, 1, "gopherReadReply: error reading: " << xstrerror());
- if (ignoreErrno(errno)) {
+ if (ignoreErrno(xerrno)) {
AsyncCall::Pointer call = commCbCall(5,4, "gopherReadReply",
CommIoCbPtrFun(gopherReadReply, gopherState));
comm_read(conn, buf, read_sz, call);
} else {
ErrorState *err = new ErrorState(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, gopherState->fwd->request);
- err->xerrno = errno;
+ err->xerrno = xerrno;
gopherState->fwd->fail(err);
gopherState->serverConn->close();
}
if (errflag) {
ErrorState *err;
err = new ErrorState(ERR_WRITE_ERROR, HTTP_SERVICE_UNAVAILABLE, gopherState->fwd->request);
- err->xerrno = errno;
+ err->xerrno = xerrno;
err->port = gopherState->fwd->request->port;
err->url = xstrdup(entry->url());
gopherState->fwd->fail(err);
// should not matter because either client-side will provide its own or
// there will be no response at all (e.g., if the the client has left).
ErrorState *err = new ErrorState(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR, fwd->request);
- err->xerrno = ERR_DETAIL_SRV_REQMOD_REQ_BODY;
+ err->detailError(ERR_DETAIL_SRV_REQMOD_REQ_BODY);
fwd->fail(err);
}
comm_read(conn, aBuffer, BUFSIZ, call);
} else {
ErrorState *err = new ErrorState(ERR_READ_ERROR, HTTP_INTERNAL_SERVER_ERROR, fwd->request);
- err->xerrno = errno;
+ err->xerrno = xerrno;
fwd->fail(err);
conn->close();
}