Пример #1
0
void
urnStart(request_t * r, StoreEntry * e)
{
    LOCAL_ARRAY(char, urlres, 4096);
    request_t *urlres_r = NULL;
    const char *t;
    char *host;
    UrnState *urnState;
    StoreEntry *urlres_e;
    ErrorState *err;
    debug(52, 3) ("urnStart: '%s'\n", storeUrl(e));
    CBDATA_INIT_TYPE(UrnState);
    urnState = cbdataAlloc(UrnState);
    urnState->entry = e;
    urnState->request = requestLink(r);
    storeLockObject(urnState->entry);
    if (strncasecmp(strBuf(r->urlpath), "menu.", 5) == 0) {
	char *new_path = xstrdup(strBuf(r->urlpath) + 5);
	urnState->flags.force_menu = 1;
	stringReset(&r->urlpath, new_path);
	xfree(new_path);
    }
    if ((t = strChr(r->urlpath, ':')) != NULL) {
	strSet(r->urlpath, t, '\0');
	host = xstrdup(strBuf(r->urlpath));
	strSet(r->urlpath, t, ':');
    } else {
	host = xstrdup(strBuf(r->urlpath));
    }
    snprintf(urlres, 4096, "http://%s/uri-res/N2L?urn:%s", host, strBuf(r->urlpath));
    safe_free(host);
    urlres_r = urlParse(METHOD_GET, urlres);
    if (urlres_r == NULL) {
	debug(52, 3) ("urnStart: Bad uri-res URL %s\n", urlres);
	err = errorCon(ERR_URN_RESOLVE, HTTP_NOT_FOUND);
	err->url = xstrdup(urlres);
	errorAppendEntry(e, err);
	return;
    }
    httpHeaderPutStr(&urlres_r->header, HDR_ACCEPT, "text/plain");
    if ((urlres_e = storeGetPublic(urlres, METHOD_GET)) == NULL) {
	urlres_e = storeCreateEntry(urlres, urlres, null_request_flags, METHOD_GET);
	urnState->sc = storeClientListAdd(urlres_e, urnState);
	fwdStart(-1, urlres_e, urlres_r);
    } else {
	storeLockObject(urlres_e);
	urnState->sc = storeClientListAdd(urlres_e, urnState);
    }
    urnState->urlres_e = urlres_e;
    urnState->urlres_r = requestLink(urlres_r);
    storeClientCopy(urnState->sc, urlres_e,
	0,
	0,
	4096,
	memAllocate(MEM_4K_BUF),
	urnHandleReply,
	urnState);
}
Пример #2
0
/*
 * copied from httpReadReply()
 *
 * by the time this is called, the ICAP headers have already
 * been read.
 */
void
icapReadReply(int fd, void *data)
{
    IcapStateData *icap = data;
    StoreEntry *entry = icap->respmod.entry;
    const request_t *request = icap->request;
    int len;
    debug(81, 5) ("icapReadReply: FD %d: icap %p.\n", fd, data);
    if (icap->flags.no_content && !icap->flags.http_server_eof) {	//AI

	return;
    }
    if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
	comm_close(fd);
	return;
    }
    errno = 0;
    statCounter.syscalls.sock.reads++;
    len = memBufRead(fd, &icap->chunk_buf);
    debug(81, 5) ("icapReadReply: FD %d: len %d.\n", fd, len);
    if (len > 0) {
	fd_bytes(fd, len, FD_READ);
	kb_incr(&statCounter.icap.all.kbytes_in, len);
	commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
	if (icap->chunk_buf.size < icap->chunk_buf.capacity) {
	    *(icap->chunk_buf.buf + icap->chunk_buf.size) = '\0';
	    debug(81, 9) ("{%s}\n", icap->chunk_buf.buf);
	}
    }
    if (len <= 0) {
	debug(81, 2) ("icapReadReply: FD %d: read failure: %s.\n",
	    fd, xstrerror());
	if (ignoreErrno(errno)) {
	    debug(81, 2) ("icapReadReply: FD %d: ignored errno\n", fd);
	    commSetSelect(fd, COMM_SELECT_READ, icapReadReply, icap, 0);
	} else if (entry->mem_obj->inmem_hi == 0) {
	    ErrorState *err;
	    debug(81, 2) ("icapReadReply: FD %d: generating error page\n", fd);
	    err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	    err->request = requestLink((request_t *) request);
	    err->xerrno = errno;
	    errorAppendEntry(entry, err);
	    comm_close(fd);
	} else {
	    debug(81, 2) ("icapReadReply: FD %d: just calling comm_close()\n",
		fd);
	    comm_close(fd);
	}
	return;
    }
    if (icapReadReply2(icap) < 0)
	comm_close(fd);
}
Пример #3
0
void
icapConnectOver(int fd, int status, void *data)
{
    ErrorState *err;
    IcapStateData *icap = data;
    debug(81, 3) ("icapConnectOver: FD %d, status=%d\n", fd, status);
    icap->flags.connect_pending = 0;
    if (status < 0) {
	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	err->xerrno = errno;
	err->request = requestLink(icap->request);
	errorAppendEntry(icap->respmod.entry, err);
	comm_close(fd);
	debug(81, 3) ("icapConnectOver: status < 0, unreachable=1\n");
	icapOptSetUnreachable(icap->current_service);
	return;
    }
    commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
}
Пример #4
0
void
cachemgrStart(int fd, request_t * request, StoreEntry * entry)
{
    cachemgrStateData *mgr = NULL;
    ErrorState *err = NULL;
    action_table *a;
    debug(16, 3) ("cachemgrStart: '%s'\n", storeUrl(entry));
    if ((mgr = cachemgrParseUrl(storeUrl(entry))) == NULL) {
	err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND, request);
	err->url = xstrdup(storeUrl(entry));
	errorAppendEntry(entry, err);
	entry->expires = squid_curtime;
	return;
    }
    mgr->entry = entry;
    storeLockObject(entry);
    entry->expires = squid_curtime;
    debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
	fd_table[fd].ipaddr, mgr->action);
    /* get additional info from request headers */
    cachemgrParseHeaders(mgr, request);
    /* Check password */
    if (cachemgrCheckPassword(mgr) != 0) {
	/* build error message */
	ErrorState *err;
	HttpReply *rep;
	err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED, request);
	/* warn if user specified incorrect password */
	if (mgr->passwd)
	    debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
		mgr->user_name ? mgr->user_name : "<unknown>",
		fd_table[fd].ipaddr, mgr->action);
	else
	    debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
		mgr->user_name ? mgr->user_name : "<unknown>",
		fd_table[fd].ipaddr, mgr->action);
	rep = errorBuildReply(err);
	errorStateFree(err);
	/*
	 * add Authenticate header, use 'action' as a realm because
	 * password depends on action
	 */
	httpHeaderPutAuth(&rep->header, "Basic", mgr->action);
	/* store the reply */
	httpReplySwapOut(rep, entry);
	entry->expires = squid_curtime;
	storeComplete(entry);
	cachemgrStateFree(mgr);
	return;
    }
    debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
	mgr->user_name ? mgr->user_name : "<unknown>",
	fd_table[fd].ipaddr, mgr->action);
    /* retrieve object requested */
    a = cachemgrFindAction(mgr->action);
    assert(a != NULL);
    storeBuffer(entry);
    {
	HttpReply *rep = entry->mem_obj->reply;
	/* prove there are no previous reply headers around */
	assert(0 == rep->sline.status);
	httpReplySetHeaders(rep, HTTP_OK, NULL, "text/plain", -1, -1, squid_curtime);
	httpReplySwapOut(rep, entry);
    }
    a->handler(entry);
    storeBufferFlush(entry);
    if (a->flags.atomic)
	storeComplete(entry);
    cachemgrStateFree(mgr);
}
Пример #5
0
static int
icapReadReply2(IcapStateData * icap)
{
    StoreEntry *entry = icap->respmod.entry;
    const request_t *request = icap->request;
    debug(81, 3) ("icapReadReply2\n");
    if (icap->chunk_buf.size == 0 && entry->mem_obj->inmem_hi == 0) {
	ErrorState *err;
	err = errorCon(ERR_ZERO_SIZE_OBJECT, HTTP_SERVICE_UNAVAILABLE);
	err->xerrno = errno;
	err->request = requestLink((request_t *) request);
	errorAppendEntry(entry, err);
	icap->flags.http_server_eof = 1;
	return -1;
    }
    if (icap->chunk_buf.size == 0) {
	/* Retrieval done. */
	if (icapHttpReplyHdrState(icap) < 2)
	    icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
		icap->chunk_buf.size);
	icap->flags.http_server_eof = 1;
	icapReadReply3(icap);
	return 0;
    }
    if (icapHttpReplyHdrState(icap) == 0) {
	int expect = icapExpectedHttpReplyHdrSize(icap);
	int so_far = icap->http_header_bytes_read_so_far;
	int needed = expect - so_far;
	debug(81, 3) ("expect=%d\n", expect);
	debug(81, 3) ("so_far=%d\n", so_far);
	debug(81, 3) ("needed=%d\n", needed);
	assert(needed < 0 || needed >= 0);
	if (0 > expect) {
	    icapProcessHttpReplyHeader(icap,
		icap->chunk_buf.buf, icap->chunk_buf.size);
	} else if (0 == expect) {
	    /*
	     * this icap reply doesn't give us new HTTP headers
	     * so we must copy them from our copy
	     */
	    debug(81, 1) ("WARNING: untested code at %s:%d\n", __FILE__,
		__LINE__);
	    if(icap->respmod.req_hdr_copy.size){/*For HTTP 0.9 we do not have headers*/
		 storeAppend(entry,
			     icap->respmod.req_hdr_copy.buf,
			     icap->respmod.req_hdr_copy.size);
	    }
	    icapProcessHttpReplyHeader(icap, icap->chunk_buf.buf,
				       icap->chunk_buf.size);
	    assert(icapHttpReplyHdrState(icap) == 2);
	    icap->chunk_size = 0;/*we are ready to read chunks of data now....*/
	} else if (needed) {
	    icapProcessHttpReplyHeader(icap,
		icap->chunk_buf.buf, icap->chunk_buf.size);
	    if (icap->chunk_buf.size >= needed) {
		storeAppend(entry, icap->chunk_buf.buf, needed);
		so_far += needed;
		xmemmove(icap->chunk_buf.buf,
		    icap->chunk_buf.buf + needed,
		    icap->chunk_buf.size - needed);
		icap->chunk_buf.size -= needed;
		assert(icapHttpReplyHdrState(icap) == 2);
		icap->chunk_size = 0;
	    } else {
		/*
		 * We don't have the full HTTP reply headers yet, so keep
		 * the partial reply buffered in 'chunk_buf' and wait
		 * for more.
		 */
                debug(81,3)("We don't have full Http headers.Schedule a new read\n");
  		commSetSelect(icap->icap_fd, COMM_SELECT_READ, icapReadReply, icap, 0);
	    }
	}
	icap->http_header_bytes_read_so_far = so_far;
    }
    debug(81, 3) ("%s:%d: icap->chunk_buf.size=%d\n", __FILE__, __LINE__,
	(int) icap->chunk_buf.size);
    debug(81, 3) ("%s:%d: flags.no_content=%d\n", __FILE__, __LINE__,
	icap->flags.no_content);
    if (icap->flags.no_content) {
	/* data from http.c is not chunked */
	if (!EBIT_TEST(entry->flags, ENTRY_ABORTED)) {
	    debug(81, 3) ("copying %d bytes from chunk_buf to entry\n",
		icap->chunk_buf.size);
	    storeAppend(entry, icap->chunk_buf.buf, icap->chunk_buf.size);
	    icap->chunk_buf.size = 0;
	}
    } else if (2 == icapHttpReplyHdrState(icap)) {
	if (icap->chunk_buf.size)
	    icapParseChunkedBody(icap, (STRCB *) storeAppend, entry);
    }
    icapReadReply3(icap);
    return 0;
}
Пример #6
0
static void
icapSendRespModDone(int fd, char *bufnotused, size_t size, int errflag,
    void *data)
{
    IcapStateData *icap = data;
    ErrorState *err;

    icap->flags.write_pending = 0;
    debug(81, 5) ("icapSendRespModDone: FD %d: size %d: errflag %d.\n",
	fd, size, errflag);
    if (size > 0) {
	fd_bytes(fd, size, FD_WRITE);
	kb_incr(&statCounter.icap.all.kbytes_out, size);
    }
    if (errflag == COMM_ERR_CLOSING)
	return;
    if (errflag) {
	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	err->xerrno = errno;
	if (cbdataValid(icap))
	    err->request = requestLink(icap->request);
	storeEntryReset(icap->respmod.entry);
	errorAppendEntry(icap->respmod.entry, err);
	comm_close(fd);
	return;
    }
    if (EBIT_TEST(icap->respmod.entry->flags, ENTRY_ABORTED)) {
        debug(81, 3) ("icapSendRespModDone: Entry Aborded\n");	
	comm_close(fd);
	return;
    }
    if (icap->flags.send_zero_chunk) {
	debug(81,
	    3) ("icapSendRespModDone: I'm supposed to send zero chunk now\n");
	icap->flags.send_zero_chunk = 0;
	icapSendRespMod(icap, NULL, 0, 1);
	return;
    }
    if (icap->flags.wait_for_preview_reply || icap->flags.wait_for_reply) {
	/* Schedule reading the ICAP response */
	debug(81,
	    3)
	    ("icapSendRespModDone: FD %d: commSetSelect on read icapRespModReadReply.\n",
	    fd);
	commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
#if 1
	commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
#else
	if (icap->flags.wait_for_preview_reply || icap->flags.http_server_eof) {
	    /*
	     * Set the read timeout only after all data has been sent
	     * or we are waiting for a preview response
	     * If the ICAP server does not return any data till all data
	     * has been sent, we are likely to hit the timeout for large
	     * HTTP bodies
	     */
	    commSetTimeout(fd, Config.Timeout.read, icapReadTimeout, icap);
	}
#endif
    }
}
Пример #7
0
static void
icapRespModReadReply(int fd, void *data)
{
    IcapStateData *icap = data;
    int version_major, version_minor;
    const char *str_status;
    int x;
    int status = 0;
    int isIcap = 0;
    int directResponse = 0;
    ErrorState *err;
    const char *start;
    const char *end;

    debug(81, 5) ("icapRespModReadReply: FD %d data = %p\n", fd, data);
    statCounter.syscalls.sock.reads++;

    x = icapReadHeader(fd, icap, &isIcap);
    if (x < 0) {
	/* Did not find a proper ICAP response */
	debug(81, 3) ("ICAP : Error path!\n");
	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	err->request = requestLink(icap->request);
	err->xerrno = errno;
	errorAppendEntry(icap->respmod.entry, err);
	comm_close(fd);
	return;
    }
    if (x == 0) {
	/*
	 * Waiting for more headers.  Schedule new read hander, but
	 * don't reset timeout.
	 */
	commSetSelect(fd, COMM_SELECT_READ, icapRespModReadReply, icap, 0);
	return;
    }
    /*
     * Parse the ICAP header
     */
    assert(icap->icap_hdr.size);
    debug(81, 3) ("Parse icap header : <%s>\n", icap->icap_hdr.buf);
    if ((status =
	    icapParseStatusLine(icap->icap_hdr.buf, icap->icap_hdr.size,
		&version_major, &version_minor, &str_status)) < 0) {
	debug(81, 1) ("BAD ICAP status line <%s>\n", icap->icap_hdr.buf);
	/* is this correct in case of ICAP protocol error? */
	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	err->request = requestLink(icap->request);
	err->xerrno = errno;
	errorAppendEntry(icap->respmod.entry, err);
	comm_close(fd);
	return;
    };
    /*  OK here we have responce. Lets stop filling the 
     *  icap->respmod.resp_copy buffer ....
     */
    icap->flags.copy_response = 0;

    icapSetKeepAlive(icap, icap->icap_hdr.buf);
#if ICAP_PREVIEW
    if (icap->flags.wait_for_preview_reply) {
	if (100 == status) {
	    debug(81, 5) ("icapRespModReadReply: 100 Continue received\n");
	    icap->flags.wait_for_preview_reply = 0;
	    /* if http_server_eof
	     * call again icapSendRespMod to handle data that
	     * was received while waiting for this ICAP response
	     * else let http to call icapSendRespMod when new data arrived
	     */
	    if (icap->flags.http_server_eof)
		icapSendRespMod(icap, NULL, 0, 0);
	    /*
	     * reset the header to send the rest of the preview
	     */
	    if (!memBufIsNull(&icap->icap_hdr))
		memBufReset(&icap->icap_hdr);

	    /*We do n't need it any more .......*/
	    if (!memBufIsNull(&icap->respmod.resp_copy))
		 memBufClean(&icap->respmod.resp_copy);

	    return;
	}
	if (204 == status) {
	    debug(81,
		5) ("icapRespModReadReply: 204 No modification received\n");
	    icap->flags.wait_for_preview_reply = 0;
	}
    }
#endif /*ICAP_PREVIEW */

#if SUPPORT_ICAP_204 || ICAP_PREVIEW
    if (204 == status) {
	debug(81, 3) ("got 204 status from ICAP server\n");
	debug(81, 3) ("setting icap->flags.no_content\n");
	icap->flags.no_content = 1;
	/*
	 * copy the response already written to the ICAP server
	 */
	debug(81, 3) ("copying %d bytes from resp_copy to chunk_buf\n",
	    icap->respmod.resp_copy.size);
	memBufAppend(&icap->chunk_buf,
	    icap->respmod.resp_copy.buf, icap->respmod.resp_copy.size);
	icap->respmod.resp_copy.size = 0;
	if (icapReadReply2(icap) < 0)
	    comm_close(fd);
	/*
	 * XXX ideally want to clean icap->respmod.resp_copy here
	 * XXX ideally want to "close" ICAP server connection here
	 * OK do it....
	 */
	if (!memBufIsNull(&icap->respmod.resp_copy))
	     memBufClean(&icap->respmod.resp_copy);
	return;
    }
#endif
    if (200 != status) {
	debug(81, 1) ("Unsupported status '%d' from ICAP server\n", status);
	/* Did not find a proper ICAP response */
	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	err->request = requestLink(icap->request);
	err->xerrno = errno;
	errorAppendEntry(icap->respmod.entry, err);
	comm_close(fd);
	return;
    }
    if (icapFindHeader(icap->icap_hdr.buf, "Encapsulated:", &start, &end)) {
	icapParseEncapsulated(icap, start, end);
    } else {
	debug(81,
	    1)
	    ("WARNING: icapRespModReadReply() did not find 'Encapsulated' header\n");
    }
    if (icap->enc.res_hdr > -1)
	directResponse = 1;
    else if (icap->enc.res_body > -1)
	directResponse = 1;
    else
	directResponse = 0;

    /*
     * "directResponse" is the normal case here.  If we don't have
     * a response header or body, it is an error.
     */
    if (!directResponse) {
	/* Did not find a proper ICAP response */
	debug(81, 3) ("ICAP : Error path!\n");
	err = errorCon(ERR_ICAP_FAILURE, HTTP_INTERNAL_SERVER_ERROR);
	err->request = requestLink(icap->request);
	err->xerrno = errno;
	errorAppendEntry(icap->respmod.entry, err);
	comm_close(fd);
	return;
    }
    /* got the reply, no need to come here again */
    icap->flags.wait_for_reply = 0;
    icap->flags.got_reply = 1;
    /* Next, gobble any data before the HTTP response starts */
    if (icap->enc.res_hdr > -1)
	icap->bytes_to_gobble = icap->enc.res_hdr;
    commSetSelect(fd, COMM_SELECT_READ, icapRespModGobble, icap, 0);
}
Пример #8
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);
}
static int process_miss_in_error_page(clientHttpRequest* http ,int *ret)
{
    debug(115, 4)("mod_customized_server_side_error_page process_miss_in_error_page\n");
	int fd = http->conn->fd;
	if(fd_table[fd].cc_run_state[mod->slot]>0)
	{
		mod_config* cfg = cc_get_mod_param(fd,mod);
		if(squid_curtime < cfg->error_page_expires )
		{
			ErrorState* err = NULL;
			/**********************************/
			err_type page_id;
            int status = cfg->ResponseStatus;
            
            // add by xueye.zhao
            // 2013-4-18

            if (is_http_move_status(status))
            {
                HttpReply *rep = httpReplyCreate();
                http->entry = clientCreateStoreEntry(http, http->request->method, http->request->flags);
                http->log_type = LOG_TCP_HIT;
                storeReleaseRequest(http->entry);
                httpRedirectReply(rep, cfg->ResponseStatus, cfg->location);
                httpReplySwapOut(rep, http->entry);
                storeComplete(http->entry);

                *ret = 1;
                return *ret;
            }

            //end add

			switch(status)
			{
				case HTTP_BAD_REQUEST:
				case HTTP_LENGTH_REQUIRED:
				case HTTP_EXPECTATION_FAILED:
					page_id = ERR_INVALID_REQ;
					break;
				case HTTP_UNAUTHORIZED:
				case HTTP_FORBIDDEN:
				case HTTP_METHOD_NOT_ALLOWED:
				case HTTP_NOT_ACCEPTABLE:
				case HTTP_PROXY_AUTHENTICATION_REQUIRED:
				case HTTP_REQUEST_TIMEOUT:
				case HTTP_CONFLICT:
				case HTTP_GONE:
				case HTTP_PRECONDITION_FAILED:
				case HTTP_UNSUPPORTED_MEDIA_TYPE:
				case HTTP_UNPROCESSABLE_ENTITY:
				case HTTP_LOCKED:
				case HTTP_FAILED_DEPENDENCY:
					page_id = ERR_ACCESS_DENIED;
					break;
				case HTTP_NOT_FOUND :
					page_id = ERR_FTP_NOT_FOUND;
					break;
				case HTTP_REQUEST_ENTITY_TOO_LARGE:
				case HTTP_REQUEST_URI_TOO_LONG:
					page_id = ERR_TOO_BIG;
					break;
				case HTTP_INTERNAL_SERVER_ERROR:
					page_id= ERR_SOCKET_FAILURE;
					break;
				case HTTP_NOT_IMPLEMENTED:
					page_id = ERR_UNSUP_REQ;
					break;
				case HTTP_BAD_GATEWAY:
				case HTTP_GATEWAY_TIMEOUT:
					page_id = ERR_CONNECT_FAIL;
					break;
				case HTTP_SERVICE_UNAVAILABLE:
					page_id = ERR_FTP_UNAVAILABLE;
					break;
				default:
					page_id = ERR_HTTP_SPECIAL;
			}
			/**********************************/
			debug(115, 5)("mod_customized_server_side_error_page: cc_error_page running, don't back source server\n");
			http->al.http.code = HTTP_FORBIDDEN;
			err = errorCon(page_id, cfg->ResponseStatus,http->request);
//			err->request = requestLink(http->request);
			err->src_addr = http->conn->peer.sin_addr;
			http->log_type = LOG_TCP_DENIED;
			http->entry = clientCreateStoreEntry(http, http->request->method, null_request_flags);
			errorAppendEntry(http->entry, err);
			*ret =1;
		}
	}
	return *ret;
		
}
/*handle errorEntry here*/
static int repl_send_start(clientHttpRequest *http, int *ret)
{
    debug(115, 4)("mod_customized_server_side_error_page repl_send_start\n");
	int fd= http->conn->fd;
	mod_config* cfg = cc_get_mod_param(fd,mod);
	//mod_config *cfg = ((mod_config*)(param->param));
	if(fd_table[fd].cc_run_state[mod->slot]>0)
	{
		error_page_private_data* pd = (error_page_private_data*) cc_get_mod_private_data(REQUEST_PRIVATE_DATA,http,mod);

		if(pd->OfflineTimeToLive > 0&& pd->recusive_time<2 && pd->recusive_time > 0 && cfg->customized_error_text.buf != NULL/* && pd->ResponseStatus <400 */)
		{
			debug(115,4)("customized_server_side_error_page: repl_send_start the recusive_time is: %d\n",pd->recusive_time);
			ErrorState *err;
			err_type page_id;
			int status = pd->ResponseStatus;
			switch(status)
			{
				case HTTP_BAD_REQUEST:
				case HTTP_LENGTH_REQUIRED:
				case HTTP_EXPECTATION_FAILED:
					page_id = ERR_INVALID_REQ;
					break;
				case HTTP_UNAUTHORIZED:
				case HTTP_FORBIDDEN:
				case HTTP_METHOD_NOT_ALLOWED:
				case HTTP_NOT_ACCEPTABLE:
				case HTTP_PROXY_AUTHENTICATION_REQUIRED:
				case HTTP_REQUEST_TIMEOUT:
				case HTTP_CONFLICT:
				case HTTP_GONE:
				case HTTP_PRECONDITION_FAILED:
				case HTTP_UNSUPPORTED_MEDIA_TYPE:
				case HTTP_UNPROCESSABLE_ENTITY:
				case HTTP_LOCKED:
				case HTTP_FAILED_DEPENDENCY:
					page_id = ERR_ACCESS_DENIED;
					break;
				case HTTP_NOT_FOUND :
					page_id = ERR_FTP_NOT_FOUND;
					break;
				case HTTP_REQUEST_ENTITY_TOO_LARGE:
				case HTTP_REQUEST_URI_TOO_LONG:
					page_id = ERR_TOO_BIG;
					break;
				case HTTP_INTERNAL_SERVER_ERROR:
					page_id= ERR_SOCKET_FAILURE;
					break;
				case HTTP_NOT_IMPLEMENTED:
					page_id = ERR_UNSUP_REQ;
					break;
				case HTTP_BAD_GATEWAY:
				case HTTP_GATEWAY_TIMEOUT:
					page_id = ERR_CONNECT_FAIL;
					break;
				case HTTP_SERVICE_UNAVAILABLE:
					page_id = ERR_FTP_UNAVAILABLE;
					break;
				default:
					page_id = ERR_HTTP_SPECIAL;
			}
			//	err = errorCon(page_id,


			err = errorCon(page_id,pd->ResponseStatus,http->request);

			/********************may be leak here**********************************/

			assert(err!=NULL);
			if(squid_curtime > cfg->error_page_expires)
				cfg->error_page_expires = squid_curtime + pd->OfflineTimeToLive;
			//err->request = requestLink(http->request);
			storeClientUnregister(http->sc,http->entry,http);
			http->sc = NULL;
			storeUnlockObject(http->entry);
			http->log_type = LOG_TCP_HIT;
			http->entry = clientCreateStoreEntry(http,http->request->method,null_request_flags);

			debug(115,4)("mod_customized_server_side_error_page repl_send_start: before errorAppendEntry, the err->page_id is: %d, the err->http_status is: %d , the err->type is: %d \n",err->page_id, err->http_status,err->type);
			errorAppendEntry(http->entry,err);
			/********************may be leak here**********************************/
			*ret = 1;

		}

        // add by xueye.zhao
        // 2013-4-18
        else if (pd->OfflineTimeToLive > 0&& pd->recusive_time<2 && pd->recusive_time > 0)
        {
            if(squid_curtime > cfg->error_page_expires)
                cfg->error_page_expires = squid_curtime + pd->OfflineTimeToLive;

            HttpReply *rep = httpReplyCreate();
            http->entry = clientCreateStoreEntry(http, http->request->method, http->request->flags);
            http->log_type = LOG_TCP_MISS;
            storeReleaseRequest(http->entry);
            httpRedirectReply(rep, cfg->ResponseStatus, cfg->location);
            httpReplySwapOut(rep, http->entry);
            storeComplete(http->entry);
            *ret = 1;

            return *ret; 
        }
        // end add
    }
	return *ret;	
}