/* * Function: errorSend * * Arguments: err - This object is destroyed after use in this function. * * Abstract: This function generates a error page from the info contained * by 'err' and then sends it to the client. * The callback function errorSendComplete() is called after * the page has been written to the client socket (fd). * errorSendComplete() deallocates 'err'. We need to add * 'err' to the cbdata because comm_write() requires it * for all callback data pointers. * * Note, normally errorSend() should only be called from * routines in ssl.c and pass.c, where we don't have any * StoreEntry's. In client_side.c we must allocate a StoreEntry * for errors and use errorAppendEntry() to account for * persistent/pipeline connections. */ void errorSend(int fd, ErrorState * err) { HttpReply *rep; debug(4, 3) ("errorSend: FD %d, err=%p\n", fd, err); assert(fd >= 0); /* * 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->err_type = err->type; /* moved in front of errorBuildBuf @?@ */ err->flags.flag_cbdata = 1; rep = errorBuildReply(err); comm_write_mbuf(fd, httpReplyPack(rep), errorSendComplete, err); httpReplyDestroy(rep); }
/* * Function: errorAppendEntry * * Arguments: err - This object is destroyed after use in this function. * * Abstract: This function generates a error page from the info contained * by 'err' and then stores the text in the specified store * entry. This function should only be called by ``server * side routines'' which need to communicate errors to the * client side. It should also be called from client_side.c * because we now support persistent connections, and * cannot assume that we can immediately write to the socket * for an error. */ void errorAppendEntry(StoreEntry * entry, ErrorState * err) { HttpReply *rep; MemObject *mem = entry->mem_obj; assert(mem != NULL); assert(mem->inmem_hi == 0); if (entry->store_status != STORE_PENDING) { /* * If the entry is not STORE_PENDING, then no clients * care about it, and we don't need to generate an * error message */ assert(EBIT_TEST(entry->flags, ENTRY_ABORTED)); assert(mem->nclients == 0); errorStateFree(err); return; } if (err->page_id == TCP_RESET) { if (err->request) { debug(4, 2) ("RSTing this reply\n"); err->request->flags.reset_tcp = 1; } } storeLockObject(entry); storeBuffer(entry); rep = errorBuildReply(err); /* Add authentication header */ /* TODO: alter errorstate to be accel on|off aware. The 0 on the next line * depends on authenticate behaviour: all schemes to date send no extra data * on 407/401 responses, and do not check the accel state on 401/407 responses */ authenticateFixHeader(rep, err->auth_user_request, err->request, 0, 1); httpReplySwapOut(rep, entry); httpReplyAbsorb(mem->reply, rep); EBIT_CLR(entry->flags, ENTRY_FWD_HDR_WAIT); storeBufferFlush(entry); storeComplete(entry); storeNegativeCache(entry); storeReleaseRequest(entry); storeUnlockObject(entry); errorStateFree(err); }
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); }