--------------------- PatchSet 8952 Date: 2007/02/25 13:26:24 Author: adri Branch: storework Tag: (none) Log: Split the reply header/data handling a little more. * don't use httpReplySwapOut - thats deprecated. Instead, use storeReply() which sets some stuff to ensure its being called once per reply and then calls InvokeHandlers() * storeClientCopyData() callback now can be given data and or reply, with the buffer and reply flags * Start moving the client_side code around to use that instead. the client_side now onlly uses one particular callback which handles the reply status+headers and data seperately. * Rename clientSendMoreHeaderData() to clientHandleReply(); remove the code which tried to append data to the reply status+headers before writing it to the socket. We'll figure out how to combine the reply status+headers and reply body into one write for small objects later (possibly, again, by (ab)using writev()) It passes the "returns cachemgr" and "returns slashdot HTML page" test but possibly handles every other case incorrectly. Members: src/HttpReply.c:1.19.2.3->1.19.2.4 src/cache_manager.c:1.11->1.11.10.1 src/client_side.c:1.168.2.9->1.168.2.10 src/enums.h:1.59->1.59.2.1 src/forward.c:1.47->1.47.2.1 src/http.c:1.56.2.3->1.56.2.4 src/protos.h:1.133.2.5->1.133.2.6 src/store.c:1.45.2.5->1.45.2.6 src/store_client.c:1.25.2.3->1.25.2.4 src/structs.h:1.139.2.3->1.139.2.4 src/typedefs.h:1.42->1.42.2.1 Index: squid/src/HttpReply.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/HttpReply.c,v retrieving revision 1.19.2.3 retrieving revision 1.19.2.4 diff -u -r1.19.2.3 -r1.19.2.4 --- squid/src/HttpReply.c 18 Feb 2007 17:28:30 -0000 1.19.2.3 +++ squid/src/HttpReply.c 25 Feb 2007 13:26:24 -0000 1.19.2.4 @@ -1,6 +1,6 @@ /* - * $Id: HttpReply.c,v 1.19.2.3 2007/02/18 17:28:30 hno Exp $ + * $Id: HttpReply.c,v 1.19.2.4 2007/02/25 13:26:24 adri Exp $ * * DEBUG: section 58 HTTP Reply (Response) * AUTHOR: Alex Rousskov @@ -170,15 +170,7 @@ void httpReplySwapOut(HttpReply * rep, StoreEntry * e) { - assert(rep && e); - - /* We only should be packing reply headers with no object data there! */ - assert(e->mem_obj->inmem_hi == 0); - - if (rep != e->mem_obj->reply) { - httpReplyAbsorb(e->mem_obj->reply, rep); - rep = e->mem_obj->reply; - } + fatal("httpReplySwapOut: has been deprecated, use storeReply instead\n"); } HttpReply * Index: squid/src/cache_manager.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/cache_manager.c,v retrieving revision 1.11 retrieving revision 1.11.10.1 diff -u -r1.11 -r1.11.10.1 --- squid/src/cache_manager.c 25 Aug 2006 12:53:49 -0000 1.11 +++ squid/src/cache_manager.c 25 Feb 2007 13:26:24 -0000 1.11.10.1 @@ -1,6 +1,6 @@ /* - * $Id: cache_manager.c,v 1.11 2006/08/25 12:53:49 squidadm Exp $ + * $Id: cache_manager.c,v 1.11.10.1 2007/02/25 13:26:24 adri Exp $ * * DEBUG: section 16 Cache Manager Objects * AUTHOR: Duane Wessels @@ -264,7 +264,7 @@ -1, /* C-Len */ squid_curtime, /* LMT */ squid_curtime); - httpReplySwapOut(rep, entry); + storeReply(entry, rep); } a->handler(entry); storeBufferFlush(entry); Index: squid/src/client_side.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/client_side.c,v retrieving revision 1.168.2.9 retrieving revision 1.168.2.10 diff -u -r1.168.2.9 -r1.168.2.10 --- squid/src/client_side.c 23 Feb 2007 12:10:13 -0000 1.168.2.9 +++ squid/src/client_side.c 25 Feb 2007 13:26:24 -0000 1.168.2.10 @@ -1,6 +1,6 @@ /* - * $Id: client_side.c,v 1.168.2.9 2007/02/23 12:10:13 adri Exp $ + * $Id: client_side.c,v 1.168.2.10 2007/02/25 13:26:24 adri Exp $ * * DEBUG: section 33 Client-side Routines * AUTHOR: Duane Wessels @@ -132,8 +132,7 @@ static void clientFollowXForwardedForDone(int answer, void *data); #endif /* FOLLOW_X_FORWARDED_FOR */ static int clientOnlyIfCached(clientHttpRequest * http); -static STCB clientSendMoreData; -static STCB clientSendMoreHeaderData; +static void clientSendMoreData(clientHttpRequest * http, char *buf, ssize_t size); static void clientSetKeepaliveFlag(clientHttpRequest *); static void clientPackRangeHdr(const HttpReply * rep, const HttpHdrRangeSpec * spec, String boundary, MemBuf * mb); static void clientPackTermBound(String boundary, MemBuf * mb); @@ -161,6 +160,8 @@ static StoreEntry *clientCreateStoreEntry(clientHttpRequest *, method_t, request_flags); static inline int clientNatLookup(ConnStateData * conn); +static void clientHandleReply(clientHttpRequest *http, HttpReply *reply); + #if USE_IDENT static void clientIdentDone(const char *ident, void *data) @@ -377,6 +378,61 @@ EBIT_TEST(r->cache_control->mask, CC_ONLY_IF_CACHED); } +/* + * This routine forms the single way data flows from store client to the client + * side code. It can return the reply, some data, or both. For now the code + * will just treat each seperately and so the reply is handled, then the + * data. Eventually that'll change to handle both if possible. + */ +static void +clientHandleStoreReply(void *data, void *repl, char *buf, squid_off_t repl_offset, ssize_t sz, st_flags_t flags) +{ + clientHttpRequest *http = data; + StoreEntry *entry = http->entry; + ConnStateData *conn = http->conn; + int fd = conn->fd; + + /* + * Handle error/EOF in a sane way + */ + if (flags & ST_CB_ERROR) { + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + return; + } + + /* + * If we're expecting the reply header but we haven't yet parsed + * it then handle the headers. We'll stop processing here as for now + * the code will handle the headers and re-schedule another read. + */ + if ((flags & ST_CB_REPLY) && (http->reply == NULL)) { + assert(repl); + clientHandleReply(http, (HttpReply *)repl); + return; + } + + /* + * If we have data but we haven't yet received a full, valid reply then + * we error out for now. This shouldn't happen for the moment. + */ + if ((flags & ST_CB_DATA) && (sz > 0)) { + assert(http->reply); + clientSendMoreData(http, buf, sz); + return; + } + + /* + * Data EOF? I'm not sure we should check for EOF here; it was done + * at the beginning of the storeclient callbacks to see whether size=0; + * I think checking it here after the data has been sent isn't the + * "right" way but we'll see. + */ + if (flags & ST_CB_EOF) { + clientWriteComplete(fd, NULL, 0, COMM_OK, http); + return; + } +} + static StoreEntry * clientCreateStoreEntry(clientHttpRequest * h, method_t m, request_flags flags) { @@ -393,7 +449,7 @@ if (h->log_type != LOG_TCP_DENIED) delaySetStoreClient(h->sc, delayClient(h)); #endif - storeClientCopyData(h->sc, e, 0, 0, CLIENT_SOCK_SZ, h->readbuf, clientSendMoreHeaderData, h); + storeClientCopyData(h->sc, e, 0, 0, CLIENT_SOCK_SZ, h->readbuf, clientHandleStoreReply, h); return e; } @@ -1527,7 +1583,7 @@ * be. */ static HttpReply * -clientBuildReply(clientHttpRequest * http, const char *buf, size_t size) +clientBuildReply(clientHttpRequest * http, HttpReply *server_reply) { HttpReply *rep = NULL; /* If we don't have a memobj / reply by now then we're stuffed */ @@ -1536,7 +1592,7 @@ return NULL; } /* try to grab the already-parsed header */ - rep = httpReplyClone(http->sc->entry->mem_obj->reply); + rep = httpReplyClone(server_reply); if (rep->pstate == psParsed) { /* enforce 1.0 reply version */ httpBuildVersion(&rep->sline.version, 1, 0); @@ -1797,10 +1853,6 @@ typedef struct { clientHttpRequest *http; - char *buf; - ssize_t size; - const char *body_buf; - ssize_t body_size; } clientCheckHeaderStateData; CBDATA_TYPE(clientCheckHeaderStateData); @@ -1816,56 +1868,45 @@ /* * accepts chunk of a http message in buf, parses prefix, filters headers and - * such, writes processed message to the client's socket + * such, writes processed message to the client's socket. */ static void -clientSendMoreHeaderData(void *data, char *buf, ssize_t size) +clientHandleReply(clientHttpRequest *http, HttpReply *server_reply) { clientCheckHeaderStateData *state; - clientHttpRequest *http = data; StoreEntry *entry = http->entry; ConnStateData *conn = http->conn; int fd = conn->fd; HttpReply *rep = NULL; - debug(33, 5) ("clientSendMoreHeaderData: %s, %d bytes\n", http->uri, (int) size); - assert(size <= CLIENT_SOCK_SZ); + debug(33, 5) ("clientHandleReply: %s\n", http->uri); assert(http->request != NULL); dlinkDelete(&http->active, &ClientActiveRequests); dlinkAdd(http, &http->active, &ClientActiveRequests); - debug(33, 5) ("clientSendMoreHeaderData: FD %d '%s', out.offset=%ld \n", + debug(33, 5) ("clientHandleReply: FD %d '%s', out.offset=%ld \n", fd, storeUrl(entry), (long int) http->out.offset); assert(conn->reqs.head != NULL); if (DLINK_HEAD(conn->reqs) != http) { /* there is another object in progress, defer this one */ - debug(33, 2) ("clientSendMoreHeaderData: Deferring %s\n", storeUrl(entry)); + debug(33, 2) ("clientHandleReply: Deferring %s\n", storeUrl(entry)); return; } else if (http->request->flags.reset_tcp) { comm_reset_close(fd); return; - } else if (entry && EBIT_TEST(entry->flags, ENTRY_ABORTED)) { - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - return; - } else if (size < 0) { - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - return; - } else if (size == 0) { - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - return; } assert(http->out.offset == 0); - rep = http->reply = clientBuildReply(http, buf, size); + rep = http->reply = clientBuildReply(http, server_reply); if (!rep) { - fatal("clientSendMoreHeaderData: Shouldn't have happened!\n"); + /* We shouldn't be handed HTTP/0.9 replies anymore! */ + fatal("clientHandleReply: Shouldn't have happened!\n"); /* Forward as HTTP/0.9 body with no reply */ +#if 0 MemBuf mb; memBufDefInit(&mb); memBufAppend(&mb, buf, size); http->out.offset += size; comm_write_mbuf(http->conn->fd, mb, clientWriteComplete, http); return; +#endif } if (Config.onoff.log_mime_hdrs) { /* XXX this is disabled for now; should probably temporarily use the packer to put headers in */ @@ -1887,31 +1928,21 @@ errorAppendEntry(http->entry, err); return; } - /* - * At this point we might have more data in the headers than this silly 4k read. - * So lets just ignore there being any body data in this particular read - * (as eventually we won't be issuing a read just to get header data) and issue - * our next read at the point just after the reply length in rep->hdr_sz. - * Hopefully this horrible hackery will go away once the store API has changed to - * seperate entity-data and reply-data. We'll then reinstance the "grab header data - * and body data, writing them out in one swift hit" logic which I've just disabled. - * - [ahc] + /* + * We used to set range_iter.prefix_size to hdr_sz which would point to the first + * byte after headers; but headers aren't in the stream now. we also used to include + * all the remaining data from the current copy and send it along with the reply + * so it could be written in one hit - but again, thats gone now. */ - //http->range_iter.prefix_size = rep->hdr_sz; http->range_iter.prefix_size = 0; CBDATA_INIT_TYPE(clientCheckHeaderStateData); + /* + * This -state- thing can go as we've deleted buf/body_buf; we're only toying around + * with state->http now. That can go away. + */ state = cbdataAlloc(clientCheckHeaderStateData); state->http = http; cbdataLock(http); - /* XXX is this state->buf used for anything? Do we free it at all? Wha? [ahc] */ - state->buf = NULL; - state->size = 0; - state->body_buf = NULL; - state->body_size = 0; - assert(state->body_size >= 0); - /* XXX should re-instansiate the header length calculation here */ - debug(33, 3) ("clientSendMoreHeaderData: Appending %d bytes of data after headers\n", - (int) state->body_size); clientHttpLocationRewriteCheck(state); } @@ -2083,8 +2114,6 @@ //state->http->reply->hdr_sz = body_offset; /* Clean up any old body content */ httpBodyClean(&state->http->reply->body); - state->body_buf = NULL; - state->body_size = 0; /* And finally, adjust content-length to the new value */ httpHeaderDelById(&state->http->reply->header, HDR_CONTENT_LENGTH); if (content_length >= 0) { @@ -2114,11 +2143,18 @@ clientCheckHeaderDone(state); } +/* + * This is the end of the line for the header checks. + * The reply is packed into a buffer, data is appended (or will be + * appended later) and then the whole lot is written out to the client + * socket. + * + * The processing continues after clientWriteComplete() is called as a callback + * from comm_write_mbuf(). + */ static void clientCheckHeaderDone(clientCheckHeaderStateData * state) { - const char *body_buf = state->body_buf; - ssize_t body_size = state->body_size; HttpReply *rep = state->http->reply; clientHttpRequest *http = state->http; MemBuf mb; @@ -2129,7 +2165,6 @@ http->range_iter.pos = HttpHdrRangeInitPos; if (http->request->method == METHOD_HEAD) { /* do not forward body for HEAD replies */ - body_size = 0; http->flags.done_copying = 1; } /* init mb; put status line and headers */ @@ -2143,19 +2178,8 @@ #if HEADERS_LOG headersLog(0, 0, http->request->method, rep); #endif - /* append body if any */ - if (http->request->range) { - /* Only GET requests should have ranges */ - assert(http->request->method == METHOD_GET); - /* clientPackMoreRanges() updates http->out.offset */ - /* force the end of the transfer if we are done */ - if (!clientPackMoreRanges(http, body_buf, body_size, &mb)) - http->flags.done_copying = 1; - } else if (body_buf && body_size) { - http->out.offset += body_size; - memBufAppend(&mb, body_buf, body_size); - } - /* write */ + + /* write the headers */ comm_write_mbuf(http->conn->fd, mb, clientWriteComplete, http); /* clean up */ aborted: @@ -2169,9 +2193,8 @@ * such, writes processed message to the client's socket */ static void -clientSendMoreData(void *data, char *buf, ssize_t size) +clientSendMoreData(clientHttpRequest *http, char *buf, ssize_t size) { - clientHttpRequest *http = data; StoreEntry *entry = http->entry; ConnStateData *conn = http->conn; int fd = conn->fd; @@ -2184,6 +2207,8 @@ debug(33, 5) ("clientSendMoreData: FD %d '%s', out.offset=%d \n", fd, storeUrl(entry), (int) http->out.offset); assert(conn->reqs.head != NULL); + /* We won't get an error/EOF condition in the data now */ + assert(size > 0); if (DLINK_HEAD(conn->reqs) != http) { /* there is another object in progress, defer this one */ debug(33, 1) ("clientSendMoreData: Deferring %s\n", storeUrl(entry)); @@ -2192,14 +2217,6 @@ /* call clientWriteComplete so the client socket gets closed */ clientWriteComplete(fd, NULL, 0, COMM_OK, http); return; - } else if (size < 0) { - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - return; - } else if (size == 0) { - /* call clientWriteComplete so the client socket gets closed */ - clientWriteComplete(fd, NULL, 0, COMM_OK, http); - return; } if (!http->request->range) { /* Avoid copying to MemBuf for non-range requests */ @@ -2301,11 +2318,12 @@ if (0 == storeClientCopyPending(http->sc, entry, http)) { if (EBIT_TEST(entry->flags, ENTRY_ABORTED)) debug(33, 0) ("clientKeepaliveNextRequest: ENTRY_ABORTED\n"); + assert(http->out.offset == 0); storeClientCopyData(http->sc, entry, http->out.offset, http->out.offset, CLIENT_SOCK_SZ, http->readbuf, - clientSendMoreHeaderData, + clientHandleStoreReply, http); } } @@ -2328,7 +2346,7 @@ /* Did we write headers? Can we assume here we wrote them all? */ if (http->flags.written_headers == 0) { http->flags.written_headers = 1; - debug(33, 2) ("clientWriteComplete: FD: written headers; size was %d\n", fd); + debug(33, 2) ("clientWriteComplete: FD: %d: written headers; size was %d\n", fd, size); } #if SIZEOF_SQUID_OFF_T <= 4 @@ -2395,7 +2413,7 @@ http->out.offset, http->out.offset, CLIENT_SOCK_SZ, http->readbuf, - clientSendMoreData, + clientHandleStoreReply, http); } } Index: squid/src/enums.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/enums.h,v retrieving revision 1.59 retrieving revision 1.59.2.1 diff -u -r1.59 -r1.59.2.1 --- squid/src/enums.h 19 Jan 2007 01:15:52 -0000 1.59 +++ squid/src/enums.h 25 Feb 2007 13:26:31 -0000 1.59.2.1 @@ -1,6 +1,6 @@ /* - * $Id: enums.h,v 1.59 2007/01/19 01:15:52 squidadm Exp $ + * $Id: enums.h,v 1.59.2.1 2007/02/25 13:26:31 adri Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -784,4 +784,11 @@ ST_OP_CREATE } store_op_t; +typedef enum { + ST_CB_DATA = 0x1, + ST_CB_REPLY = 0x2, + ST_CB_EOF = 0x4, + ST_CB_ERROR = 0x8, +} st_flags_t; + #endif /* SQUID_ENUMS_H */ Index: squid/src/forward.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/forward.c,v retrieving revision 1.47 retrieving revision 1.47.2.1 diff -u -r1.47 -r1.47.2.1 --- squid/src/forward.c 2 Feb 2007 12:58:54 -0000 1.47 +++ squid/src/forward.c 25 Feb 2007 13:26:32 -0000 1.47.2.1 @@ -1,6 +1,6 @@ /* - * $Id: forward.c,v 1.47 2007/02/02 12:58:54 squidadm Exp $ + * $Id: forward.c,v 1.47.2.1 2007/02/25 13:26:32 adri Exp $ * * DEBUG: section 17 Request Forwarding * AUTHOR: Duane Wessels @@ -737,6 +737,7 @@ assert(e->mem_obj->chksum == url_checksum(e->mem_obj->url)); #endif debug(17, 3) ("fwdReforward: %s?\n", storeUrl(e)); + /* [ahc] is this used as a check to see whether the reply have been passed on? */ if (!EBIT_TEST(e->flags, ENTRY_FWD_HDR_WAIT)) { debug(17, 3) ("fwdReforward: No, ENTRY_FWD_HDR_WAIT isn't set\n"); return 0; Index: squid/src/http.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/http.c,v retrieving revision 1.56.2.3 retrieving revision 1.56.2.4 diff -u -r1.56.2.3 -r1.56.2.4 --- squid/src/http.c 13 Feb 2007 23:18:19 -0000 1.56.2.3 +++ squid/src/http.c 25 Feb 2007 13:26:32 -0000 1.56.2.4 @@ -1,6 +1,6 @@ /* - * $Id: http.c,v 1.56.2.3 2007/02/13 23:18:19 hno Exp $ + * $Id: http.c,v 1.56.2.4 2007/02/25 13:26:32 adri Exp $ * * DEBUG: section 11 Hypertext Transfer Protocol (HTTP) * AUTHOR: Harvest Derived @@ -405,7 +405,7 @@ /* Parse headers into reply structure */ /* what happens if we fail to parse here? */ httpReplyParse(reply, httpState->reply_hdr.buf, hdr_size); - httpReplySwapOut(reply, entry); + storeReply(entry, reply); done = hdr_size - old_size; if (reply->sline.status >= HTTP_INVALID_HEADER) { debug(11, 3) ("httpProcessReplyHeader: Non-HTTP-compliant header: '%s'\n", httpState->reply_hdr.buf); @@ -851,7 +851,7 @@ httpBuildVersion(&reply->sline.version, 1, 0); reply->sline.status = HTTP_OK; httpHeaderPutTime(&reply->header, HDR_DATE, squid_curtime); - httpReplySwapOut(reply, entry); + storeReply(entry, reply); } #if WIP_FWD_LOG fwdStatus(httpState->fwd, s); Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.133.2.5 retrieving revision 1.133.2.6 diff -u -r1.133.2.5 -r1.133.2.6 --- squid/src/protos.h 17 Feb 2007 05:21:57 -0000 1.133.2.5 +++ squid/src/protos.h 25 Feb 2007 13:26:32 -0000 1.133.2.6 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.133.2.5 2007/02/17 05:21:57 adri Exp $ + * $Id: protos.h,v 1.133.2.6 2007/02/25 13:26:32 adri Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -908,6 +908,8 @@ extern void storeInit(void); extern void storeAbort(StoreEntry *); extern void storeAppend(StoreEntry *, const char *, int); +extern void storeAppendData(StoreEntry *, const char *, int); +extern void storeReply(StoreEntry *e, HttpReply *rep); extern void storeLockObjectDebug(StoreEntry *, const char *file, const int line); extern void storeRelease(StoreEntry *); extern int storeUnlockObjectDebug(StoreEntry *, const char *file, const int line); @@ -1075,7 +1077,7 @@ */ extern store_client *storeClientRegister(StoreEntry * e, void *data); extern void storeClientCopy(store_client *, StoreEntry *, squid_off_t, squid_off_t, size_t, char *, STCB *, void *); -extern void storeClientCopyData(store_client *, StoreEntry *, squid_off_t, squid_off_t, size_t, char *, STCB *, void *); +extern void storeClientCopyData(store_client *, StoreEntry *, squid_off_t, squid_off_t, size_t, char *, ST2CB *, void *); extern int storeClientCopyPending(store_client *, StoreEntry * e, void *data); extern int storeClientUnregister(store_client * sc, StoreEntry * e, void *data); extern squid_off_t storeLowestMemReaderOffset(const StoreEntry * entry); Index: squid/src/store.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/store.c,v retrieving revision 1.45.2.5 retrieving revision 1.45.2.6 diff -u -r1.45.2.5 -r1.45.2.6 --- squid/src/store.c 15 Feb 2007 10:23:11 -0000 1.45.2.5 +++ squid/src/store.c 25 Feb 2007 13:26:33 -0000 1.45.2.6 @@ -1,6 +1,6 @@ /* - * $Id: store.c,v 1.45.2.5 2007/02/15 10:23:11 adri Exp $ + * $Id: store.c,v 1.45.2.6 2007/02/25 13:26:33 adri Exp $ * * DEBUG: section 20 Storage Manager * AUTHOR: Harvest Derived @@ -1411,3 +1411,41 @@ e->mem_obj->serverfd = -1; } +/* + * Handle the HTTP reply status+headers. + * They're all pushed in one hit to the store for the time being. + * + * "rep" is an existing reply which _must_ be e->mem_obj->reply + * for the time being; meaning that the reply must've already been + * parsed or built and associated with the mem_obj. + */ +void +storeReply(StoreEntry *e, HttpReply *rep) +{ + assert(rep && e); + + /* We only should be packing reply headers with no object data there! */ + assert(e->mem_obj->inmem_hi == 0); + + /* + * We should only be storing reply headers once; we don't currently get a second + * chance at it. This might change later on if we move towards a more event-centric + * setup where sometimes data, sometimes headers can be pushed. + */ + assert(e->mem_obj->flags.have_reply == 0); + + /* And make sure they're the same for the time being */ + assert(e->mem_obj->reply == rep); + e->mem_obj->flags.have_reply = 1; + + /* + * At this point we can schedule a callback for the store clients who are + * awaiting a HTTP reply. + * + * Yes, this means we'll have to "upgrade" InvokeHandlers() to seperate + * reply body and reply status+headers. It still thinks everything is "data" + * (and thus returns 0 byte data replies when trying to spit out the response + * headers+data.) + */ + InvokeHandlers(e); +} Index: squid/src/store_client.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/store_client.c,v retrieving revision 1.25.2.3 retrieving revision 1.25.2.4 diff -u -r1.25.2.3 -r1.25.2.4 --- squid/src/store_client.c 17 Feb 2007 06:26:56 -0000 1.25.2.3 +++ squid/src/store_client.c 25 Feb 2007 13:26:33 -0000 1.25.2.4 @@ -1,6 +1,6 @@ /* - * $Id: store_client.c,v 1.25.2.3 2007/02/17 06:26:56 adri Exp $ + * $Id: store_client.c,v 1.25.2.4 2007/02/25 13:26:33 adri Exp $ * * DEBUG: section 20 Storage Manager Client-Side Interface * AUTHOR: Duane Wessels @@ -133,15 +133,41 @@ static void storeClientCallback(store_client * sc, ssize_t sz) { - STCB *callback = sc->callback; + ST2CB *callback = sc->callback; void *cbdata = sc->callback_data; char *buf = sc->copy_buf; + st_flags_t flags = 0; + squid_off_t req_offset = sc->copy_offset; + assert(sc->callback); sc->callback = NULL; sc->callback_data = NULL; sc->copy_buf = NULL; - if (cbdataValid(cbdata)) - callback(cbdata, buf, sz); + if (cbdataValid(cbdata)) { + /* Do we have any valid data to provide? */ + if (sz > 0) + flags |= ST_CB_DATA; + + /* Do we have any valid reply to provide? */ + if (sc->entry->mem_obj->reply != NULL && sc->entry->mem_obj->reply->pstate == psParsed) + flags |= ST_CB_REPLY; + + /* Has there been an error at this point? */ + /* + * XXX [ahc] this can't be an ABORTED check as we want to feed the client what + * we have first. + */ + if (sz == -1) { + flags |= ST_CB_ERROR; + } + + /* Are we at EOF? - STORE_OK at least */ + if ((sc->entry->store_status == STORE_OK) && + (sc->copy_offset + sz >= sc->entry->mem_obj->inmem_hi)) { + flags |= ST_CB_EOF; + } + callback(cbdata, sc->entry->mem_obj->reply, buf, req_offset, sz, flags); + } cbdataUnlock(cbdata); } @@ -157,10 +183,17 @@ } /* - * Copy some data. seen_offset and copy_offset are offset into the - * data, _not_ including the reply. This routine must only be called - * once the header reply+status size is known - so it can't currently - * be called off the bat. The reply + headers must first be read in. + * Request a message "chunk". A message chunk can be one or more of + * the reply and data. We won't specifically require the caller to + * specify what they're after here - only that they're after + * something. + * + * They'll get back one or more of: + * + the reply, when its available + * + some data, if asked for + * + status/error - eg, there's an error, or there's no more + * data coming (which implies no more header information is coming + * if it hasn't been presented.) */ void storeClientCopyData(store_client *sc, @@ -169,7 +202,7 @@ squid_off_t copy_offset, size_t size, char *buf, - STCB * callback, + ST2CB * callback, void *data) { assert(!EBIT_TEST(e->flags, ENTRY_ABORTED)); Index: squid/src/structs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/structs.h,v retrieving revision 1.139.2.3 retrieving revision 1.139.2.4 diff -u -r1.139.2.3 -r1.139.2.4 --- squid/src/structs.h 14 Feb 2007 14:18:26 -0000 1.139.2.3 +++ squid/src/structs.h 25 Feb 2007 13:26:34 -0000 1.139.2.4 @@ -1,6 +1,6 @@ /* - * $Id: structs.h,v 1.139.2.3 2007/02/14 14:18:26 adri Exp $ + * $Id: structs.h,v 1.139.2.4 2007/02/25 13:26:34 adri Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -1635,7 +1635,7 @@ squid_off_t seen_offset; size_t copy_size; char *copy_buf; - STCB *callback; + ST2CB *callback; void *callback_data; StoreEntry *entry; /* ptr to the parent StoreEntry, argh! */ storeIOState *swapin_sio; @@ -1713,6 +1713,9 @@ STABH *callback; void *data; } abort; + struct { + int have_reply:1; + } flags; RemovalPolicyNode repl; int id; squid_off_t object_sz; Index: squid/src/typedefs.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/typedefs.h,v retrieving revision 1.42 retrieving revision 1.42.2.1 diff -u -r1.42 -r1.42.2.1 --- squid/src/typedefs.h 21 Jan 2007 14:04:14 -0000 1.42 +++ squid/src/typedefs.h 25 Feb 2007 13:26:34 -0000 1.42.2.1 @@ -1,6 +1,6 @@ /* - * $Id: typedefs.h,v 1.42 2007/01/21 14:04:14 squidadm Exp $ + * $Id: typedefs.h,v 1.42.2.1 2007/02/25 13:26:34 adri Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -276,6 +276,10 @@ typedef void SIH(storeIOState *, void *); /* swap in */ typedef int QS(const void *, const void *); /* qsort */ typedef void STCB(void *, char *, ssize_t); /* store callback */ + +/* new store callback - header, data, flags */ +typedef void ST2CB(void *cbdata, void *reply, char *buf, squid_off_t req_offset, ssize_t req_size, st_flags_t flags); + typedef void STABH(void *); typedef void ERCB(int fd, void *, size_t); typedef void OBJH(StoreEntry *);