예제 #1
0
static void
peerCountMcastPeersDone(void *data)
{
    ps_state *psstate = data;
    peer *p = psstate->callback_data;
    StoreEntry *fake = psstate->entry;
    if (cbdataValid(p)) {
	p->mcast.flags.counting = 0;
	p->mcast.avg_n_members = doubleAverage(p->mcast.avg_n_members,
	    (double) psstate->ping.n_recv,
	    ++p->mcast.n_times_counted,
	    10);
	debug(15, 1) ("Group %s: %d replies, %4.1f average, RTT %d\n",
	    p->host,
	    psstate->ping.n_recv,
	    p->mcast.avg_n_members,
	    p->stats.rtt);
	p->mcast.n_replies_expected = (int) p->mcast.avg_n_members;
    }
    cbdataUnlock(p);
    EBIT_SET(fake->flags, ENTRY_ABORTED);
    requestUnlink(fake->mem_obj->request);
    fake->mem_obj->request = NULL;
    storeReleaseRequest(fake);
    storeUnlockObject(fake);
    requestUnlink(psstate->request);
    cbdataFree(psstate);
}
예제 #2
0
/* free fetch state structures
 * must be called only when fetch cbdata is valid */
static void
peerDigestFetchFinish(DigestFetchState * fetch, int err)
{
    assert(fetch->entry && fetch->request);

    if (fetch->old_entry) {
	debug(72, 2) ("peerDigestFetchFinish: deleting old entry\n");
	storeUnregister(fetch->old_entry, fetch);
	storeReleaseRequest(fetch->old_entry);
	storeUnlockObject(fetch->old_entry);
	fetch->old_entry = NULL;
    }
    /* update global stats */
    kb_incr(&Counter.cd.kbytes_sent, (size_t) fetch->sent.bytes);
    kb_incr(&Counter.cd.kbytes_recv, (size_t) fetch->recv.bytes);
    Counter.cd.msgs_sent += fetch->sent.msg;
    Counter.cd.msgs_recv += fetch->recv.msg;

    /* unlock everything */
    storeUnregister(fetch->entry, fetch);
    storeUnlockObject(fetch->entry);
    requestUnlink(fetch->request);
    fetch->entry = NULL;
    fetch->request = NULL;
    assert(fetch->pd == NULL);
    cbdataUnlock(fetch);
    cbdataFree(fetch);
}
예제 #3
0
static void asyncPrefetchTs(const char *url)
{
    debug(207, 1) ("start asyncPrefetchTs async prefetch: '%s'\n", url);
        
    request_t *request = NULL;
    StoreEntry *entry = NULL;
    request = modifyRequestUrlstoreUrl(url);
    request->flags.cachable = CACHE;
    
    if (storeGetPublicByRequest(request) != NULL) {
        debug(207, 3) ("this entry has already exist,give up async prefetch: '%s'\n", request->store_url);
        return;
    }
    
	entry = storeCreateEntry(urlCanonical(request),
			request->flags,
			request->method);
    if (request->store_url) 
        storeEntrySetStoreUrl(entry, request->store_url);

    if(Config.onoff.collapsed_forwarding)
    {
        EBIT_SET(entry->flags, KEY_EARLY_PUBLIC);
        storeSetPublicKey(entry);
    }

	fwdStart(-1, entry, request);
	requestUnlink(request);
}
static void
waisStateFree(int fdnotused, void *data)
{
    WaisStateData *waisState = data;
    if (waisState == NULL)
	return;
    storeUnlockObject(waisState->entry);
    requestUnlink(waisState->request);
    cbdataFree(waisState);
}
예제 #5
0
파일: asn.c 프로젝트: CoolerVoid/squid
static void
asStateFree(void *data)
{
    ASState *asState = data;
    debug(53, 3) ("asStateFree: %s\n", storeUrl(asState->entry));
    storeClientUnregister(asState->sc, asState->entry, asState);
    storeUnlockObject(asState->entry);
    requestUnlink(asState->request);
    cbdataFree(asState);
}
예제 #6
0
static void
netdbExchangeDone(void *data)
{
    netdbExchangeState *ex = data;
    debug(38, 3) ("netdbExchangeDone: %s\n", storeUrl(ex->e));
    requestUnlink(ex->r);
    storeClientUnregister(ex->sc, ex->e, ex);
    storeUnlockObject(ex->e);
    cbdataUnlock(ex->p);
    cbdataFree(ex);
}
예제 #7
0
static inline void modify_request(clientHttpRequest * http)
{
	debug(97, 3)("modify_request: start, uri=[%s]\n", http->uri);
	request_t* old_request = http->request;
	request_t* new_request = urlParse(old_request->method, http->uri);
	safe_free(http->uri);

	if (new_request)
	{
		safe_free(http->uri);
		http->uri = xstrdup(urlCanonical(new_request));
		if(!http->log_uri)
			http->log_uri = xstrdup(urlCanonicalClean(old_request));
		new_request->http_ver = old_request->http_ver;
		httpHeaderAppend(&new_request->header, &old_request->header);
		new_request->client_addr = old_request->client_addr;
		new_request->client_port = old_request->client_port;
#if FOLLOW_X_FORWARDED_FOR
		new_request->indirect_client_addr = old_request->indirect_client_addr;
#endif /* FOLLOW_X_FORWARDED_FOR */
		new_request->my_addr = old_request->my_addr;
		new_request->my_port = old_request->my_port;
		new_request->flags = old_request->flags;
		new_request->flags.redirected = 1;
		if (old_request->auth_user_request)
		{
			new_request->auth_user_request = old_request->auth_user_request;
			authenticateAuthUserRequestLock(new_request->auth_user_request);
		}
		if (old_request->body_reader)
		{
			new_request->body_reader = old_request->body_reader;
			new_request->body_reader_data = old_request->body_reader_data;
			old_request->body_reader = NULL;
			old_request->body_reader_data = NULL;
		}
		new_request->content_length = old_request->content_length;
		if (strBuf(old_request->extacl_log))
			new_request->extacl_log = stringDup(&old_request->extacl_log);
		if (old_request->extacl_user)
			new_request->extacl_user = xstrdup(old_request->extacl_user);
		if (old_request->extacl_passwd)
			new_request->extacl_passwd = xstrdup(old_request->extacl_passwd);
		if(old_request->cc_request_private_data)
		{
			new_request->cc_request_private_data = old_request->cc_request_private_data;
			old_request->cc_request_private_data = NULL;
		}
		requestUnlink(old_request);
		http->request = requestLink(new_request);
	}
}
예제 #8
0
파일: errormap.c 프로젝트: cristdai/squid2
static void
errorMapFetchComplete(ErrorMapState * state)
{
    storeClientUnregister(state->sc, state->e, state);
    state->sc = NULL;
    storeUnlockObject(state->e);
    state->e = NULL;
    requestUnlink(state->req);
    state->req = NULL;
    cbdataUnlock(state->callback_data);
    state->callback_data = NULL;
    cbdataFree(state);
}
예제 #9
0
static void
peerMonitorCompleted(PeerMonitor * pm)
{
    int state = PEER_ALIVE;
    peer *p = pm->peer;
    storeClientUnregister(pm->running.sc, pm->running.e, pm);
    storeUnlockObject(pm->running.e);
    requestUnlink(pm->running.req);
    memFree(pm->running.buf, MEM_4K_BUF);
    if (pm->running.timeout_set) {
	eventDelete(peerMonitorTimeout, pm);
	pm->running.timeout_set = 0;
    }
    if (!cbdataValid(pm->peer)) {
	cbdataFree(pm);
	return;
    }
    /* Figure out if the response was OK or not */
    if (pm->running.status != HTTP_OK) {
	debug(DBG, 1) ("peerMonitor %s: Failed, status != 200 (%d)\n",
	    p->name, pm->running.status);
	state = PEER_DEAD;
    } else if (pm->running.size < p->monitor.min) {
	debug(DBG, 1) ("peerMonitor %s: Failed, reply size %d < min %d\n",
	    p->name, pm->running.size, p->monitor.min);
	state = PEER_DEAD;
    } else if (pm->running.size > p->monitor.max && p->monitor.max > 0) {
	debug(DBG, 1) ("peerMonitor %s: Failed, reply size %d > max %d\n",
	    p->name, pm->running.size, p->monitor.max);
	state = PEER_DEAD;
    } else {
	debug(DBG, 2) ("peerMonitor %s: OK\n", p->name);
    }
    p->monitor.state = state;
    if (state != p->stats.logged_state) {
	switch (state) {
	case PEER_ALIVE:
	    debug(DBG, 1) ("Detected REVIVED %s: %s\n",
		neighborTypeStr(p), p->name);
	    peerClearRR();
	    break;
	case PEER_DEAD:
	    debug(DBG, 1) ("Detected DEAD %s: %s\n",
		neighborTypeStr(p), p->name);
	    break;
	}
	p->stats.logged_state = state;
    }
    memset(&pm->running, 0, sizeof(pm->running));
    eventAdd(pm->name, peerMonitorRequest, pm, (double) (pm->last_probe + pm->peer->monitor.interval - current_dtime), 1);
}
예제 #10
0
static void
gopherStateFree(int fdnotused, void *data)
{
    GopherStateData *gopherState = data;
    if (gopherState == NULL)
	return;
    if (gopherState->entry) {
	storeUnlockObject(gopherState->entry);
    }
    if (gopherState->req) {
	requestUnlink(gopherState->req);
    }
    memFree(gopherState->buf, MEM_4K_BUF);
    gopherState->buf = NULL;
    cbdataFree(gopherState);
}
예제 #11
0
void
errorStateFree(ErrorState * err)
{
    requestUnlink(err->request);
    safe_free(err->redirect_url);
    safe_free(err->url);
    safe_free(err->dnsserver_msg);
    safe_free(err->request_hdrs);
    wordlistDestroy(&err->ftp.server_msg);
    safe_free(err->ftp.request);
    safe_free(err->ftp.reply);
    if (err->auth_user_request)
	authenticateAuthUserRequestUnlock(err->auth_user_request);
    err->auth_user_request = NULL;
    cbdataFree(err);
}
예제 #12
0
static void
authNegotiateRequestFree(negotiate_request_t * negotiate_request)
{
    if (!negotiate_request)
	return;
    safe_free(negotiate_request->server_blob);
    safe_free(negotiate_request->client_blob);
    if (negotiate_request->authserver != NULL) {
	debug(29, 9) ("authenticateNegotiateRequestFree: releasing server '%p'\n", negotiate_request->authserver);
	authenticateNegotiateReleaseServer(negotiate_request);
    }
    if (negotiate_request->request) {
	requestUnlink(negotiate_request->request);
	negotiate_request->request = NULL;
    }
    memPoolFree(negotiate_request_pool, negotiate_request);
}
예제 #13
0
파일: peer_select.c 프로젝트: selecli/squid
static void
peerSelectStateFree(ps_state * psstate)
{
	if (psstate->acl_checklist)
	{
		debug(44, 1) ("calling aclChecklistFree() from peerSelectStateFree\n");
		aclChecklistFree(psstate->acl_checklist);
	}
	requestUnlink(psstate->request);
	psstate->request = NULL;
	if (psstate->entry)
	{
		assert(psstate->entry->ping_status != PING_WAITING);
		storeUnlockObject(psstate->entry);
		psstate->entry = NULL;
	}
	cbdataFree(psstate);
}
예제 #14
0
static void
sslStateFree(SslStateData * sslState)
{
    debug(26, 3) ("sslStateFree: sslState=%p\n", sslState);
    assert(sslState != NULL);
    assert(sslState->client.fd == -1);
    assert(sslState->server.fd == -1);
    safe_free(sslState->server.buf);
    safe_free(sslState->client.buf);
    safe_free(sslState->url);
    fwdServersFree(&sslState->servers);
    sslState->host = NULL;
    requestUnlink(sslState->request);
    sslState->request = NULL;
#if DELAY_POOLS
    delayUnregisterDelayIdPtr(&sslState->delay_id);
#endif
    cbdataFree(sslState);
}
예제 #15
0
/* finishes swap out sequence for the digest; schedules next rewrite */
static void
storeDigestRewriteFinish(StoreEntry * e)
{
    assert(sd_state.rewrite_lock && e == sd_state.rewrite_lock->data);
    storeComplete(e);
    storeTimestampsSet(e);
    debug(71, 2) ("storeDigestRewriteFinish: digest expires at %ld (%+d)\n",
	(long int) e->expires, (int) (e->expires - squid_curtime));
    /* is this the write order? @?@ */
    requestUnlink(e->mem_obj->request);
    e->mem_obj->request = NULL;
    storeUnlockObject(e);
    cbdataFree(sd_state.rewrite_lock);
    e = NULL;
    sd_state.rewrite_lock = NULL;
    sd_state.rewrite_count++;
    eventAdd("storeDigestRewriteStart", storeDigestRewriteStart, NULL, (double)
	Config.digest.rewrite_period, 1);
    /* resume pending Rebuild if any */
    if (sd_state.rebuild_lock)
	storeDigestRebuildResume();
}
예제 #16
0
static void
authenticateNegotiateHandleReply(void *data, void *srv, char *reply)
{
    authenticateStateData *r = data;
    int valid;
    auth_user_request_t *auth_user_request;
    auth_user_t *auth_user;
    negotiate_user_t *negotiate_user;
    negotiate_request_t *negotiate_request;
    char *blob, *arg;
    debug(29, 9) ("authenticateNegotiateHandleReply: Helper: '%p' {%s}\n", srv, reply ? reply : "<NULL>");
    valid = cbdataValid(r->data);
    if (!valid) {
	debug(29, 2) ("AuthenticateNegotiateHandleReply: invalid callback data. Releasing helper '%p'.\n", srv);
	negotiate_request = r->auth_user_request->scheme_data;
	if (negotiate_request != NULL) {
	    if (negotiate_request->authserver == NULL)
		negotiate_request->authserver = srv;
	    authenticateNegotiateReleaseServer(negotiate_request);
	}
	cbdataUnlock(r->data);
	authenticateStateFree(r);
	return;
    }
    if (!reply) {
	debug(29, 1) ("AuthenticateNegotiateHandleReply: Helper '%p' crashed!.\n", srv);
	reply = (char *) "BH Internal error";
    }
    auth_user_request = r->auth_user_request;

    negotiate_request = auth_user_request->scheme_data;
    assert(negotiate_request != NULL);

    assert(negotiate_request->waiting);
    negotiate_request->waiting = 0;
    safe_free(negotiate_request->client_blob);

    auth_user = auth_user_request->auth_user;
    assert(auth_user != NULL);
    assert(auth_user->auth_type == AUTH_NEGOTIATE);
    negotiate_user = auth_user_request->auth_user->scheme_data;

    if (negotiate_request->authserver == NULL)
	negotiate_request->authserver = srv;
    else
	assert(negotiate_request->authserver == srv);

    /* seperate out the useful data */
    blob = strchr(reply, ' ');
    if (blob) {
	blob++;
	arg = strchr(blob + 1, ' ');
    } else {
	arg = NULL;
    }

    if (strncasecmp(reply, "TT ", 3) == 0) {
	/* we have been given a blob to send to the client */
	if (arg)
	    *arg++ = '\0';
	safe_free(negotiate_request->server_blob);
	negotiate_request->request->flags.must_keepalive = 1;
	if (negotiate_request->request->flags.proxy_keepalive) {
	    negotiate_request->server_blob = xstrdup(blob);
	    negotiate_request->auth_state = AUTHENTICATE_STATE_NEGOTIATE;
	    safe_free(auth_user_request->message);
	    auth_user_request->message = xstrdup("Authentication in progress");
	    debug(29, 4) ("authenticateNegotiateHandleReply: Need to challenge the client with a server blob '%s'\n", blob);
	} else {
	    negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED;
	    safe_free(auth_user_request->message);
	    auth_user_request->message = xstrdup("NTLM authentication requires a persistent connection");
	}
    } else if (strncasecmp(reply, "AF ", 3) == 0 && arg != NULL) {
	auth_user_hash_pointer *usernamehash;
	/* we're finished, release the helper */
	if (arg)
	    *arg++ = '\0';
	safe_free(negotiate_user->username);
	negotiate_user->username = xstrdup(arg);
	safe_free(auth_user_request->message);
	auth_user_request->message = xstrdup("Login successful");
	safe_free(negotiate_request->server_blob);
	negotiate_request->server_blob = xstrdup(blob);
	debug(29, 4) ("authenticateNegotiateHandleReply: Successfully validated user via Negotiate. Username '%s'\n", arg);
	/* this connection is authenticated */
	debug(29, 4) ("authenticated user %s\n", negotiate_user->username);
	/* see if this is an existing user with a different proxy_auth 
	 * string */
	usernamehash = hash_lookup(proxy_auth_username_cache, negotiate_user->username);
	if (usernamehash) {
	    while (usernamehash && (usernamehash->auth_user->auth_type != auth_user->auth_type || authenticateNegotiatecmpUsername(usernamehash->auth_user->scheme_data, negotiate_user) != 0))
		usernamehash = usernamehash->next;
	}
	if (usernamehash) {
	    /* we can't seamlessly recheck the username due to the 
	     * challenge nature of the protocol. Just free the 
	     * temporary auth_user */
	    authenticateAuthUserMerge(auth_user, usernamehash->auth_user);
	    auth_user = usernamehash->auth_user;
	    auth_user_request->auth_user = auth_user;
	} else {
	    /* store user in hash's */
	    authenticateUserNameCacheAdd(auth_user);
	}
	/* set these to now because this is either a new login from an 
	 * existing user or a new user */
	auth_user->expiretime = current_time.tv_sec;
	authenticateNegotiateReleaseServer(negotiate_request);
	negotiate_request->auth_state = AUTHENTICATE_STATE_DONE;
    } else if (strncasecmp(reply, "NA ", 3) == 0 && arg != NULL) {
	if (arg)
	    *arg++ = '\0';
	safe_free(auth_user_request->message);
	auth_user_request->message = xstrdup(arg);
	negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED;
	safe_free(negotiate_request->server_blob);
	negotiate_request->server_blob = xstrdup(blob);
	authenticateNegotiateReleaseServer(negotiate_request);
	debug(29, 4) ("authenticateNegotiateHandleReply: Failed validating user via Negotiate. Error returned '%s'\n", arg);
    } else if (strncasecmp(reply, "BH ", 3) == 0) {
	/* TODO kick off a refresh process. This can occur after a YR or after
	 * a KK. If after a YR release the helper and resubmit the request via 
	 * Authenticate Negotiate start. 
	 * If after a KK deny the user's request w/ 407 and mark the helper as 
	 * Needing YR. */
	auth_user_request->message = xstrdup(blob);
	negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED;
	safe_free(negotiate_request->server_blob);
	authenticateNegotiateReleaseServer(negotiate_request);
	debug(29, 1) ("authenticateNegotiateHandleReply: Error validating user via Negotiate. Error returned '%s'\n", reply);
    } else {
	fatalf("authenticateNegotiateHandleReply: *** Unsupported helper response ***, '%s'\n", reply);
    }
    requestUnlink(negotiate_request->request);
    negotiate_request->request = NULL;
    r->handler(r->data, NULL);
    cbdataUnlock(r->data);
    authenticateStateFree(r);
}
예제 #17
0
static void
urnHandleReply(void *data, char *buf, ssize_t size)
{
    UrnState *urnState = data;
    StoreEntry *e = urnState->entry;
    StoreEntry *urlres_e = urnState->urlres_e;
    char *s = NULL;
    size_t k;
    HttpReply *rep;
    url_entry *urls;
    url_entry *u;
    url_entry *min_u;
    MemBuf mb;
    ErrorState *err;
    int i;
    int urlcnt = 0;
    http_version_t version;

    debug(52, 3) ("urnHandleReply: Called with size=%d.\n", (int) size);
    if (EBIT_TEST(urlres_e->flags, ENTRY_ABORTED)) {
	memFree(buf, MEM_4K_BUF);
	return;
    }
    if (size == 0) {
	memFree(buf, MEM_4K_BUF);
	return;
    } else if (size < 0) {
	memFree(buf, MEM_4K_BUF);
	return;
    }
    if (urlres_e->store_status == STORE_PENDING && size < SM_PAGE_SIZE) {
	storeClientCopy(urnState->sc, urlres_e,
	    size,
	    0,
	    SM_PAGE_SIZE,
	    buf,
	    urnHandleReply,
	    urnState);
	return;
    }
    /* we know its STORE_OK */
    k = headersEnd(buf, size);
    if (0 == k) {
	debug(52, 1) ("urnHandleReply: didn't find end-of-headers for %s\n",
	    storeUrl(e));
	return;
    }
    s = buf + k;
    assert(urlres_e->mem_obj->reply);
    httpReplyParse(urlres_e->mem_obj->reply, buf, k);
    debug(52, 3) ("mem->reply exists, code=%d.\n",
	urlres_e->mem_obj->reply->sline.status);
    if (urlres_e->mem_obj->reply->sline.status != HTTP_OK) {
	debug(52, 3) ("urnHandleReply: failed.\n");
	err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
	err->request = requestLink(urnState->request);
	err->url = xstrdup(storeUrl(e));
	errorAppendEntry(e, err);
	return;
    }
    while (xisspace(*s))
	s++;
    urls = urnParseReply(s, urnState->request->method);
    for (i = 0; NULL != urls[i].url; i++)
	urlcnt++;
    debug(53, 3) ("urnFindMinRtt: Counted %d URLs\n", i);
    if (urls == NULL) {		/* unkown URN error */
	debug(52, 3) ("urnTranslateDone: unknown URN %s\n", storeUrl(e));
	err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
	err->request = requestLink(urnState->request);
	err->url = xstrdup(storeUrl(e));
	errorAppendEntry(e, err);
	return;
    }
    min_u = urnFindMinRtt(urls, urnState->request->method, NULL);
    qsort(urls, urlcnt, sizeof(*urls), url_entry_sort);
    storeBuffer(e);
    memBufDefInit(&mb);
    memBufPrintf(&mb,
	"<TITLE>Select URL for %s</TITLE>\n"
	"<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n"
	"<H2>Select URL for %s</H2>\n"
	"<TABLE BORDER=\"0\" WIDTH=\"100%%\">\n", storeUrl(e), storeUrl(e));
    for (i = 0; i < urlcnt; i++) {
	u = &urls[i];
	debug(52, 3) ("URL {%s}\n", u->url);
	memBufPrintf(&mb,
	    "<TR><TD><A HREF=\"%s\">%s</A></TD>", u->url, u->url);
	if (urls[i].rtt > 0)
	    memBufPrintf(&mb,
		"<TD align=\"right\">%4d <it>ms</it></TD>", u->rtt);
	else
	    memBufPrintf(&mb, "<TD align=\"right\">Unknown</TD>");
	memBufPrintf(&mb,
	    "<TD>%s</TD></TR>\n", u->flags.cached ? "    [cached]" : " ");
    }
    memBufPrintf(&mb,
	"</TABLE>"
	"<HR noshade size=\"1px\">\n"
	"<ADDRESS>\n"
	"Generated by %s@%s\n"
	"</ADDRESS>\n",
	full_appname_string, getMyHostname());
    rep = e->mem_obj->reply;
    httpReplyReset(rep);
    httpBuildVersion(&version, 1, 0);
    httpReplySetHeaders(rep, version, HTTP_MOVED_TEMPORARILY, NULL,
	"text/html", mb.size, 0, squid_curtime);
    if (urnState->flags.force_menu) {
	debug(51, 3) ("urnHandleReply: forcing menu\n");
    } else if (min_u) {
	httpHeaderPutStr(&rep->header, HDR_LOCATION, min_u->url);
    }
    httpBodySet(&rep->body, &mb);
    httpReplySwapOut(rep, e);
    storeComplete(e);
    memFree(buf, MEM_4K_BUF);
    for (i = 0; i < urlcnt; i++) {
	safe_free(urls[i].url);
	safe_free(urls[i].host);
    }
    safe_free(urls);
    /* mb was absorbed in httpBodySet call, so we must not clean it */
    storeUnregister(urnState->sc, urlres_e, urnState);
    storeUnlockObject(urlres_e);
    storeUnlockObject(urnState->entry);
    requestUnlink(urnState->request);
    requestUnlink(urnState->urlres_r);
    cbdataFree(urnState);
}
예제 #18
0
static void
authenticateNegotiateAuthenticateUser(auth_user_request_t * auth_user_request, request_t * request, ConnStateData * conn, http_hdr_type type)
{
    const char *proxy_auth, *blob;
    auth_user_t *auth_user;
    negotiate_request_t *negotiate_request;

    auth_user = auth_user_request->auth_user;
    assert(auth_user);
    assert(auth_user->auth_type == AUTH_NEGOTIATE);
    assert(auth_user->scheme_data != NULL);
    assert(auth_user_request->scheme_data != NULL);
    negotiate_request = auth_user_request->scheme_data;
    /* Check that we are in the client side, where we can generate
     * auth challenges */
    if (!conn) {
	negotiate_request->auth_state = AUTHENTICATE_STATE_FAILED;
	debug(29, 1) ("authenticateNegotiateAuthenticateUser: attempt to perform authentication without a connection!\n");
	return;
    }
    if (negotiate_request->waiting) {
	debug(29, 1) ("authenticateNegotiateAuthenticateUser: waiting for helper reply!\n");
	return;
    }
    if (negotiate_request->server_blob) {
	debug(29, 2) ("authenticateNegotiateAuthenticateUser: need to challenge client '%s'!\n", negotiate_request->server_blob);
	return;
    }
    /* get header */
    proxy_auth = httpHeaderGetStr(&request->header, type);
    blob = proxy_auth;
    while (xisspace(*blob) && *blob)
	blob++;
    while (!xisspace(*blob) && *blob)
	blob++;
    while (xisspace(*blob) && *blob)
	blob++;

    switch (negotiate_request->auth_state) {
    case AUTHENTICATE_STATE_NONE:
	/* we've received a negotiate request. pass to a helper */
	debug(29, 9) ("authenticateNegotiateAuthenticateUser: auth state negotiate none. %s\n", proxy_auth);
	negotiate_request->auth_state = AUTHENTICATE_STATE_INITIAL;
	safe_free(negotiate_request->client_blob);
	negotiate_request->client_blob = xstrdup(blob);
	conn->auth_type = AUTH_NEGOTIATE;
	conn->auth_user_request = auth_user_request;
	negotiate_request->conn = conn;
	/* and lock for the connection duration */
	debug(29, 9) ("authenticateNegotiateAuthenticateUser: Locking auth_user from the connection.\n");
	authenticateAuthUserRequestLock(auth_user_request);
	negotiate_request->request = requestLink(request);
	return;
	break;
    case AUTHENTICATE_STATE_INITIAL:
	debug(29, 1) ("authenticateNegotiateAuthenticateUser: need to ask helper!\n");
	return;
	break;
    case AUTHENTICATE_STATE_NEGOTIATE:
	/* we should have received a blob from the clien. pass it to the same 
	 * helper process */
	debug(29, 9) ("authenticateNegotiateAuthenticateUser: auth state challenge with header %s.\n", proxy_auth);
	/* do a cache lookup here. If it matches it's a successful negotiate 
	 * challenge - release the helper and use the existing auth_user 
	 * details. */
	safe_free(negotiate_request->client_blob);
	negotiate_request->client_blob = xstrdup(blob);
	if (negotiate_request->request)
	    requestUnlink(negotiate_request->request);
	negotiate_request->request = requestLink(request);
	return;
	break;
    case AUTHENTICATE_STATE_DONE:
	fatal("authenticateNegotiateAuthenticateUser: unexpect auth state DONE! Report a bug to the squid developers.\n");
	break;
    case AUTHENTICATE_STATE_FAILED:
	/* we've failed somewhere in authentication */
	debug(29, 9) ("authenticateNegotiateAuthenticateUser: auth state negotiate failed. %s\n", proxy_auth);
	return;
    }
    return;
}