From e41f2b74c53d9d97b51dfc1d20aa201e4b2c9201 Mon Sep 17 00:00:00 2001 From: Daniel Veillard Date: Sun, 30 Jan 2000 20:00:07 +0000 Subject: [PATCH] Released 1.8.6, Daniel. --- ChangeLog | 11 + configure.in | 2 +- doc/html/gnome-xml-debugxml.html | 38 +- doc/html/gnome-xml-encoding.html | 32 +- doc/html/gnome-xml-entities.html | 56 +-- doc/html/gnome-xml-htmlparser.html | 62 +-- doc/html/gnome-xml-htmltree.html | 20 +- doc/html/gnome-xml-nanoftp.html | 417 ++++++++++++++++-- doc/html/gnome-xml-nanohttp.html | 152 ++++++- doc/html/gnome-xml-parserinternals.html | 182 ++++---- doc/html/gnome-xml-tree.html | 306 ++++++++------ doc/html/gnome-xml-valid.html | 140 +++--- doc/html/gnome-xml-xml-error.html | 22 +- doc/html/gnome-xml-xmlio.html | 30 +- doc/html/gnome-xml-xmlmemory.html | 40 +- doc/html/gnome-xml-xpath.html | 76 ++-- doc/html/index.sgml | 8 + doc/xml.html | 10 +- include/libxml/nanoftp.h | 27 +- include/libxml/nanohttp.h | 3 + include/libxml/tree.h | 1 + nanoftp.c | 538 +++++++++++++++++++++--- nanoftp.h | 27 +- nanohttp.c | 177 +++++++- nanohttp.h | 3 + tree.c | 4 +- tree.h | 1 + 27 files changed, 1789 insertions(+), 596 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2d5603bf..a1c6a7c1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +Mon Jan 31 14:25:57 CET 2000 Daniel Veillard + + * nanoftp.[ch]: cleanup, bug fixes, integration in rpmfind, added + xmlNanoFTPUpdateURL for persistent control connections. + * configure.in: 1.8.6 + +Thu Jan 27 17:52:29 CET 2000 Daniel Veillard + + * nanohttp.[ch], nanoftp.[ch]: cleanup, added proxy support + * tree.[ch] : added xmlSaveNoEmptyTags + 2000-01-29 James Henstridge * nanoftp.c: include for IPPROTO_TCP. diff --git a/configure.in b/configure.in index e3b5844e..3665b54a 100644 --- a/configure.in +++ b/configure.in @@ -5,7 +5,7 @@ AM_CONFIG_HEADER(config.h) LIBXML_MAJOR_VERSION=1 LIBXML_MINOR_VERSION=8 -LIBXML_MICRO_VERSION=5 +LIBXML_MICRO_VERSION=6 LIBXML_VERSION=$LIBXML_MAJOR_VERSION.$LIBXML_MINOR_VERSION.$LIBXML_MICRO_VERSION LIBXML_VERSION_INFO=`expr $LIBXML_MAJOR_VERSION + $LIBXML_MINOR_VERSION`:$LIBXML_MICRO_VERSION:$LIBXML_MINOR_VERSION diff --git a/doc/html/gnome-xml-debugxml.html b/doc/html/gnome-xml-debugxml.html index ba39ab48..03fdbada 100644 --- a/doc/html/gnome-xml-debugxml.html +++ b/doc/html/gnome-xml-debugxml.html @@ -115,7 +115,7 @@ SIZE="3" >

Name

Synopsis

Description

Details















Name

Synopsis

Description

Details












Name

Synopsis

Description

Details
























Name

Synopsis

Description

Details



























Name

Synopsis

Description

Details






Name

Synopsis

xmlNanoFTPInit (void); +void xmlNanoFTPCleanup (void); void* xmlNanoFTPNewCtxtxmlNanoFTPQuit (void *ctx); +void xmlNanoFTPScanProxy (const char *URL); +void xmlNanoFTPProxy (const char *host, + int port, + const char *user, + const char *passwd, + int type); +int xmlNanoFTPUpdateURL (void *ctx, + const char *URL); int xmlNanoFTPGetResponse

Description

Details

hour : minute :



xmlNanoFTPCleanup ()

void        xmlNanoFTPCleanup               (void);









xmlNanoFTPScanProxy ()

void        xmlNanoFTPScanProxy             (const char *URL);

(Re)Initialize the FTP Proxy context by parsing the URL and finding +the protocol host port it indicates. +Should be like ftp://myproxy/ or ftp://myproxy:3128/ +A NULL URL cleans up proxy informations.

URL : The proxy URL used to initialize the proxy context


xmlNanoFTPProxy ()

void        xmlNanoFTPProxy                 (const char *host,
+                                             int port,
+                                             const char *user,
+                                             const char *passwd,
+                                             int type);

Setup the FTP proxy informations. +This can also be done by using ftp_proxy ftp_proxy_user and +ftp_proxy_password environment variables.

host : the proxy host name
port : the proxy port
user : the proxy user name
passwd : the proxy password
type : the type of proxy 1 for using SITE, 2 for USER ab


xmlNanoFTPUpdateURL ()

int         xmlNanoFTPUpdateURL             (void *ctx,
+                                             const char *URL);

Update an FTP context by parsing the URL and finding +new path it indicates. If there is an error in the +protocol, hostname, port or other information, the +error is raised. It indicates a new connection has to +be established.

ctx : an FTP context
URL : The URL used to update the context
Returns :0 if Ok, -1 in case of error (other host).








the file to retrieve the file to retrieve (or NULL if path is in context).


Name

Synopsis

+void xmlNanoHTTPInit (void); +void xmlNanoHTTPCleanup (void); +void xmlNanoHTTPScanProxy (const char *URL); int xmlNanoHTTPFetch

Description

Details

xmlNanoHTTPInit ()

void        xmlNanoHTTPInit                 (void);

Initialize the HTTP protocol layer. +Currently it just checks for proxy informations


xmlNanoHTTPCleanup ()

void        xmlNanoHTTPCleanup              (void);


xmlNanoHTTPScanProxy ()

void        xmlNanoHTTPScanProxy            (const char *URL);

(Re)Initialize the HTTP Proxy context by parsing the URL and finding +the protocol host port it indicates. +Should be like http://myproxy/ or http://myproxy:3128/ +A NULL URL cleans up proxy informations.

URL : The proxy URL used to initialize the proxy context








Name

Synopsis

Description

Details























































































xmlBufferAllocScheme; +extern int xmlSaveNoEmptyTags; xmlBufferPtr

Description

Details










































xmlSaveNoEmptyTags

extern int xmlSaveNoEmptyTags;   /* save empty tags as <empty></empty> */
































































































Name

Synopsis

Description

Details


































































Name

Synopsis

Description

Details







Name

Synopsis

Description

Details











Name

Synopsis

Description

Details
















Name

Synopsis

Description

Details


































+ @@ -437,6 +438,9 @@ + + + @@ -448,6 +452,7 @@ + @@ -455,6 +460,9 @@ + + + diff --git a/doc/xml.html b/doc/xml.html index 105b1975..ebf534bb 100644 --- a/doc/xml.html +++ b/doc/xml.html @@ -149,7 +149,13 @@ for really accurate description

  • there is some kind of roadmap to libxml-2.0: fix I18N, and change structures to accomodate DOM
  • -
  • added a nanoFTP transport module
  • + + +

    1.8.6: Jan 31 2000

    +
      +
    • added a nanoFTP transport module, debugged until the new version of rpmfind can use + it without troubles

    1.8.5: Jan 21 2000

    @@ -1004,6 +1010,6 @@ base under gnome-xml/example

    Daniel Veillard

    -

    $Id: xml.html,v 1.22 2000/01/18 18:01:01 veillard Exp $

    +

    $Id: xml.html,v 1.23 2000/01/25 18:31:22 veillard Exp $

    diff --git a/include/libxml/nanoftp.h b/include/libxml/nanoftp.h index 84ee18df..0a41b975 100644 --- a/include/libxml/nanoftp.h +++ b/include/libxml/nanoftp.h @@ -14,13 +14,28 @@ extern "C" { /** * ftpListCallback: + * @userData: user provided data for the callback + * @filename: the file name (including "->" when links are shown) + * @attrib: the attribute string + * @owner: the owner string + * @group: the group string + * @size: the file size + * @links: the link count + * @year: the year + * @month: the month + * @day: the day + * @hour: the hour + * @minute: the minute + * * A callback for the xmlNanoFTPList command + * Note that only one of year and day:minute are specified */ typedef void (*ftpListCallback) (void *userData, const char *filename, const char* attrib, const char *owner, const char *group, unsigned long size, int links, int year, - const char *month, int day, int minute); + const char *month, int day, int hour, + int minute); /** * ftpDataCallback: * A callback for the xmlNanoFTPGet command @@ -31,6 +46,7 @@ typedef void (*ftpDataCallback) (void *userData, const char *data, int len); * Init */ void xmlNanoFTPInit (void); +void xmlNanoFTPCleanup (void); /* * Creating/freeing contexts @@ -46,7 +62,14 @@ void * xmlNanoFTPOpen (const char *URL); int xmlNanoFTPConnect (void *ctx); int xmlNanoFTPClose (void *ctx); int xmlNanoFTPQuit (void *ctx); - +void xmlNanoFTPScanProxy (const char *URL); +void xmlNanoFTPProxy (const char *host, + int port, + const char *user, + const char *passwd, + int type); +int xmlNanoFTPUpdateURL (void *ctx, + const char *URL); /* * Rathern internal commands diff --git a/include/libxml/nanohttp.h b/include/libxml/nanohttp.h index aeefe405..7e0e2cec 100644 --- a/include/libxml/nanohttp.h +++ b/include/libxml/nanohttp.h @@ -11,6 +11,9 @@ #ifdef __cplusplus extern "C" { #endif +void xmlNanoHTTPInit (void); +void xmlNanoHTTPCleanup (void); +void xmlNanoHTTPScanProxy (const char *URL); int xmlNanoHTTPFetch (const char *URL, const char *filename, char **contentType); diff --git a/include/libxml/tree.h b/include/libxml/tree.h index f53c4ca3..09682298 100644 --- a/include/libxml/tree.h +++ b/include/libxml/tree.h @@ -317,6 +317,7 @@ extern xmlNsPtr baseDTD; extern int oldXMLWDcompatibility;/* maintain compatibility with old WD */ extern int xmlIndentTreeOutput; /* try to indent the tree dumps */ extern xmlBufferAllocationScheme xmlBufferAllocScheme; /* alloc scheme to use */ +extern int xmlSaveNoEmptyTags; /* save empty tags as */ /* * Handling Buffers. diff --git a/nanoftp.c b/nanoftp.c index 69ddc02f..9af52c05 100644 --- a/nanoftp.c +++ b/nanoftp.c @@ -31,20 +31,40 @@ #ifdef HAVE_NETINET_IN_H #include #endif +#ifdef HAVE_ARPA_INET_H +#include +#endif #ifdef HAVE_NETDB_H #include #endif +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif #ifdef HAVE_RESOLV_H #include #endif +#ifdef HAVE_STDLIB_H +#include +#endif #include "xmlmemory.h" #include "nanoftp.h" /* #define DEBUG_FTP 1 */ #ifdef STANDALONE +#ifndef DEBUG_FTP #define DEBUG_FTP 1 #endif +#endif static char hostname[100]; @@ -67,6 +87,111 @@ typedef struct xmlNanoFTPCtxt { int returnValue; /* the protocol return value */ } xmlNanoFTPCtxt, *xmlNanoFTPCtxtPtr; +static int initialized = 0; +static char *proxy = NULL; /* the proxy name if any */ +static int proxyPort = 0; /* the proxy port if any */ +static char *proxyUser = NULL; /* user for proxy authentication */ +static char *proxyPasswd = NULL;/* passwd for proxy authentication */ +static int proxyType = 0; /* uses TYPE or a@b ? */ + +/** + * xmlNanoFTPInit: + * + * Initialize the FTP protocol layer. + * Currently it just checks for proxy informations, + * and get the hostname + */ + +void +xmlNanoFTPInit(void) { + const char *env; + + if (initialized) + return; + + gethostname(hostname, sizeof(hostname)); + + proxyPort = 21; + env = getenv("no_proxy"); + if (env != NULL) + return; + env = getenv("ftp_proxy"); + if (env != NULL) { + xmlNanoFTPScanProxy(env); + } else { + env = getenv("FTP_PROXY"); + if (env != NULL) { + xmlNanoFTPScanProxy(env); + } + } + env = getenv("ftp_proxy_user"); + if (env != NULL) { + proxyUser = xmlMemStrdup(env); + } + env = getenv("ftp_proxy_password"); + if (env != NULL) { + proxyPasswd = xmlMemStrdup(env); + } + initialized = 1; +} + +/** + * xmlNanoFTPClenup: + * + * Cleanup the FTP protocol layer. This cleanup proxy informations. + */ + +void +xmlNanoFTPCleanup(void) { + if (proxy != NULL) { + xmlFree(proxy); + proxy = NULL; + } + if (proxyUser != NULL) { + xmlFree(proxyUser); + proxyUser = NULL; + } + if (proxyPasswd != NULL) { + xmlFree(proxyPasswd); + proxyPasswd = NULL; + } + hostname[0] = 0; + initialized = 0; + return; +} + +/** + * xmlNanoFTPProxy: + * @host: the proxy host name + * @port: the proxy port + * @user: the proxy user name + * @passwd: the proxy password + * @type: the type of proxy 1 for using SITE, 2 for USER a@b + * + * Setup the FTP proxy informations. + * This can also be done by using ftp_proxy ftp_proxy_user and + * ftp_proxy_password environment variables. + */ + +void +xmlNanoFTPProxy(const char *host, int port, const char *user, + const char *passwd, int type) { + if (proxy != NULL) + xmlFree(proxy); + if (proxyUser != NULL) + xmlFree(proxyUser); + if (proxyPasswd != NULL) + xmlFree(proxyPasswd); + if (host) + proxy = xmlMemStrdup(host); + if (user) + proxyUser = xmlMemStrdup(user); + if (passwd) + proxyPasswd = xmlMemStrdup(passwd); + proxyPort = port; + proxyType = type; +} + /** * xmlNanoFTPScanURL: * @ctx: an FTP context @@ -96,6 +221,7 @@ xmlNanoFTPScanURL(void *ctx, const char *URL) { xmlFree(ctxt->path); ctxt->path = NULL; } + if (URL == NULL) return; buf[index] = 0; while (*cur != 0) { if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { @@ -148,6 +274,169 @@ xmlNanoFTPScanURL(void *ctx, const char *URL) { } } +/** + * xmlNanoFTPUpdateURL: + * @ctx: an FTP context + * @URL: The URL used to update the context + * + * Update an FTP context by parsing the URL and finding + * new path it indicates. If there is an error in the + * protocol, hostname, port or other information, the + * error is raised. It indicates a new connection has to + * be established. + * + * Returns 0 if Ok, -1 in case of error (other host). + */ + +int +xmlNanoFTPUpdateURL(void *ctx, const char *URL) { + xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; + const char *cur = URL; + char buf[4096]; + int index = 0; + int port = 0; + + if (URL == NULL) + return(-1); + if (ctxt == NULL) + return(-1); + if (ctxt->protocol == NULL) + return(-1); + if (ctxt->hostname == NULL) + return(-1); + buf[index] = 0; + while (*cur != 0) { + if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { + buf[index] = 0; + if (strcmp(ctxt->protocol, buf)) + return(-1); + index = 0; + cur += 3; + break; + } + buf[index++] = *cur++; + } + if (*cur == 0) + return(-1); + + buf[index] = 0; + while (1) { + if (cur[0] == ':') { + buf[index] = 0; + if (strcmp(ctxt->hostname, buf)) + return(-1); + index = 0; + cur += 1; + while ((*cur >= '0') && (*cur <= '9')) { + port *= 10; + port += *cur - '0'; + cur++; + } + if (port != ctxt->port) + return(-1); + while ((cur[0] != '/') && (*cur != 0)) + cur++; + break; + } + if ((*cur == '/') || (*cur == 0)) { + buf[index] = 0; + if (strcmp(ctxt->hostname, buf)) + return(-1); + index = 0; + break; + } + buf[index++] = *cur++; + } + if (ctxt->path != NULL) { + xmlFree(ctxt->path); + ctxt->path = NULL; + } + + if (*cur == 0) + ctxt->path = xmlMemStrdup("/"); + else { + buf[index] = 0; + while (*cur != 0) { + if ((cur[0] == '#') || (cur[0] == '?')) + break; + buf[index++] = *cur++; + } + buf[index] = 0; + ctxt->path = xmlMemStrdup(buf); + } + return(0); +} + +/** + * xmlNanoFTPScanProxy: + * @URL: The proxy URL used to initialize the proxy context + * + * (Re)Initialize the FTP Proxy context by parsing the URL and finding + * the protocol host port it indicates. + * Should be like ftp://myproxy/ or ftp://myproxy:3128/ + * A NULL URL cleans up proxy informations. + */ + +void +xmlNanoFTPScanProxy(const char *URL) { + const char *cur = URL; + char buf[4096]; + int index = 0; + int port = 0; + + if (proxy != NULL) { + xmlFree(proxy); + proxy = NULL; + } + if (proxyPort != 0) { + proxyPort = 0; + } +#ifdef DEBUG_FTP + if (URL == NULL) + printf("Removing FTP proxy info\n"); + else + printf("Using FTP proxy %s\n", URL); +#endif + if (URL == NULL) return; + buf[index] = 0; + while (*cur != 0) { + if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { + buf[index] = 0; + index = 0; + cur += 3; + break; + } + buf[index++] = *cur++; + } + if (*cur == 0) return; + + buf[index] = 0; + while (1) { + if (cur[0] == ':') { + buf[index] = 0; + proxy = xmlMemStrdup(buf); + index = 0; + cur += 1; + while ((*cur >= '0') && (*cur <= '9')) { + port *= 10; + port += *cur - '0'; + cur++; + } + if (port != 0) proxyPort = port; + while ((cur[0] != '/') && (*cur != 0)) + cur++; + break; + } + if ((*cur == '/') || (*cur == 0)) { + buf[index] = 0; + proxy = xmlMemStrdup(buf); + index = 0; + break; + } + buf[index++] = *cur++; + } +} + /** * xmlNanoFTPNewCtxt: * @URL: The URL used to initialize the context @@ -195,20 +484,6 @@ xmlNanoFTPFreeCtxt(void * ctx) { xmlFree(ctxt); } -/** - * xmlNanoFTPInit: - * - * Initialize the FTP handling. - */ - -void -xmlNanoFTPInit(void) { - static int done = 0; - if (done) return; - gethostname(hostname, sizeof(hostname)); - done = 1; -} - /** * Parsing of the server answer, we just extract the code. * return 0 for errors @@ -446,6 +721,7 @@ int xmlNanoFTPConnect(void *ctx) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; struct hostent *hp; + int port; int res; if (ctxt == NULL) @@ -456,7 +732,10 @@ xmlNanoFTPConnect(void *ctx) { /* * do the blocking DNS query. */ - hp = gethostbyname(ctxt->hostname); + if (proxy) + hp = gethostbyname(proxy); + else + hp = gethostbyname(ctxt->hostname); if (hp == NULL) return(-1); @@ -466,9 +745,14 @@ xmlNanoFTPConnect(void *ctx) { memset(&ctxt->ftpAddr, 0, sizeof(ctxt->ftpAddr)); ctxt->ftpAddr.sin_family = AF_INET; memcpy(&ctxt->ftpAddr.sin_addr, hp->h_addr_list[0], hp->h_length); - if (ctxt->port == 0) - ctxt->port = 21; - ctxt->ftpAddr.sin_port = htons(ctxt->port); + if (proxy) { + port = proxyPort; + } else { + port = ctxt->port; + } + if (port == 0) + port = 21; + ctxt->ftpAddr.sin_port = htons(port); ctxt->controlFd = socket(AF_INET, SOCK_STREAM, 0); if (ctxt->controlFd < 0) return(-1); @@ -524,6 +808,157 @@ xmlNanoFTPConnect(void *ctx) { * +---+ ACCT +---+-- | ----->+---+ * | |---------->| W | 4,5 -------->| F | * +---+ +---+------------->+---+ + * + * Of course in case of using a proxy this get really nasty and is not + * standardized at all :-( + */ + if (proxy) { + int len; + char buf[400]; + + if (proxyUser != NULL) { + /* + * We need proxy auth + */ + len = snprintf(buf, sizeof(buf), "USER %s\r\n", proxyUser); +#ifdef DEBUG_FTP + printf(buf); +#endif + res = send(ctxt->controlFd, buf, len, 0); + if (res < 0) { + close(ctxt->controlFd); + ctxt->controlFd = -1; + return(res); + } + res = xmlNanoFTPGetResponse(ctxt); + switch (res) { + case 2: + if (proxyPasswd == NULL) + break; + case 3: + if (proxyPasswd != NULL) + len = snprintf(buf, sizeof(buf), "PASS %s\r\n", proxyPasswd); + else + len = snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", + hostname); +#ifdef DEBUG_FTP + printf(buf); +#endif + res = send(ctxt->controlFd, buf, len, 0); + if (res < 0) { + close(ctxt->controlFd); + ctxt->controlFd = -1; + return(res); + } + res = xmlNanoFTPGetResponse(ctxt); + if (res > 3) { + close(ctxt->controlFd); + ctxt->controlFd = -1; + return(-1); + } + break; + case 1: + break; + case 4: + case 5: + case -1: + default: + close(ctxt->controlFd); + ctxt->controlFd = -1; + return(-1); + } + } + + /* + * We assume we don't need more authentication to the proxy + * and that it succeeded :-\ + */ + switch (proxyType) { + case 0: + /* we will try in seqence */ + case 1: + /* Using SITE command */ + len = snprintf(buf, sizeof(buf), "SITE %s\r\n", ctxt->hostname); +#ifdef DEBUG_FTP + printf(buf); +#endif + res = send(ctxt->controlFd, buf, len, 0); + if (res < 0) { + close(ctxt->controlFd); ctxt->controlFd = -1; + ctxt->controlFd = -1; + return(res); + } + res = xmlNanoFTPGetResponse(ctxt); + if (res == 2) { + /* we assume it worked :-\ 1 is error for SITE command */ + proxyType = 1; + break; + } + if (proxyType == 1) { + close(ctxt->controlFd); ctxt->controlFd = -1; + ctxt->controlFd = -1; + return(-1); + } + case 2: + /* USER user@host command */ + if (ctxt->user == NULL) + len = snprintf(buf, sizeof(buf), "USER anonymous@%s\r\n", + ctxt->hostname); + else + len = snprintf(buf, sizeof(buf), "USER %s@%s\r\n", + ctxt->user, ctxt->hostname); +#ifdef DEBUG_FTP + printf(buf); +#endif + res = send(ctxt->controlFd, buf, len, 0); + if (res < 0) { + close(ctxt->controlFd); ctxt->controlFd = -1; + ctxt->controlFd = -1; + return(res); + } + res = xmlNanoFTPGetResponse(ctxt); + if ((res == 1) || (res == 2)) { + /* we assume it worked :-\ */ + proxyType = 2; + return(0); + } + if (ctxt->passwd == NULL) + len = snprintf(buf, sizeof(buf), "PASS libxml@%s\r\n", hostname); + else + len = snprintf(buf, sizeof(buf), "PASS %s\r\n", ctxt->passwd); +#ifdef DEBUG_FTP + printf(buf); +#endif + res = send(ctxt->controlFd, buf, len, 0); + if (res < 0) { + close(ctxt->controlFd); ctxt->controlFd = -1; + ctxt->controlFd = -1; + return(res); + } + res = xmlNanoFTPGetResponse(ctxt); + if ((res == 1) || (res == 2)) { + /* we assume it worked :-\ */ + proxyType = 2; + return(0); + } + if (proxyType == 2) { + close(ctxt->controlFd); ctxt->controlFd = -1; + ctxt->controlFd = -1; + return(-1); + } + case 3: + /* + * If you need support for other Proxy authentication scheme + * send the code or at least the sequence in use. + */ + default: + close(ctxt->controlFd); ctxt->controlFd = -1; + ctxt->controlFd = -1; + return(-1); + } + } + /* + * Non-proxy handling. */ res = xmlNanoFTPSendUser(ctxt); if (res < 0) { @@ -896,7 +1331,7 @@ xmlNanoFTPParseList(const char *list, ftpListCallback callback, void *userData) } if (callback != NULL) { callback(userData, filename, attrib, owner, group, size, links, - year, month, day, minute); + year, month, day, hour, minute); } return(cur - list); } @@ -924,12 +1359,19 @@ xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, fd_set rfd, efd; struct timeval tv; - ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); - - if (filename != NULL) - len = snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename); - else + if (filename == NULL) { + if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1) + return(-1); + ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); len = snprintf(buf, sizeof(buf), "LIST -L\r\n"); + } else { + if (filename[0] != '/') { + if (xmlNanoFTPCwd(ctxt, ctxt->path) < 1) + return(-1); + } + ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); + len = snprintf(buf, sizeof(buf), "LIST -L %s\r\n", filename); + } #ifdef DEBUG_FTP printf(buf); #endif @@ -1003,7 +1445,7 @@ xmlNanoFTPList(void *ctx, ftpListCallback callback, void *userData, /** * xmlNanoFTPGetSocket: * @ctx: an FTP context - * @filename: the file to retrieve + * @filename: the file to retrieve (or NULL if path is in context). * * Initiate fetch of the given file from the server. * @@ -1016,7 +1458,7 @@ xmlNanoFTPGetSocket(void *ctx, const char *filename) { xmlNanoFTPCtxtPtr ctxt = (xmlNanoFTPCtxtPtr) ctx; char buf[300]; int res, len; - if (filename == NULL) + if ((filename == NULL) && (ctxt->path == NULL)) return(-1); ctxt->dataFd = xmlNanoFTPGetConnection(ctxt); @@ -1034,7 +1476,10 @@ xmlNanoFTPGetSocket(void *ctx, const char *filename) { close(ctxt->dataFd); ctxt->dataFd = -1; return(-res); } - len = snprintf(buf, sizeof(buf), "RETR %s\r\n", filename); + if (filename == NULL) + len = snprintf(buf, sizeof(buf), "RETR %s\r\n", ctxt->path); + else + len = snprintf(buf, sizeof(buf), "RETR %s\r\n", filename); #ifdef DEBUG_FTP printf(buf); #endif @@ -1073,7 +1518,7 @@ xmlNanoFTPGet(void *ctx, ftpDataCallback callback, void *userData, fd_set rfd; struct timeval tv; - if (filename == NULL) + if ((filename == NULL) && (ctxt->path == NULL)) return(-1); if (callback == NULL) return(-1); @@ -1218,7 +1663,7 @@ xmlNanoFTPClose(void *ctx) { ************************************************************************/ void ftpList(void *userData, const char *filename, const char* attrib, const char *owner, const char *group, unsigned long size, int links, - int year, const char *month, int day, int minute) { + int year, const char *month, int day, int hour, int minute) { printf("%s %s %s %ld %s\n", attrib, owner, group, size, filename); } void ftpData(void *userData, const char *data, int len) { @@ -1233,12 +1678,15 @@ void ftpData(void *userData, const char *data, int len) { int main(int argc, char **argv) { void *ctxt; FILE *output; - int res; - const char *tstfile = "tstfile"; + char *tstfile = NULL; xmlNanoFTPInit(); if (argc > 1) { - ctxt = xmlNanoFTPConnectTo(argv[1], 0); + ctxt = xmlNanoFTPNewCtxt(argv[1]); + if (xmlNanoFTPConnect(ctxt) < 0) { + fprintf(stderr, "Couldn't connect to %s\n", argv[1]); + exit(1); + } if (argc > 2) tstfile = argv[2]; } else @@ -1247,33 +1695,11 @@ int main(int argc, char **argv) { fprintf(stderr, "Couldn't connect to localhost\n"); exit(1); } - res = xmlNanoFTPCwd(ctxt, "/linux"); - if (res < 0) { - fprintf(stderr, "disconnected\n"); - xmlNanoFTPClose(ctxt); - exit(1); - } - if (res == 0) { - fprintf(stderr, "/linux : CWD failed\n"); - } else { - fprintf(stderr, "/linux : CWD successful\n"); - } - res = xmlNanoFTPCwd(ctxt, "/toto"); - if (res < 0) { - fprintf(stderr, "disconnected\n"); - xmlNanoFTPClose(ctxt); - exit(1); - } - if (res == 0) { - fprintf(stderr, "/toto : CWD failed\n"); - } else { - fprintf(stderr, "/toto : CWD successful\n"); - } - xmlNanoFTPList(ctxt, ftpList, NULL, NULL); + xmlNanoFTPList(ctxt, ftpList, NULL, tstfile); output = fopen("/tmp/tstdata", "w"); if (output != NULL) { if (xmlNanoFTPGet(ctxt, ftpData, (void *) output, tstfile) < 0) - fprintf(stderr, "Failed to get file %s\n", tstfile); + fprintf(stderr, "Failed to get file\n"); } xmlNanoFTPClose(ctxt); diff --git a/nanoftp.h b/nanoftp.h index 84ee18df..0a41b975 100644 --- a/nanoftp.h +++ b/nanoftp.h @@ -14,13 +14,28 @@ extern "C" { /** * ftpListCallback: + * @userData: user provided data for the callback + * @filename: the file name (including "->" when links are shown) + * @attrib: the attribute string + * @owner: the owner string + * @group: the group string + * @size: the file size + * @links: the link count + * @year: the year + * @month: the month + * @day: the day + * @hour: the hour + * @minute: the minute + * * A callback for the xmlNanoFTPList command + * Note that only one of year and day:minute are specified */ typedef void (*ftpListCallback) (void *userData, const char *filename, const char* attrib, const char *owner, const char *group, unsigned long size, int links, int year, - const char *month, int day, int minute); + const char *month, int day, int hour, + int minute); /** * ftpDataCallback: * A callback for the xmlNanoFTPGet command @@ -31,6 +46,7 @@ typedef void (*ftpDataCallback) (void *userData, const char *data, int len); * Init */ void xmlNanoFTPInit (void); +void xmlNanoFTPCleanup (void); /* * Creating/freeing contexts @@ -46,7 +62,14 @@ void * xmlNanoFTPOpen (const char *URL); int xmlNanoFTPConnect (void *ctx); int xmlNanoFTPClose (void *ctx); int xmlNanoFTPQuit (void *ctx); - +void xmlNanoFTPScanProxy (const char *URL); +void xmlNanoFTPProxy (const char *host, + int port, + const char *user, + const char *passwd, + int type); +int xmlNanoFTPUpdateURL (void *ctx, + const char *URL); /* * Rathern internal commands diff --git a/nanohttp.c b/nanohttp.c index 4b27225a..e2dfda3b 100644 --- a/nanohttp.c +++ b/nanohttp.c @@ -92,6 +92,58 @@ typedef struct xmlNanoHTTPCtxt { char *location; /* the new URL in case of redirect */ } xmlNanoHTTPCtxt, *xmlNanoHTTPCtxtPtr; +static int initialized = 0; +static char *proxy = NULL; /* the proxy name if any */ +static int proxyPort; /* the proxy port if any */ + +/** + * xmlNanoHTTPInit: + * + * Initialize the HTTP protocol layer. + * Currently it just checks for proxy informations + */ + +void +xmlNanoHTTPInit(void) { + const char *env; + + if (initialized) + return; + + if (proxy == NULL) { + proxyPort = 80; + env = getenv("no_proxy"); + if (env != NULL) + goto done; + env = getenv("http_proxy"); + if (env != NULL) { + xmlNanoHTTPScanProxy(env); + goto done; + } + env = getenv("HTTP_PROXY"); + if (env != NULL) { + xmlNanoHTTPScanProxy(env); + goto done; + } + } +done: + initialized = 1; +} + +/** + * xmlNanoHTTPClenup: + * + * Cleanup the HTTP protocol layer. + */ + +void +xmlNanoHTTPCleanup(void) { + if (proxy != NULL) + xmlFree(proxy); + initialized = 0; + return; +} + /** * xmlNanoHTTPScanURL: * @ctxt: an HTTP context @@ -120,6 +172,7 @@ xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) { xmlFree(ctxt->path); ctxt->path = NULL; } + if (URL == NULL) return; buf[index] = 0; while (*cur != 0) { if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { @@ -172,6 +225,76 @@ xmlNanoHTTPScanURL(xmlNanoHTTPCtxtPtr ctxt, const char *URL) { } } +/** + * xmlNanoHTTPScanProxy: + * @URL: The proxy URL used to initialize the proxy context + * + * (Re)Initialize the HTTP Proxy context by parsing the URL and finding + * the protocol host port it indicates. + * Should be like http://myproxy/ or http://myproxy:3128/ + * A NULL URL cleans up proxy informations. + */ + +void +xmlNanoHTTPScanProxy(const char *URL) { + const char *cur = URL; + char buf[4096]; + int index = 0; + int port = 0; + + if (proxy != NULL) { + xmlFree(proxy); + proxy = NULL; + } + if (proxyPort != 0) { + proxyPort = 0; + } +#ifdef DEBUG_HTTP + if (URL == NULL) + printf("Removing HTTP proxy info\n"); + else + printf("Using HTTP proxy %s\n", URL); +#endif + if (URL == NULL) return; + buf[index] = 0; + while (*cur != 0) { + if ((cur[0] == ':') && (cur[1] == '/') && (cur[2] == '/')) { + buf[index] = 0; + index = 0; + cur += 3; + break; + } + buf[index++] = *cur++; + } + if (*cur == 0) return; + + buf[index] = 0; + while (1) { + if (cur[0] == ':') { + buf[index] = 0; + proxy = xmlMemStrdup(buf); + index = 0; + cur += 1; + while ((*cur >= '0') && (*cur <= '9')) { + port *= 10; + port += *cur - '0'; + cur++; + } + if (port != 0) proxyPort = port; + while ((cur[0] != '/') && (*cur != 0)) + cur++; + break; + } + if ((*cur == '/') || (*cur == 0)) { + buf[index] = 0; + proxy = xmlMemStrdup(buf); + index = 0; + break; + } + buf[index++] = *cur++; + } +} + /** * xmlNanoHTTPNewCtxt: * @URL: The URL used to initialize the context @@ -598,6 +721,7 @@ xmlNanoHTTPOpen(const char *URL, char **contentType) { int nbRedirects = 0; char *redirURL = NULL; + xmlNanoHTTPInit(); if (contentType != NULL) *contentType = NULL; retry: @@ -618,23 +742,54 @@ retry: xmlNanoHTTPFreeCtxt(ctxt); return(NULL); } - ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); + if (proxy) + ret = xmlNanoHTTPConnectHost(proxy, proxyPort); + else + ret = xmlNanoHTTPConnectHost(ctxt->hostname, ctxt->port); if (ret < 0) { xmlNanoHTTPFreeCtxt(ctxt); return(NULL); } ctxt->fd = ret; -#ifdef HAVE_SNPRINTF - snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", - ctxt->path, ctxt->hostname); + if (proxy) { +#ifdef have_snprintf + if (ctxt->port != 80) + snprintf(buf, sizeof(buf), + "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n", + ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname); + else + snprintf(buf, sizeof(buf),"GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", + ctxt->hostname, ctxt->path, ctxt->hostname); #else - sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", - ctxt->path, ctxt->hostname); + if (ctxt->port != 80) + sprintf(buf, + "GET http://%s:%d%s HTTP/1.0\r\nHost: %s\r\n\r\n", + ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname); + else + sprintf(buf, "GET http://%s%s HTTP/1.0\r\nHost: %s\r\n\r\n", + ctxt->hostname, ctxt->path, ctxt->hostname); #endif #ifdef DEBUG_HTTP - printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n", - ctxt->path, ctxt->hostname); + if (ctxt->port != 80) + printf("-> Proxy GET http://%s:%d%s HTTP/1.0\n-> Host: %s\n\n", + ctxt->hostname, ctxt->port, ctxt->path, ctxt->hostname); + else + printf("-> Proxy GET http://%s%s HTTP/1.0\n-> Host: %s\n\n", + ctxt->hostname, ctxt->path, ctxt->hostname); #endif + } else { +#ifdef HAVE_SNPRINTF + snprintf(buf, sizeof(buf),"GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", + ctxt->path, ctxt->hostname); +#else + sprintf(buf, "GET %s HTTP/1.0\r\nHost: %s\r\n\r\n", + ctxt->path, ctxt->hostname); +#endif +#ifdef DEBUG_HTTP + printf("-> GET %s HTTP/1.0\n-> Host: %s\n\n", + ctxt->path, ctxt->hostname); +#endif + } ctxt->outptr = ctxt->out = xmlMemStrdup(buf); ctxt->state = XML_NANO_HTTP_WRITE; xmlNanoHTTPSend(ctxt); @@ -645,6 +800,7 @@ retry: if (head && (*p == 0)) { head = 0; ctxt->content = ctxt->inrptr; + xmlFree(p); break; } xmlNanoHTTPScanAnswer(ctxt, p); @@ -984,7 +1140,7 @@ xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) { if (!strcmp(filename, "-")) fd = 0; else { - fd = open(filename, O_CREAT | O_WRONLY); + fd = open(filename, O_CREAT | O_WRONLY, 00644); if (fd < 0) { xmlNanoHTTPClose(ctxt); if ((contentType != NULL) && (*contentType != NULL)) { @@ -1000,6 +1156,7 @@ xmlNanoHTTPFetch(const char *URL, const char *filename, char **contentType) { } xmlNanoHTTPClose(ctxt); + close(fd); return(0); } @@ -1068,6 +1225,8 @@ int main(int argc, char **argv) { printf("%s: minimal HTTP GET implementation\n", argv[0]); printf("\tusage %s [ URL [ filename ] ]\n", argv[0]); } + xmlNanoHTTPCleanup(); + xmlMemoryDump(); return(0); } #endif /* STANDALONE */ diff --git a/nanohttp.h b/nanohttp.h index aeefe405..7e0e2cec 100644 --- a/nanohttp.h +++ b/nanohttp.h @@ -11,6 +11,9 @@ #ifdef __cplusplus extern "C" { #endif +void xmlNanoHTTPInit (void); +void xmlNanoHTTPCleanup (void); +void xmlNanoHTTPScanProxy (const char *URL); int xmlNanoHTTPFetch (const char *URL, const char *filename, char **contentType); diff --git a/tree.c b/tree.c index db2b5d26..466c11f3 100644 --- a/tree.c +++ b/tree.c @@ -38,6 +38,7 @@ xmlBufferAllocationScheme xmlBufferAllocScheme = XML_BUFFER_ALLOC_EXACT; static int xmlCompressMode = 0; static int xmlCheckDTD = 1; +int xmlSaveNoEmptyTags = 0; #define UPDATE_LAST_CHILD(n) if ((n) != NULL) { \ xmlNodePtr ulccur = (n)->childs; \ @@ -4299,7 +4300,8 @@ xmlNodeDump(xmlBufferPtr buf, xmlDocPtr doc, xmlNodePtr cur, int level, if (cur->properties != NULL) xmlAttrListDump(buf, doc, cur->properties); - if ((cur->content == NULL) && (cur->childs == NULL)) { + if ((cur->content == NULL) && (cur->childs == NULL) && + (!xmlSaveNoEmptyTags)) { xmlBufferWriteChar(buf, "/>"); return; } diff --git a/tree.h b/tree.h index f53c4ca3..09682298 100644 --- a/tree.h +++ b/tree.h @@ -317,6 +317,7 @@ extern xmlNsPtr baseDTD; extern int oldXMLWDcompatibility;/* maintain compatibility with old WD */ extern int xmlIndentTreeOutput; /* try to indent the tree dumps */ extern xmlBufferAllocationScheme xmlBufferAllocScheme; /* alloc scheme to use */ +extern int xmlSaveNoEmptyTags; /* save empty tags as */ /* * Handling Buffers.