<p><b>Unable to forward this request at this time.</b></p>
</blockquote>
-<p>This request could not be forwarded to the origin server or to any parent caches. The most likely cause for this error is that the cache administrator does not allow this cache to make direct connections to origin servers, and all configured parent caches are currently unreachable.</p>
+<p>This request could not be forwarded to the origin server or to any parent caches.</p>
+
+<p>Some possible problems are:</p>
+<ul>
+<li id="network-down">An Internet connection needed to access this domains origin servers may be down.</li>
+<li id="no-peer">All configured parent caches may be currently unreachable.</li>
+<li id="permission-denied">The administrator may not allow this cache to make direct connections to origin servers.</li>
+</ul>
<p>Your cache administrator is <a href="mailto:%w%W">%w</a>.</p>
class HttpRequest;
class StoreEntry;
+class ErrorState;
-typedef void PSC(Comm::ConnectionList *, void *);
+typedef void PSC(Comm::ConnectionList *, ErrorState *, void *);
SQUIDCEXTERN void peerSelect(Comm::ConnectionList *, HttpRequest *, StoreEntry *, PSC *, void *data);
SQUIDCEXTERN void peerSelectInit(void);
int direct; // TODO: fold always_direct/never_direct/prefer_direct into this now that ACL can do a multi-state result.
PSC *callback;
void *callback_data;
+ ErrorState *lastError;
Comm::ConnectionList *paths; ///< the callers paths array. to be filled with our final results.
FwdServer *servers; ///< temporary linked list of peers we will pass back.
/**** CALLBACK WRAPPERS ************************************************************/
static void
-fwdPeerSelectionCompleteWrapper(Comm::ConnectionList * unused, void *data)
+fwdPeerSelectionCompleteWrapper(Comm::ConnectionList * unused, ErrorState *err, void *data)
{
FwdState *fwd = (FwdState *) data;
+ if (err)
+ fwd->fail(err);
fwd->startConnectionOrFail();
}
#include "squid.h"
#include "DnsLookupDetails.h"
+#include "errorpage.h"
#include "event.h"
#include "PeerSelectState.h"
#include "Store.h"
psstate->entry = NULL;
}
+ delete psstate->lastError;
+
cbdataFree(psstate);
}
void *cbdata;
if (cbdataReferenceValidDone(psstate->callback_data, &cbdata)) {
- callback(psstate->paths, cbdata);
+ callback(psstate->paths, psstate->lastError, cbdata);
+ psstate->lastError = NULL; // FwdState has taken control over the ErrorState object.
}
peerSelectStateFree(psstate);
}
} else {
debugs(44, 3, HERE << "Unknown host: " << fs->_peer ? fs->_peer->host : psstate->request->GetHost());
+ // discard any previous error.
+ delete psstate->lastError;
+ psstate->lastError = NULL;
+ if (fs->code == HIER_DIRECT) {
+ psstate->lastError = new ErrorState(ERR_DNS_FAIL, HTTP_SERVICE_UNAVAILABLE, psstate->request);
+ psstate->lastError->dnsError = details.error;
+ }
}
psstate->servers = fs->next;
direct(DIRECT_UNKNOWN),
callback (NULL),
callback_data (NULL),
+ lastError(NULL),
servers (NULL),
first_parent_miss(),
closest_parent_miss(),
}
static void
-tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, void *data)
+tunnelPeerSelectComplete(Comm::ConnectionList *peer_paths, ErrorState *err, void *data)
{
TunnelStateData *tunnelState = (TunnelStateData *)data;
if (peer_paths == NULL || peer_paths->size() < 1) {
debugs(26, 3, HERE << "No paths found. Aborting CONNECT");
- ErrorState *err;
- err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
- *tunnelState->status_ptr = HTTP_SERVICE_UNAVAILABLE;
+ if (!err) {
+ err = errorCon(ERR_CANNOT_FORWARD, HTTP_SERVICE_UNAVAILABLE, tunnelState->request);
+ }
+ *tunnelState->status_ptr = err->httpStatus;
err->callback = tunnelErrorComplete;
err->callback_data = tunnelState;
errorSend(tunnelState->client.conn, err);
return;
}
+ delete err;
+
debugs(26, 3, HERE << "paths=" << peer_paths->size() << ", p[0]={" << (*peer_paths)[0] << "}, serverDest[0]={" <<
tunnelState->serverDestinations[0] << "}");