Wire HTTP PUT through libneon.
CVS patchset: 7570 CVS date: 2004/11/11 00:13:38
This commit is contained in:
parent
910c42099e
commit
103a5c0e48
197
rpmio/rpmdav.c
197
rpmio/rpmdav.c
|
@ -14,6 +14,13 @@
|
|||
#include <neon/ne_basic.h>
|
||||
#include <neon/ne_dates.h>
|
||||
#include <neon/ne_locks.h>
|
||||
|
||||
#define NEONBLOWSCHUNKS
|
||||
#ifndef NEONBLOWSCHUNKS
|
||||
/* HACK: include ne_private.h to access sess->socket for now. */
|
||||
#include "../neon/src/ne_private.h"
|
||||
#endif
|
||||
|
||||
#include <neon/ne_props.h>
|
||||
#include <neon/ne_request.h>
|
||||
#include <neon/ne_socket.h>
|
||||
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue