From 103a5c0e4860837984060eeb2c3d6f366993d03d Mon Sep 17 00:00:00 2001 From: jbj Date: Thu, 11 Nov 2004 00:13:38 +0000 Subject: [PATCH] Wire HTTP PUT through libneon. CVS patchset: 7570 CVS date: 2004/11/11 00:13:38 --- rpmio/rpmdav.c | 197 +++++++++++++++++++++++++++++++-------------------------- rpmio/rpmio.c | 78 ++++++++++++++++++----- 2 files changed, 170 insertions(+), 105 deletions(-) diff --git a/rpmio/rpmdav.c b/rpmio/rpmdav.c index f91b544..f53229b 100644 --- a/rpmio/rpmdav.c +++ b/rpmio/rpmdav.c @@ -14,6 +14,13 @@ #include #include #include + +#define NEONBLOWSCHUNKS +#ifndef NEONBLOWSCHUNKS +/* HACK: include ne_private.h to access sess->socket for now. */ +#include "../neon/src/ne_private.h" +#endif + #include #include #include @@ -33,7 +40,11 @@ /*@access FD_t @*/ /*@access urlinfo @*/ +#if 0 /* HACK: reasonable value needed. */ #define TIMEOUT_SECS 60 +#else +#define TIMEOUT_SECS 5 +#endif /*@unchecked@*/ static int httpTimeoutSecs = TIMEOUT_SECS; @@ -247,12 +258,50 @@ fprintf(stderr, "*** davVerifyCert(%p,%d,%p) %s\n", userdata, failures, cert, ho return 0; /* HACK: trust all server certificates. */ } +static int davConnect(urlinfo u) + /*@globals internalState @*/ + /*@modifies u, internalState @*/ +{ + const char * path = NULL; + int rc; + + /* 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: + break; + case NE_ERROR: + /* HACK: "301 Moved Permanently" on empty subdir. */ + if (!strncmp("301 ", ne_get_error(u->sess), sizeof("301 ")-1)) + break; + /*@fallthrough@*/ + case NE_CONNECT: + case NE_LOOKUP: + default: +if (_dav_debug) +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; +} + static int davInit(const char * url, urlinfo * uret) /*@globals internalState @*/ /*@modifies *uret, internalState @*/ { urlinfo u = NULL; - int xx; + int rc = 0; /*@-globs@*/ /* FIX: h_errno annoyance. */ if (urlSplit(url, &u)) @@ -266,10 +315,10 @@ static int davInit(const char * url, urlinfo * uret) /* HACK: oneshots should be done Somewhere Else Instead. */ /*@-noeffect@*/ - xx = ((_dav_debug < 0) ? NE_DBG_HTTP : 0); - ne_debug_init(stderr, xx); /* XXX oneshot? */ + rc = ((_dav_debug < 0) ? NE_DBG_HTTP : 0); + ne_debug_init(stderr, rc); /* XXX oneshot? */ /*@=noeffect@*/ - xx = ne_sock_init(); /* XXX oneshot? */ + rc = ne_sock_init(); /* XXX oneshot? */ u->capabilities = capabilities = xcalloc(1, sizeof(*capabilities)); u->sess = ne_session_create(u->scheme, u->host, u->port); @@ -306,52 +355,21 @@ static int davInit(const char * url, urlinfo * uret) ne_hook_pre_send(u->sess, davPreSend, u); ne_hook_post_send(u->sess, davPostSend, u); ne_hook_destroy_request(u->sess, davDestroyRequest, u); + + /* HACK: where should server capabilities be read? */ + rc = davConnect(u); + if (rc) + goto exit; + } +exit: /*@-boundswrite@*/ - if (uret != NULL) + if (rc == 0 && uret != NULL) *uret = urlLink(u, __FUNCTION__); /*@=boundswrite@*/ u = urlFree(u, "urlSplit (davInit)"); - return 0; -} - -static int davConnect(urlinfo u) - /*@globals internalState @*/ - /*@modifies u, internalState @*/ -{ - const char * path = NULL; - int rc; - - /* 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: - break; - case NE_ERROR: - /* HACK: "301 Moved Permanently" on empty subdir. */ - if (!strncmp("301 ", ne_get_error(u->sess), sizeof("301 ")-1)) - break; - /*@fallthrough@*/ - case NE_CONNECT: - case NE_LOOKUP: - default: -if (_dav_debug) -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; } @@ -749,11 +767,6 @@ static int davNLST(struct fetch_context_s * ctx) if (rc || u == NULL) goto exit; - /* HACK: where should server capabilities be read? */ - rc = davConnect(u); - if (rc) - goto exit; - rc = davFetch(u, ctx); switch (rc) { case NE_OK: @@ -816,8 +829,8 @@ static int my_result(const char * msg, int ret, /*@null@*/ FILE * fp) return ret; } -#ifdef DYING -static void hexdump(unsigned char * buf, ssize_t len) +#ifndef DYING +static void hexdump(const unsigned char * buf, ssize_t len) /*@*/ { int i; @@ -882,10 +895,12 @@ int davResp(urlinfo u, FD_t ctrl, /*@unused@*/ char *const * str) rc = ne_begin_request(ctrl->req); rc = my_result("ne_begin_req(ctrl->req)", rc, NULL); + if (_dav_debug < 0) fprintf(stderr, "*** davResp(%p,%p,%p) sess %p req %p rc %d\n", u, ctrl, str, u->sess, ctrl->req, rc); /* HACK: stupid error impedence matching. */ + /* HACK: NE_TIMEOUT et al here does not unravel refcnt correctly. */ switch (rc) { case NE_OK: rc = 0; break; case NE_ERROR: rc = FTPERR_SERVER_IO_ERROR; break; @@ -912,7 +927,7 @@ fprintf(stderr, "*** davResp(%p,%p,%p) sess %p req %p rc %d\n", u, ctrl, str, u- int davReq(FD_t ctrl, const char * httpCmd, const char * httpArg) { urlinfo u; - int rc; + int rc = 0; assert(ctrl != NULL); u = ctrl->url; @@ -921,23 +936,6 @@ assert(ctrl != NULL); if (_dav_debug < 0) fprintf(stderr, "*** davReq(%p,%s,\"%s\") entry sess %p req %p\n", ctrl, httpCmd, (httpArg ? httpArg : ""), u->sess, ctrl->req); - /* HACK: handle proxy host and port here. */ -#ifdef REFERENCE - if (((host = (u->proxyh ? u->proxyh : u->host)) == NULL)) - return FTPERR_BAD_HOSTNAME; - - if ((port = (u->proxyp > 0 ? u->proxyp : u->port)) < 0) port = 80; - path = (u->proxyh || u->proxyp > 0) ? u->url : httpArg; - -/*@-branchstate@*/ - if (path == NULL) path = ""; -/*@=branchstate@*/ -#endif - - /* 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)"); @@ -952,22 +950,30 @@ assert(ctrl->req != NULL); ne_add_response_header_catcher(ctrl->req, davAllHeaders, ctrl); - ne_add_response_header_handler(ctrl->req, "Accept-Ranges", - davAcceptRanges, u); ne_add_response_header_handler(ctrl->req, "Content-Length", davContentLength, ctrl); ne_add_response_header_handler(ctrl->req, "Connection", davConnection, ctrl); -#ifdef NOTYET -if (_ftp_debug) -fprintf(stderr, "-> %s", req); -#endif - - /* HACK: other errors may need retry too. */ - do { + if (!strcmp(httpCmd, "PUT")) { + ctrl->wr_chunked = 1; + ne_add_request_header(ctrl->req, "Transfer-Encoding", "chunked"); + ne_set_request_chunked(ctrl->req, 1); + /* HACK: no retries if/when chunking. */ rc = davResp(u, ctrl, NULL); - } while (rc == NE_RETRY); + } else { + /* HACK: possible Last-Modified: Tue, 02 Nov 2004 14:29:36 GMT */ + /* HACK: possible ETag: "inode-size-mtime" */ + ne_add_response_header_handler(ctrl->req, "Accept-Ranges", + davAcceptRanges, u); + /* HACK: possible Transfer-Encoding: on GET. */ + + /* HACK: other errors may need retry too. */ + /* HACK: neon retries once, gud enuf. */ + do { + rc = davResp(u, ctrl, NULL); + } while (rc == NE_RETRY); + } if (rc) goto errxit; @@ -1059,14 +1065,33 @@ hexdump(buf, rc); ssize_t davWrite(void * cookie, const char * buf, size_t count) { -#ifdef NOTYET FD_t fd = cookie; - return ne_read_response_block(fd->req, buf, count); + ssize_t rc; + int xx; + +#ifndef NEONBLOWSCHUNKS + ne_session * sess; + +assert(fd->req != NULL); + sess = ne_get_session(fd->req); +assert(sess != NULL); + + /* HACK: include ne_private.h to access sess->socket for now. */ + xx = ne_sock_fullwrite(sess->socket, buf, count); #else -if (_dav_debug < 0) -fprintf(stderr, "*** davWrite(%p,%p,0x%x)\n", cookie, buf, count); - return -1; +assert(fd->req != NULL); + xx = ne_send_request_chunk(fd->req, buf, count); #endif + + /* HACK: stupid error impedence matching. */ + rc = (xx == 0 ? count : -1); + +if (_dav_debug < 0) +fprintf(stderr, "*** davWrite(%p,%p,0x%x) rc 0x%x\n", cookie, buf, count, rc); +if (count > 0) +hexdump(buf, count); + + return rc; } int davSeek(void * cookie, /*@unused@*/ _libio_pos_t pos, int whence) @@ -1105,7 +1130,6 @@ int davMkdir(const char * path, mode_t mode) int rc; rc = davInit(path, &u); -assert(u != NULL); if (rc) goto exit; @@ -1130,7 +1154,6 @@ int davRmdir(const char * path) int rc; rc = davInit(path, &u); -assert(u != NULL); if (rc) goto exit; @@ -1157,7 +1180,6 @@ int davRename(const char * oldpath, const char * newpath) int rc; rc = davInit(oldpath, &u); -assert(u != NULL); if (rc) goto exit; @@ -1183,7 +1205,6 @@ int davUnlink(const char * path) int rc; rc = davInit(path, &u); -assert(u != NULL); if (rc) goto exit; @@ -1193,9 +1214,9 @@ assert(u != NULL); rc = ne_delete(u->sess, src); +exit: if (rc) rc = -1; /* XXX HACK: errno impedance match */ -exit: if (_dav_debug) fprintf(stderr, "*** davUnlink(%s) rc %d\n", path, rc); return rc; diff --git a/rpmio/rpmio.c b/rpmio/rpmio.c index 4d05f2f..39c4698 100644 --- a/rpmio/rpmio.c +++ b/rpmio/rpmio.c @@ -398,24 +398,47 @@ static ssize_t fdWrite(void * cookie, const char * buf, size_t count) if (fd->ndigests && count > 0) fdUpdateDigests(fd, buf, count); +#define NEONBLOWSCHUNKS +#ifdef NEONBLOWSCHUNKS + if (fd->req == NULL) +#endif if (fd->wr_chunked) { - char chunksize[20]; + char chunksize[20]; /* HACK: big enough. */ sprintf(chunksize, "%x\r\n", (unsigned)count); - rc = write(fdno, chunksize, strlen(chunksize)); +#ifndef NEONBLOWSCHUNKS + /* HACK: flimsy wiring for davWrite */ + if (fd->req != NULL) + rc = davWrite(fd, chunksize, strlen(chunksize)); + else +#endif + rc = write(fdno, chunksize, strlen(chunksize)); if (rc == -1) fd->syserrno = errno; } if (count == 0) return 0; fdstat_enter(fd, FDSTAT_WRITE); /*@-boundsread@*/ - rc = write(fdno, buf, (count > fd->bytesRemain ? fd->bytesRemain : count)); + /* HACK: flimsy wiring for davWrite */ + if (fd->req != NULL) + rc = davWrite(fd, buf, (count > fd->bytesRemain ? fd->bytesRemain : count)); + else + rc = write(fdno, buf, (count > fd->bytesRemain ? fd->bytesRemain : count)); /*@=boundsread@*/ fdstat_exit(fd, FDSTAT_WRITE, rc); +#ifdef NEONBLOWSCHUNKS + if (fd->req == NULL) +#endif if (fd->wr_chunked) { int ec; /*@-boundsread@*/ - ec = write(fdno, "\r\n", sizeof("\r\n")-1); +#ifndef NEONBLOWSCHUNKS + /* HACK: flimsy wiring for davWrite */ + if (fd->req != NULL) + ec = davWrite(fd, "\r\n", sizeof("\r\n")-1); + else +#endif + ec = write(fdno, "\r\n", sizeof("\r\n")-1); /*@=boundsread@*/ if (ec == -1) fd->syserrno = errno; } @@ -542,6 +565,7 @@ int fdWritable(FD_t fd, int secs) /*@=compdef =nullpass@*/ #endif + /* HACK: EBADF on PUT chunked termination from ufdClose. */ if (_rpmio_debug && !(rc == 1 && errno == 0)) fprintf(stderr, "*** fdWritable fdno %d rc %d %s\n", fdno, rc, strerror(errno)); if (rc < 0) { @@ -1568,17 +1592,22 @@ static int httpResp(urlinfo u, FD_t ctrl, /*@out@*/ char ** str) URLSANE(u); rc = checkResponse(u, ctrl, &ec, str); -if (_ftp_debug && !(rc == 0 && ec == 200)) +if (_ftp_debug && !(rc == 0 && (ec == 200 || ec == 201))) fprintf(stderr, "*** httpResp: rc %d ec %d\n", rc, ec); switch (ec) { case 200: + case 201: /* 201 Created. */ + break; + case 204: /* HACK: if overwriting, 204 No Content. */ + case 403: /* 403 Forbidden. */ + ctrl->syserrno = EACCES; /* HACK */ + rc = FTPERR_UNKNOWN; break; default: rc = FTPERR_FILE_NOT_FOUND; break; } - return rc; } @@ -1935,21 +1964,36 @@ 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. */ - (void) fdWrite(fd, NULL, 0); - fd->wr_chunked = 0; - /* XXX HTTP PUT requires terminating entity-header. */ + +#ifdef NEONBLOWSCHUNKS + if (!noNeon) { + fd->wr_chunked = 0; + /* HACK: flimsy wiring for davWrite */ + rc = ne_send_request_chunk(fd->req, (void *)NULL, (size_t)0); + rc = ne_finish_request(fd->req); + rc = davResp(u, fd, NULL); + } else +#endif + { + /* XXX HTTP PUT requires terminating 0 length chunk. */ + (void) fdWrite(fd, NULL, 0); + fd->wr_chunked = 0; + /* XXX HTTP PUT requires terminating entity-header. */ if (_ftp_debug) fprintf(stderr, "-> \r\n"); - (void) fdWrite(fd, "\r\n", sizeof("\r\n")-1); - /* HACK: flimsy wiring for davWrite */ - if (!strcmp(u->scheme, "https")) - rc = davResp(u, fd, NULL); - else - rc = httpResp(u, fd, NULL); + (void) fdWrite(fd, "\r\n", sizeof("\r\n")-1); +#ifndef NEONBLOWSCHUNKS + if (!noNeon) { + rc = ne_finish_request(fd->req); + rc = davResp(u, fd, NULL); + } else +#endif + rc = httpResp(u, fd, NULL); + } +if ((_ftp_debug || _rpmio_debug) && rc) /* HACK: PUT rc not returned to Fclose. */ +fprintf(stderr, "*** ufdClose: httpResp rc %d errno(%d) %s\n", rc, fd->syserrno, strerror(fd->syserrno)); } /* -- 2.7.4