From e5370f96a4c4eaa3d054d8a0e60aa8f593f5373e Mon Sep 17 00:00:00 2001 From: jbj Date: Sun, 7 Nov 2004 18:49:08 +0000 Subject: [PATCH] Drill many neon hooks. CVS patchset: 7552 CVS date: 2004/11/07 18:49:08 --- rpmio/.cvsignore | 1 + rpmio/Makefile.am | 9 +- rpmio/rpmdav.c | 303 ++++++++++++++++++++++++++++++++++++++++++++++-------- rpmio/rpmdav.h | 19 +++- rpmio/rpmio.c | 24 ++++- rpmio/rpmurl.h | 13 ++- rpmio/tfts.c | 8 +- rpmio/tget.c | 14 +-- rpmio/url.c | 5 + 9 files changed, 331 insertions(+), 65 deletions(-) diff --git a/rpmio/.cvsignore b/rpmio/.cvsignore index ea302ce..9513ed7 100644 --- a/rpmio/.cvsignore +++ b/rpmio/.cvsignore @@ -12,6 +12,7 @@ tdigest tdir tficl tfts +tget tglob tinv tkey diff --git a/rpmio/Makefile.am b/rpmio/Makefile.am index ce88050..85a9a2f 100644 --- a/rpmio/Makefile.am +++ b/rpmio/Makefile.am @@ -4,9 +4,9 @@ AUTOMAKE_OPTIONS = 1.4 foreign LINT = splint -EXTRA_DIST = tax.c tdigest.c tdir.c tficl.c tfts.c tget.c tglob.c tinv.c tkey.c trpmio.c +EXTRA_DIST = tax.c tdigest.c tdir.c tficl.c tfts.c tget.c tput.c tglob.c tinv.c tkey.c trpmio.c -EXTRA_PROGRAMS = tax tdigest tdir tfts tget tglob tinv tkey tring trpmio tsw dumpasn1 +EXTRA_PROGRAMS = tax tdigest tdir tfts tget tput tglob tinv tkey tring trpmio tsw dumpasn1 INCLUDES = -I. \ -I$(top_srcdir) \ @@ -84,6 +84,11 @@ tget_SOURCES = tget.c tget_LDFLAGS = -all-static tget_LDADD = librpmio.la $(top_builddir)/popt/libpopt.la +tput_SOURCES = tput.c +tput_LDFLAGS = -all-static +tput_LDADD = librpmio.la $(top_builddir)/popt/libpopt.la + + tglob_SOURCES = tglob.c tglob_LDFLAGS = -all-static tglob_LDADD = librpmio.la $(top_builddir)/popt/libpopt.la diff --git a/rpmio/rpmdav.c b/rpmio/rpmdav.c index 7d63131..5284dca 100644 --- a/rpmio/rpmdav.c +++ b/rpmio/rpmdav.c @@ -37,6 +37,10 @@ /*@access FD_t @*/ /*@access urlinfo @*/ +#define TIMEOUT_SECS 60 +/*@unchecked@*/ +static int httpTimeoutSecs = TIMEOUT_SECS; + /** * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL. * @param p memory to free @@ -66,14 +70,173 @@ static int davFree(urlinfo u) return 0; } +static void davProgress(void * userdata, off_t current, off_t total) +{ + urlinfo u = userdata; + ne_session * sess; + +assert(u != NULL); + sess = u->sess; +assert(sess != NULL); +assert(u == ne_get_session_private(sess, "urlinfo")); + + u->current = current; + u->total = total; + +if (_dav_debug) +fprintf(stderr, "*** davProgress(%p,0x%x:0x%x) sess %p u %p\n", userdata, (unsigned int)current, (unsigned int)total, sess, u); +} + +static void davNotify(void * userdata, + ne_conn_status connstatus, const char * info) +{ + urlinfo u = userdata; + ne_session * sess; + static const char * connstates[] = { + "namelookup", + "connecting", + "connected", + "secure", + "unknown" + }; + +assert(u != NULL); + sess = u->sess; +assert(sess != NULL); +assert(u == ne_get_session_private(sess, "urlinfo")); + +#ifdef REFERENCE +typedef enum { + ne_conn_namelookup, /* lookup up hostname (info = hostname) */ + ne_conn_connecting, /* connecting to host (info = hostname) */ + ne_conn_connected, /* connected to host (info = hostname) */ + ne_conn_secure /* connection now secure (info = crypto level) */ +} ne_conn_status; +#endif + + u->connstatus = connstatus; + +if (_dav_debug) +fprintf(stderr, "*** davNotify(%p,%d,%p) sess %p u %p %s\n", userdata, connstatus, info, sess, u, connstates[ (connstatus < 4 ? connstatus : 4)]); + +} + +static void davCreateRequest(ne_request * req, void * userdata, + const char * method, const char * uri) +{ + urlinfo u = userdata; + ne_session * sess; + void * private = NULL;; + const char * id = "urlinfo"; + +assert(u != NULL); +assert(u->sess); +assert(req != NULL); + sess = ne_get_session(req); +assert(sess == u->sess); +assert(u == ne_get_session_private(sess, "urlinfo")); + +assert(sess != NULL); + private = ne_get_session_private(sess, id); +assert(u == private); + +if (_dav_debug) +fprintf(stderr, "*** davCreateRequest(%p,%p,%s,%s) %s:%p\n", req, userdata, method, uri, id, private); +} + +static void davPreSend(ne_request * req, void * userdata, ne_buffer * buf) +{ + urlinfo u = userdata; + ne_session * sess; + const char * id = "fd"; + FD_t fd = NULL; + +assert(u != NULL); +assert(u->sess); +assert(req != NULL); + sess = ne_get_session(req); +assert(sess == u->sess); +assert(u == ne_get_session_private(sess, "urlinfo")); + + fd = ne_get_request_private(req, id); + +if (_dav_debug) { +fprintf(stderr, "*** davPreSend(%p,%p,%p) sess %p %s %p\n", req, userdata, buf, sess, id, fd); +fprintf(stderr, "-> %s\n", buf->data); +} + +} + +static int davPostSend(ne_request * req, void * userdata, const ne_status * status) +{ + urlinfo u = userdata; + ne_session * sess; + const char * id = "fd"; + FD_t fd = NULL; + +assert(u != NULL); +assert(u->sess); +assert(req != NULL); + sess = ne_get_session(req); +assert(sess == u->sess); +assert(u == ne_get_session_private(sess, "urlinfo")); + + fd = ne_get_request_private(req, id); + +if (_dav_debug) +fprintf(stderr, "*** davPostSend(%p,%p,%p) sess %p %s %p %s\n", req, userdata, status, sess, id, fd, ne_get_error(sess)); + return NE_OK; +} + +static void davDestroyRequest(ne_request * req, void * userdata) +{ + urlinfo u = userdata; + ne_session * sess; + const char * id = "fd"; + FD_t fd = NULL; + +assert(u != NULL); +assert(u->sess); +assert(req != NULL); + sess = ne_get_session(req); +assert(sess == u->sess); +assert(u == ne_get_session_private(sess, "urlinfo")); + + fd = ne_get_request_private(req, id); + +if (_dav_debug) +fprintf(stderr, "*** davDestroyRequest(%p,%p) sess %p %s %p\n", req, userdata, sess, id, fd); +} + +static void davDestroySession(void * userdata) +{ + urlinfo u = userdata; + ne_session * sess; + void * private = NULL;; + const char * id = "urlinfo"; + +assert(u != NULL); +assert(u->sess); + sess = u->sess; +assert(u == ne_get_session_private(sess, "urlinfo")); + +assert(sess != NULL); + private = ne_get_session_private(sess, id); +assert(u == private); + +if (_dav_debug) +fprintf(stderr, "*** davDestroySession(%p) sess %p %s %p\n", userdata, sess, id, private); +} + static int -trust_all_server_certs(/*@unused@*/ void *userdata, /*@unused@*/ int failures, - /*@unused@*/ const ne_ssl_certificate *cert) +davVerifyCert(void *userdata, int failures, const ne_ssl_certificate *cert) /*@*/ { -#if 0 const char *hostname = userdata; -#endif + +if (_dav_debug) +fprintf(stderr, "*** davVerifyCert(%p,%d,%p) %s\n", userdata, failures, cert, hostname); + return 0; /* HACK: trust all server certificates. */ } @@ -102,14 +265,38 @@ static int davInit(const char * url, urlinfo * uret) u->capabilities = capabilities = xcalloc(1, sizeof(*capabilities)); u->sess = ne_session_create(u->scheme, u->host, u->port); - /* XXX check that neon is ssl enabled. */ - if (!strcasecmp(u->scheme, "https")) - ne_ssl_set_verify(u->sess, trust_all_server_certs, (char *)u->host); - u->lockstore = ne_lockstore_create(); /* XXX oneshot? */ ne_lockstore_register(u->lockstore, u->sess); + if (u->proxyh != NULL) + ne_session_proxy(u->sess, u->proxyh, u->proxyp); + +#if 0 + { const ne_inet_addr ** addrs; + unsigned int n; + ne_set_addrlist(u->sess, addrs, n); + } +#endif + + ne_set_progress(u->sess, davProgress, u); + ne_set_status(u->sess, davNotify, u); + + ne_set_persist(u->sess, 1); + ne_set_read_timeout(u->sess, httpTimeoutSecs); ne_set_useragent(u->sess, PACKAGE "/" PACKAGE_VERSION); + + /* XXX check that neon is ssl enabled. */ + if (!strcasecmp(u->scheme, "https")) + ne_ssl_set_verify(u->sess, davVerifyCert, (char *)u->host); + + ne_set_session_private(u->sess, "urlinfo", u); + + ne_hook_destroy_session(u->sess, davDestroySession, u); + + ne_hook_create_request(u->sess, davCreateRequest, u); + ne_hook_pre_send(u->sess, davPreSend, u); + ne_hook_post_send(u->sess, davPostSend, u); + ne_hook_destroy_request(u->sess, davDestroyRequest, u); } if (uret != NULL) @@ -128,6 +315,7 @@ static int davConnect(urlinfo u) /* HACK: where should server capabilities be read? */ (void) urlPath(u->url, &path); + /* HACK: perhaps capture Allow: tag, look for PUT permitted. */ rc = ne_options(u->sess, path, u->capabilities); switch (rc) { case NE_OK: @@ -141,10 +329,18 @@ static int davConnect(urlinfo u) case NE_LOOKUP: default: if (_dav_debug) -fprintf(stderr, "Connect to %s:%d failed(%d):\n%s\n", +fprintf(stderr, "*** Connect to %s:%d failed(%d):\n\t%s\n", u->host, u->port, rc, ne_get_error(u->sess)); break; } + + /* HACK: sensitive to error returns? */ + u->httpVersion = (ne_version_pre_http11(u->sess) ? 0 : 1); + + /* HACK: stupid error impedence matching. */ + if (rc) + rc = FTPERR_FAILED_CONNECT; + return rc; } @@ -549,7 +745,8 @@ static int davNLST(struct fetch_context_s * ctx) break; /*@fallthrough@*/ default: -fprintf(stderr, "Fetch from %s:%d failed:\n%s\n", +if (_dav_debug) +fprintf(stderr, "*** Fetch from %s:%d failed:\n\t%s\n", u->host, u->port, ne_get_error(u->sess)); break; } @@ -613,35 +810,48 @@ static void hexdump(unsigned char * buf, ssize_t len) fprintf(stderr, "\n"); } -static void davAcceptRanges(void * userdata, const char * val) +static void davAcceptRanges(void * userdata, const char * value) { urlinfo u = userdata; + if (_dav_debug) -fprintf(stderr, "*** u %p Accept-Ranges: %s\n", u, val); - if (!strcmp(val, "bytes")) +fprintf(stderr, "*** u %p Accept-Ranges: %s\n", u, value); + if (!strcmp(value, "bytes")) u->httpHasRange = 1; - if (!strcmp(val, "none")) + if (!strcmp(value, "none")) u->httpHasRange = 0; } -static void davContentLength(void * userdata, const char * val) +static void davAllHeaders(void * userdata, const char * value) +{ + FD_t ctrl = userdata; + +if (_dav_debug) +fprintf(stderr, "<- %s\n", value); +} + +static void davContentLength(void * userdata, const char * value) { FD_t ctrl = userdata; + if (_dav_debug) -fprintf(stderr, "*** fd %p Content-Length: %s\n", ctrl, val); - ctrl->contentLength = strtoll(val, NULL, 10); +fprintf(stderr, "*** fd %p Content-Length: %s\n", ctrl, value); + ctrl->contentLength = strtoll(value, NULL, 10); } -static void davConnection(void * userdata, const char * val) +static void davConnection(void * userdata, const char * value) { FD_t ctrl = userdata; + if (_dav_debug) -fprintf(stderr, "*** fd %p Connection: %s\n", ctrl, val); - if (!strcmp(val, "close")) +fprintf(stderr, "*** fd %p Connection: %s\n", ctrl, value); + if (!strcasecmp(value, "close")) ctrl->persist = 0; + else if (!strcasecmp(value, "Keep-Alive")) + ctrl->persist = 1; } -static int davResp(urlinfo u, FD_t ctrl, /*@unused@*/ /*@out@*/ char ** str) +int davResp(urlinfo u, FD_t ctrl, /*@unused@*/ char *const * str) /*@globals fileSystem @*/ /*@modifies ctrl, *str, fileSystem @*/ { @@ -649,6 +859,8 @@ static int davResp(urlinfo u, FD_t ctrl, /*@unused@*/ /*@out@*/ char ** str) rc = ne_begin_request(ctrl->req); rc = my_result("ne_begin_req(ctrl->req)", rc, NULL); +if (_dav_debug) +fprintf(stderr, "*** davResp(%p,%p,%p) sess %p req %p rc %d\n", u, ctrl, str, u->sess, ctrl->req, rc); #ifdef NOTYET if (_ftp_debug) @@ -687,6 +899,9 @@ assert(ctrl != NULL); u = ctrl->url; URLSANE(u); +if (_dav_debug) +fprintf(stderr, "*** davReq(%p,%s,\"%s\") entry sess %p req %p\n", ctrl, httpCmd, httpArg, u->sess, ctrl->req); + /* HACK: handle proxy host and port here. */ #ifdef REFERENCE if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) @@ -702,10 +917,19 @@ assert(ctrl != NULL); /* HACK: where should server capabilities be read? */ rc = davConnect(u); + if (rc) + goto errxit; + ctrl->persist = (u->httpVersion > 0 ? 1 : 0); + ctrl = fdLink(ctrl, "open ctrl (davReq)"); assert(u->sess); assert(ctrl->req == NULL); ctrl->req = ne_request_create(u->sess, httpCmd, httpArg); +assert(ctrl->req != NULL); + + ne_set_request_private(ctrl->req, "fd", ctrl); + + ne_add_response_header_catcher(ctrl->req, davAllHeaders, ctrl); ne_add_response_header_handler(ctrl->req, "Accept-Ranges", davAcceptRanges, u); @@ -723,23 +947,21 @@ fprintf(stderr, "-> %s", req); do { rc = davResp(u, ctrl, NULL); } while (rc == NE_RETRY); + if (rc) + goto errxit; if (_dav_debug) -fprintf(stderr, "*** davReq(%p,%s,\"%s\") sess %p req %p rc %d\n", ctrl, httpCmd, httpArg, u->sess, ctrl->req, rc); +fprintf(stderr, "*** davReq(%p,%s,\"%s\") exit sess %p req %p rc %d\n", ctrl, httpCmd, httpArg, u->sess, ctrl->req, rc); - /* HACK: error path refcnts probably goofy here. */ - if (rc == 0) { - ctrl = fdLink(ctrl, "open ctrl (davReq)"); - ctrl = fdLink(ctrl, "open data (davReq)"); - } + ctrl = fdLink(ctrl, "open data (davReq)"); + return 0; + +errxit: + fdSetSyserrno(ctrl, errno, ftpStrerror(rc)); return rc; } -#define TIMEOUT_SECS 60 -/*@unchecked@*/ -static int httpTimeoutSecs = TIMEOUT_SECS; - FD_t davOpen(const char * url, /*@unused@*/ int flags, /*@unused@*/ mode_t mode, /*@out@*/ urlinfo * uret) { @@ -829,21 +1051,18 @@ fprintf(stderr, "*** davSeek(%p,pos,%d)\n", cookie, whence); int davClose(/*@only@*/ void * cookie) { FD_t fd = cookie; - ne_request * req = fd->req; - int ret; - -if (_dav_debug) -fprintf(stderr, "*** davClose(%p)\n", cookie); - ret = ne_end_request(req); - ret = my_result("ne_end_request(req)", ret, NULL); + int rc; - /* HACK: gotta figger NE_RETRY somehow. */ +assert(fd->req != NULL); + rc = ne_end_request(fd->req); + rc = my_result("ne_end_request(req)", rc, NULL); - /* HACK: also needs doing in rpmio.c */ - ne_request_destroy(req); + ne_request_destroy(fd->req); fd->req = NULL; - return ret; +if (_dav_debug) +fprintf(stderr, "*** davClose(%p) rc %d\n", fd, rc); + return rc; } /* =============================================================== */ diff --git a/rpmio/rpmdav.h b/rpmio/rpmdav.h index 0f4cfd8..c2bcef6 100644 --- a/rpmio/rpmdav.h +++ b/rpmio/rpmdav.h @@ -83,14 +83,25 @@ DIR * avOpendir(const char * path) /*@-globuse@*/ /** * Send a http request. - * @param data + * @param ctrl * @param davCmd http command - * @param davArg http command argumeny + * @param davArg http command argument * @returns 0 on success */ -int davReq(FD_t data, const char * davCmd, const char * davArg) +int davReq(FD_t ctrl, const char * davCmd, const char * davArg) /*@globals fileSystem, internalState @*/ - /*@modifies data, fileSystem, internalState @*/; + /*@modifies ctrl, fileSystem, internalState @*/; + +/** + * Read a http response. + * @param u + * @param cntl + * @retval *str error msg + * @returns 0 on success + */ +int davResp(urlinfo u, FD_t ctrl, /*@out@*/ char *const * str) + /*@globals fileSystem @*/ + /*@modifies ctrl, *str, fileSystem @*/; /** */ diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c index 4c85754..950de87 100644 --- a/rpmio/rpmio.c +++ b/rpmio/rpmio.c @@ -459,7 +459,12 @@ static int fdClose( /*@only@*/ void * cookie) fdSetFdno(fd, -1); fdstat_enter(fd, FDSTAT_CLOSE); - rc = ((fdno >= 0) ? close(fdno) : -2); + /* HACK: flimsy wiring for davClose */ + if (fd->req != NULL) { + rc = davClose(fd); +assert(fd->req == NULL); + } else + rc = ((fdno >= 0) ? close(fdno) : -2); fdstat_exit(fd, FDSTAT_CLOSE, rc); DBGIO(fd, (stderr, "==>\tfdClose(%p) rc %lx %s\n", (fd ? fd : NULL), (unsigned long)rc, fdbg(fd))); @@ -559,6 +564,10 @@ int fdReadable(FD_t fd, int secs) FD_ZERO(&rdfds); #endif + /* HACK: flimsy wiring for davRead */ + if (fd->req != NULL) + return 1; + if ((fdno = fdFileno(fd)) < 0) return -1; /* XXX W2DO? */ @@ -1724,8 +1733,6 @@ static ssize_t ufdRead(void * cookie, /*@out@*/ char * buf, size_t count) bytesRead = 0; - /* HACK: flimsy wiring for davRead */ - if (fd->req == NULL) { /* Is there data to read? */ if (fd->bytesRemain == 0) return total; /* XXX simulate EOF */ rc = fdReadable(fd, fd->rd_timeoutsecs); @@ -1738,7 +1745,6 @@ static ssize_t ufdRead(void * cookie, /*@out@*/ char * buf, size_t count) default: /* data to read */ /*@switchbreak@*/ break; } - } /*@-boundswrite@*/ rc = fdRead(fd, buf + total, count - total); @@ -1925,6 +1931,7 @@ int ufdClose( /*@only@*/ void * cookie) /* XXX Why not (u->urltype == URL_IS_HTTPS) ??? */ if (u->scheme != NULL && !strncmp(u->scheme, "http", sizeof("http")-1)) { + /* HACK: not even close for neon. */ if (fd->wr_chunked) { int rc; /* XXX HTTP PUT requires terminating 0 length chunk. */ @@ -1934,7 +1941,11 @@ int ufdClose( /*@only@*/ void * cookie) if (_ftp_debug) fprintf(stderr, "-> \r\n"); (void) fdWrite(fd, "\r\n", sizeof("\r\n")-1); - rc = httpResp(u, fd, NULL); + /* HACK: flimsy wiring for davClose */ + if (!strcmp(u->scheme, "https")) + rc = davResp(u, fd, NULL); + else + rc = httpResp(u, fd, NULL); } if (fd == u->ctrl) @@ -1965,6 +1976,9 @@ fprintf(stderr, "-> \r\n"); if (fd->persist && u->httpVersion && (fd == u->ctrl || fd == u->data) && fd->bytesRemain == 0) { fd->contentLength = fd->bytesRemain = -1; + /* HACK: flimsy wiring for davClose */ + if (!strcmp(u->scheme, "https")) + return davClose(fd); return 0; } else { fd->contentLength = fd->bytesRemain = -1; diff --git a/rpmio/rpmurl.h b/rpmio/rpmurl.h index 77ecd1a..f3881f8 100644 --- a/rpmio/rpmurl.h +++ b/rpmio/rpmurl.h @@ -57,7 +57,18 @@ struct urlinfo_s { void * lockstore; /*!< neon ne_lock_store ptr */ /*@relnull@*/ void * sess; /*!< neon ne_session ptr */ - + off_t current; /*!< neon current body offset. */ + off_t total; /*!< neon total body length. */ + int connstatus; /*!< neon connection status. */ +#ifdef REFERENCE +typedef enum { + ne_conn_namelookup, /* lookup up hostname (info = hostname) */ + ne_conn_connecting, /* connecting to host (info = hostname) */ + ne_conn_connected, /* connected to host (info = hostname) */ + ne_conn_secure /* connection now secure (info = crypto level) */ +} ne_conn_status; +#endif + int bufAlloced; /*!< sizeof I/O buffer */ /*@owned@*/ char * buf; /*!< I/O buffer */ diff --git a/rpmio/tfts.c b/rpmio/tfts.c index cea2edf..0ff43a9 100644 --- a/rpmio/tfts.c +++ b/rpmio/tfts.c @@ -12,13 +12,13 @@ static int _fts_debug = 0; #if 1 -#define HTTPPATH "https://wellfleet.jbj.org/rawhide/test/" +#define HTTPSPATH "https://wellfleet.jbj.org/rawhide/test/" #else -#define HTTPPATH "https://wellfleet.jbj.org/rawhide/" +#define HTTPSPATH "https://wellfleet.jbj.org/rawhide/" #endif #define FTPPATH "ftp://wellfleet.jbj.org/pub/rawhide/packages/test" #define DIRPATH "/var/ftp/pub/rawhide/packages/test" -static char * httppath = HTTPPATH; +static char * httpspath = HTTPSPATH; static char * ftppath = FTPPATH; static char * dirpath = DIRPATH; @@ -166,7 +166,7 @@ _dav_debug = -1; #if 0 ftsWalk(ftppath); #endif - ftsWalk(httppath); + ftsWalk(httpspath); /*@i@*/ urlFreeCache(); diff --git a/rpmio/tget.c b/rpmio/tget.c index 2badd09..7bf88c6 100644 --- a/rpmio/tget.c +++ b/rpmio/tget.c @@ -18,7 +18,7 @@ static char * httppath = HTTPPATH; static char * ftppath = FTPPATH; static char * dirpath = DIRPATH; -static void printFile(const char * path) +static void readFile(const char * path) { FD_t fd; @@ -27,11 +27,10 @@ fprintf(stderr, "===== %s\n", path); if (fd != NULL) { char buf[BUFSIZ]; size_t len = Fread(buf, 1, sizeof(buf), fd); - int xx; + int xx = Fclose(fd); if (len > 0) fwrite(buf, 1, len, stderr); - xx = Fclose(fd); } } @@ -73,11 +72,12 @@ _av_debug = -1; _ftp_debug = -1; _dav_debug = -1; #if 0 - printFile(dirpath); - printFile(ftppath); + readFile(dirpath); + readFile(ftppath); + readFile(httppath); #endif - printFile(httppath); - printFile(httpspath); + readFile(httpspath); + readFile(httpspath); /*@i@*/ urlFreeCache(); diff --git a/rpmio/url.c b/rpmio/url.c index 7dd05df..1f63b4c 100644 --- a/rpmio/url.c +++ b/rpmio/url.c @@ -143,6 +143,11 @@ URLDBGREFS(0, (stderr, "--> url %p -- %d %s at %s:%u\n", u, u->nrefs, msg, file, (u->scheme ? u->scheme : "")); /*@=usereleased@*/ } + if (u->sess != NULL) { + /* HACK: neon include has prototype. */ + ne_session_destroy(u->sess); + u->sess = NULL; + } u->buf = _free(u->buf); u->url = _free(u->url); u->scheme = _free((void *)u->scheme); -- 2.7.4