2001-02-23 20:55:21 +03:00
/*
* nanohttp . c : minimalist HTTP GET implementation to fetch external subsets .
* focuses on size , streamability , reentrancy and portability
*
* This is clearly not a general purpose HTTP implementation
* If you look for one , check :
* http : //www.w3.org/Library/
*
* See Copyright for the status of this software .
*
2001-06-24 16:13:24 +04:00
* daniel @ veillard . com
2001-02-23 20:55:21 +03:00
*/
2012-09-11 09:26:36 +04:00
2002-03-18 22:37:11 +03:00
# define IN_LIBXML
2001-04-21 20:57:29 +04:00
# include "libxml.h"
2001-02-23 20:55:21 +03:00
# ifdef LIBXML_HTTP_ENABLED
# include <string.h>
2022-11-04 15:34:39 +03:00
# include <ctype.h>
2001-02-23 20:55:21 +03:00
# include <stdlib.h>
2022-03-02 02:29:17 +03:00
# include <errno.h>
2001-02-23 20:55:21 +03:00
# ifdef HAVE_UNISTD_H
# include <unistd.h>
2022-11-22 10:20:53 +03:00
# elif defined (_WIN32)
# include <io.h>
2001-02-23 20:55:21 +03:00
# endif
# ifdef HAVE_SYS_SOCKET_H
# include <sys/socket.h>
# endif
# ifdef HAVE_NETINET_IN_H
# include <netinet/in.h>
# endif
# ifdef HAVE_ARPA_INET_H
# include <arpa/inet.h>
# endif
# ifdef HAVE_NETDB_H
# include <netdb.h>
# endif
# ifdef HAVE_FCNTL_H
2012-09-11 09:26:36 +04:00
# include <fcntl.h>
2001-02-23 20:55:21 +03:00
# endif
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# endif
2009-08-23 15:11:01 +04:00
# ifndef HAVE_POLL_H
2001-02-23 20:55:21 +03:00
# ifdef HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif
2009-08-23 15:11:01 +04:00
# else
# include <poll.h>
# endif
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
# include <zlib.h>
# endif
2001-02-23 20:55:21 +03:00
# ifdef VMS
# include <stropts>
2005-03-31 14:24:24 +04:00
# define XML_SOCKLEN_T unsigned int
2001-02-23 20:55:21 +03:00
# endif
2022-03-01 00:42:10 +03:00
# if defined(_WIN32)
2003-08-14 05:23:25 +04:00
# include <wsockcompat.h>
# endif
2001-10-13 13:15:48 +04:00
# include <libxml/globals.h>
2001-07-23 23:10:52 +04:00
# include <libxml/xmlerror.h>
2001-02-23 20:55:21 +03:00
# include <libxml/xmlmemory.h>
# include <libxml/parser.h> /* for xmlStr(n)casecmp() */
# include <libxml/nanohttp.h>
2001-10-17 19:58:35 +04:00
# include <libxml/globals.h>
2002-12-04 14:44:48 +03:00
# include <libxml/uri.h>
2001-02-23 20:55:21 +03:00
2022-08-26 02:22:33 +03:00
# include "private/error.h"
# include "private/io.h"
2001-02-23 20:55:21 +03:00
/**
* A couple portability macros
*/
# ifndef _WINSOCKAPI_
# define closesocket(s) close(s)
# define SOCKET int
2010-11-04 14:08:08 +03:00
# define INVALID_SOCKET (-1)
2001-02-23 20:55:21 +03:00
# endif
2005-03-31 14:24:24 +04:00
# ifndef XML_SOCKLEN_T
# define XML_SOCKLEN_T unsigned int
2002-03-13 13:03:35 +03:00
# endif
2001-07-23 23:10:52 +04:00
2022-09-04 04:19:01 +03:00
# define GETHOSTBYNAME_ARG_CAST (char *)
# define SEND_ARG2_CAST (char *)
2001-02-23 20:55:21 +03:00
# ifdef STANDALONE
# define DEBUG_HTTP
# define xmlStrncasecmp(a, b, n) strncasecmp((char *)a, (char *)b, n)
# define xmlStrcasecmpi(a, b) strcasecmp((char *)a, (char *)b)
# endif
# define XML_NANO_HTTP_MAX_REDIR 10
# define XML_NANO_HTTP_CHUNK 4096
# define XML_NANO_HTTP_CLOSED 0
# define XML_NANO_HTTP_WRITE 1
# define XML_NANO_HTTP_READ 2
# define XML_NANO_HTTP_NONE 4
typedef struct xmlNanoHTTPCtxt {
char * protocol ; /* the protocol name */
char * hostname ; /* the host name */
int port ; /* the port */
char * path ; /* the path within the URL */
2005-04-13 06:55:12 +04:00
char * query ; /* the query string */
2001-02-23 20:55:21 +03:00
SOCKET fd ; /* the file descriptor for the socket */
int state ; /* WRITE / READ / CLOSED */
char * out ; /* buffer sent (zero terminated) */
char * outptr ; /* index within the buffer sent */
char * in ; /* the receiving buffer */
char * content ; /* the start of the content */
char * inptr ; /* the next byte to read from network */
char * inrptr ; /* the next byte to give back to the client */
int inlen ; /* len of the input buffer */
int last ; /* return code for last operation */
int returnValue ; /* the protocol return value */
2009-09-05 16:52:55 +04:00
int version ; /* the protocol version */
2001-07-23 23:10:52 +04:00
int ContentLength ; /* specified content length from HTTP header */
2001-02-23 20:55:21 +03:00
char * contentType ; /* the MIME type for the input */
char * location ; /* the new URL in case of redirect */
char * authHeader ; /* contents of {WWW,Proxy}-Authenticate header */
2003-10-18 15:29:40 +04:00
char * encoding ; /* encoding extracted from the contentType */
2003-10-19 17:35:37 +04:00
char * mimeType ; /* Mime-Type extracted from the contentType */
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
z_stream * strm ; /* Zlib stream object */
int usesGzip ; /* "Content-Encoding: gzip" was detected */
# endif
2001-02-23 20:55:21 +03:00
} xmlNanoHTTPCtxt , * xmlNanoHTTPCtxtPtr ;
static int initialized = 0 ;
static char * proxy = NULL ; /* the proxy name if any */
static int proxyPort ; /* the proxy port if any */
static unsigned int timeout = 60 ; /* the select() timeout in seconds */
2004-06-27 16:08:10 +04:00
static int xmlNanoHTTPFetchContent ( void * ctx , char * * ptr , int * len ) ;
2001-07-23 23:10:52 +04:00
2003-10-10 23:36:36 +04:00
/**
* xmlHTTPErrMemory :
2020-03-08 19:19:42 +03:00
* @ extra : extra information
2003-10-10 23:36:36 +04:00
*
* Handle an out of memory condition
*/
static void
xmlHTTPErrMemory ( const char * extra )
{
__xmlSimpleError ( XML_FROM_HTTP , XML_ERR_NO_MEMORY , NULL , NULL , extra ) ;
}
2001-02-23 20:55:21 +03:00
/**
* A portability function
*/
2001-03-24 20:00:36 +03:00
static int socket_errno ( void ) {
2001-02-23 20:55:21 +03:00
# ifdef _WINSOCKAPI_
2017-10-09 01:05:04 +03:00
int err = WSAGetLastError ( ) ;
switch ( err ) {
case WSAECONNRESET :
return ( ECONNRESET ) ;
case WSAEINPROGRESS :
return ( EINPROGRESS ) ;
case WSAEINTR :
return ( EINTR ) ;
case WSAESHUTDOWN :
return ( ESHUTDOWN ) ;
case WSAEWOULDBLOCK :
return ( EWOULDBLOCK ) ;
default :
return ( err ) ;
}
2001-02-23 20:55:21 +03:00
# else
return ( errno ) ;
# endif
}
/**
* xmlNanoHTTPInit :
*
* Initialize the HTTP protocol layer .
2020-03-08 19:19:42 +03:00
* Currently it just checks for proxy information
2001-02-23 20:55:21 +03:00
*/
void
xmlNanoHTTPInit ( void ) {
const char * env ;
# ifdef _WINSOCKAPI_
2012-09-11 09:26:36 +04:00
WSADATA wsaData ;
2001-02-23 20:55:21 +03:00
# endif
if ( initialized )
return ;
# ifdef _WINSOCKAPI_
if ( WSAStartup ( MAKEWORD ( 1 , 1 ) , & wsaData ) ! = 0 )
return ;
# endif
if ( proxy = = NULL ) {
proxyPort = 80 ;
env = getenv ( " no_proxy " ) ;
2004-08-16 04:39:03 +04:00
if ( env & & ( ( env [ 0 ] = = ' * ' ) & & ( env [ 1 ] = = 0 ) ) )
2001-02-23 20:55:21 +03:00
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 ;
}
/**
2001-07-18 23:30:27 +04:00
* xmlNanoHTTPCleanup :
2001-02-23 20:55:21 +03:00
*
* Cleanup the HTTP protocol layer .
*/
void
xmlNanoHTTPCleanup ( void ) {
2005-07-12 19:09:53 +04:00
if ( proxy ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( proxy ) ;
2005-07-12 19:09:53 +04:00
proxy = NULL ;
}
2001-02-23 20:55:21 +03:00
# ifdef _WINSOCKAPI_
if ( initialized )
WSACleanup ( ) ;
# endif
initialized = 0 ;
return ;
}
/**
* xmlNanoHTTPScanURL :
* @ ctxt : an HTTP context
* @ URL : The URL used to initialize the context
*
* ( Re ) Initialize an HTTP context by parsing the URL and finding
* the protocol host port and path it indicates .
*/
static void
xmlNanoHTTPScanURL ( xmlNanoHTTPCtxtPtr ctxt , const char * URL ) {
2005-02-13 11:18:52 +03:00
xmlURIPtr uri ;
2013-02-28 14:22:46 +04:00
int len ;
2005-02-13 11:18:52 +03:00
/*
* Clear any existing data from the context
*/
2012-09-11 09:26:36 +04:00
if ( ctxt - > protocol ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt - > protocol ) ;
ctxt - > protocol = NULL ;
}
2012-09-11 09:26:36 +04:00
if ( ctxt - > hostname ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt - > hostname ) ;
ctxt - > hostname = NULL ;
}
2012-09-11 09:26:36 +04:00
if ( ctxt - > path ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt - > path ) ;
ctxt - > path = NULL ;
}
2012-09-11 09:26:36 +04:00
if ( ctxt - > query ! = NULL ) {
2005-04-13 06:55:12 +04:00
xmlFree ( ctxt - > query ) ;
ctxt - > query = NULL ;
}
2001-02-23 20:55:21 +03:00
if ( URL = = NULL ) return ;
2003-06-21 18:20:04 +04:00
2005-08-07 14:46:19 +04:00
uri = xmlParseURIRaw ( URL , 1 ) ;
2005-02-13 11:18:52 +03:00
if ( uri = = NULL )
return ;
2003-06-21 18:20:04 +04:00
2005-02-13 11:18:52 +03:00
if ( ( uri - > scheme = = NULL ) | | ( uri - > server = = NULL ) ) {
xmlFreeURI ( uri ) ;
return ;
2001-02-23 20:55:21 +03:00
}
2012-09-11 09:26:36 +04:00
2005-02-13 11:18:52 +03:00
ctxt - > protocol = xmlMemStrdup ( uri - > scheme ) ;
2013-02-28 14:22:46 +04:00
/* special case of IPv6 addresses, the [] need to be removed */
if ( ( uri - > server ! = NULL ) & & ( * uri - > server = = ' [ ' ) ) {
len = strlen ( uri - > server ) ;
if ( ( len > 2 ) & & ( uri - > server [ len - 1 ] = = ' ] ' ) ) {
ctxt - > hostname = ( char * ) xmlCharStrndup ( uri - > server + 1 , len - 2 ) ;
} else
ctxt - > hostname = xmlMemStrdup ( uri - > server ) ;
} else
ctxt - > hostname = xmlMemStrdup ( uri - > server ) ;
2005-02-13 11:18:52 +03:00
if ( uri - > path ! = NULL )
ctxt - > path = xmlMemStrdup ( uri - > path ) ;
else
ctxt - > path = xmlMemStrdup ( " / " ) ;
2005-04-13 06:55:12 +04:00
if ( uri - > query ! = NULL )
ctxt - > query = xmlMemStrdup ( uri - > query ) ;
2005-02-13 11:18:52 +03:00
if ( uri - > port ! = 0 )
ctxt - > port = uri - > port ;
xmlFreeURI ( uri ) ;
2001-02-23 20:55:21 +03:00
}
/**
* 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/
2020-03-08 19:19:42 +03:00
* A NULL URL cleans up proxy information .
2001-02-23 20:55:21 +03:00
*/
void
xmlNanoHTTPScanProxy ( const char * URL ) {
2005-02-13 11:18:52 +03:00
xmlURIPtr uri ;
2001-02-23 20:55:21 +03:00
2012-09-11 09:26:36 +04:00
if ( proxy ! = NULL ) {
2001-02-23 20:55:21 +03:00
xmlFree ( proxy ) ;
proxy = NULL ;
}
2005-02-13 11:18:52 +03:00
proxyPort = 0 ;
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_HTTP
if ( URL = = NULL )
xmlGenericError ( xmlGenericErrorContext ,
" Removing HTTP proxy info \n " ) ;
else
xmlGenericError ( xmlGenericErrorContext ,
" Using HTTP proxy %s \n " , URL ) ;
# endif
if ( URL = = NULL ) return ;
2003-06-21 18:20:04 +04:00
2005-08-07 14:46:19 +04:00
uri = xmlParseURIRaw ( URL , 1 ) ;
2005-02-13 11:18:52 +03:00
if ( ( uri = = NULL ) | | ( uri - > scheme = = NULL ) | |
( strcmp ( uri - > scheme , " http " ) ) | | ( uri - > server = = NULL ) ) {
__xmlIOErr ( XML_FROM_HTTP , XML_HTTP_URL_SYNTAX , " Syntax Error \n " ) ;
if ( uri ! = NULL )
xmlFreeURI ( uri ) ;
return ;
2001-02-23 20:55:21 +03:00
}
2012-09-11 09:26:36 +04:00
2005-02-13 11:18:52 +03:00
proxy = xmlMemStrdup ( uri - > server ) ;
if ( uri - > port ! = 0 )
proxyPort = uri - > port ;
xmlFreeURI ( uri ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoHTTPNewCtxt :
* @ URL : The URL used to initialize the context
*
* Allocate and initialize a new HTTP context .
*
* Returns an HTTP context or NULL in case of error .
*/
static xmlNanoHTTPCtxtPtr
xmlNanoHTTPNewCtxt ( const char * URL ) {
xmlNanoHTTPCtxtPtr ret ;
ret = ( xmlNanoHTTPCtxtPtr ) xmlMalloc ( sizeof ( xmlNanoHTTPCtxt ) ) ;
2003-10-10 23:36:36 +04:00
if ( ret = = NULL ) {
xmlHTTPErrMemory ( " allocating context " ) ;
return ( NULL ) ;
}
2001-02-23 20:55:21 +03:00
memset ( ret , 0 , sizeof ( xmlNanoHTTPCtxt ) ) ;
ret - > port = 80 ;
ret - > returnValue = 0 ;
2010-11-04 14:08:08 +03:00
ret - > fd = INVALID_SOCKET ;
2001-07-23 23:10:52 +04:00
ret - > ContentLength = - 1 ;
2001-02-23 20:55:21 +03:00
2003-01-10 19:09:51 +03:00
xmlNanoHTTPScanURL ( ret , URL ) ;
2001-02-23 20:55:21 +03:00
return ( ret ) ;
}
/**
* xmlNanoHTTPFreeCtxt :
* @ ctxt : an HTTP context
*
* Frees the context after closing the connection .
*/
static void
xmlNanoHTTPFreeCtxt ( xmlNanoHTTPCtxtPtr ctxt ) {
if ( ctxt = = NULL ) return ;
if ( ctxt - > hostname ! = NULL ) xmlFree ( ctxt - > hostname ) ;
if ( ctxt - > protocol ! = NULL ) xmlFree ( ctxt - > protocol ) ;
if ( ctxt - > path ! = NULL ) xmlFree ( ctxt - > path ) ;
2005-04-13 06:55:12 +04:00
if ( ctxt - > query ! = NULL ) xmlFree ( ctxt - > query ) ;
2001-02-23 20:55:21 +03:00
if ( ctxt - > out ! = NULL ) xmlFree ( ctxt - > out ) ;
if ( ctxt - > in ! = NULL ) xmlFree ( ctxt - > in ) ;
if ( ctxt - > contentType ! = NULL ) xmlFree ( ctxt - > contentType ) ;
2003-10-18 15:29:40 +04:00
if ( ctxt - > encoding ! = NULL ) xmlFree ( ctxt - > encoding ) ;
2003-10-19 17:35:37 +04:00
if ( ctxt - > mimeType ! = NULL ) xmlFree ( ctxt - > mimeType ) ;
2001-02-23 20:55:21 +03:00
if ( ctxt - > location ! = NULL ) xmlFree ( ctxt - > location ) ;
if ( ctxt - > authHeader ! = NULL ) xmlFree ( ctxt - > authHeader ) ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
if ( ctxt - > strm ! = NULL ) {
inflateEnd ( ctxt - > strm ) ;
xmlFree ( ctxt - > strm ) ;
}
# endif
2001-02-23 20:55:21 +03:00
ctxt - > state = XML_NANO_HTTP_NONE ;
2010-11-04 14:08:08 +03:00
if ( ctxt - > fd ! = INVALID_SOCKET ) closesocket ( ctxt - > fd ) ;
ctxt - > fd = INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
xmlFree ( ctxt ) ;
}
/**
* xmlNanoHTTPSend :
* @ ctxt : an HTTP context
*
* Send the input needed to initiate the processing on the server side
2001-07-23 23:10:52 +04:00
* Returns number of bytes sent or - 1 on error .
2001-02-23 20:55:21 +03:00
*/
2001-07-23 23:10:52 +04:00
static int
2009-08-23 15:11:01 +04:00
xmlNanoHTTPSend ( xmlNanoHTTPCtxtPtr ctxt , const char * xmt_ptr , int outlen )
{
int total_sent = 0 ;
# ifdef HAVE_POLL_H
struct pollfd p ;
# else
struct timeval tv ;
fd_set wfd ;
# endif
2001-07-23 23:10:52 +04:00
2009-08-23 15:11:01 +04:00
if ( ( ctxt - > state & XML_NANO_HTTP_WRITE ) & & ( xmt_ptr ! = NULL ) ) {
2001-07-23 23:10:52 +04:00
while ( total_sent < outlen ) {
2013-12-12 11:23:09 +04:00
int nsent = send ( ctxt - > fd , SEND_ARG2_CAST ( xmt_ptr + total_sent ) ,
2009-08-23 15:11:01 +04:00
outlen - total_sent , 0 ) ;
if ( nsent > 0 )
2001-02-23 20:55:21 +03:00
total_sent + = nsent ;
2009-08-23 15:11:01 +04:00
else if ( ( nsent = = - 1 ) & &
2001-07-31 20:25:45 +04:00
# if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
2009-08-23 15:11:01 +04:00
( socket_errno ( ) ! = EAGAIN ) & &
2001-07-31 20:25:45 +04:00
# endif
2009-08-23 15:11:01 +04:00
( socket_errno ( ) ! = EWOULDBLOCK ) ) {
__xmlIOErr ( XML_FROM_HTTP , 0 , " send failed \n " ) ;
if ( total_sent = = 0 )
total_sent = - 1 ;
break ;
} else {
/*
* No data sent
* Since non - blocking sockets are used , wait for
* socket to be writable or default timeout prior
* to retrying .
*/
# ifndef HAVE_POLL_H
2009-10-19 16:03:25 +04:00
# ifndef _WINSOCKAPI_
2009-08-23 15:11:01 +04:00
if ( ctxt - > fd > FD_SETSIZE )
return - 1 ;
2009-10-19 16:03:25 +04:00
# endif
2009-08-23 15:11:01 +04:00
tv . tv_sec = timeout ;
tv . tv_usec = 0 ;
FD_ZERO ( & wfd ) ;
2005-08-09 00:33:54 +04:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4018)
# endif
2009-08-23 15:11:01 +04:00
FD_SET ( ctxt - > fd , & wfd ) ;
2005-08-09 00:33:54 +04:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2009-08-23 15:11:01 +04:00
( void ) select ( ctxt - > fd + 1 , NULL , & wfd , NULL , & tv ) ;
# else
p . fd = ctxt - > fd ;
p . events = POLLOUT ;
( void ) poll ( & p , 1 , timeout * 1000 ) ;
# endif /* !HAVE_POLL_H */
}
}
2001-02-23 20:55:21 +03:00
}
2001-07-23 23:10:52 +04:00
return total_sent ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoHTTPRecv :
* @ ctxt : an HTTP context
*
* Read information coming from the HTTP connection .
* This is a blocking call ( but it blocks in select ( ) , not read ( ) ) .
*
* Returns the number of byte read or - 1 in case of error .
*/
static int
2009-08-23 15:11:01 +04:00
xmlNanoHTTPRecv ( xmlNanoHTTPCtxtPtr ctxt )
{
# ifdef HAVE_POLL_H
struct pollfd p ;
# else
2001-02-23 20:55:21 +03:00
fd_set rfd ;
struct timeval tv ;
2009-08-23 15:11:01 +04:00
# endif
2001-02-23 20:55:21 +03:00
while ( ctxt - > state & XML_NANO_HTTP_READ ) {
2009-08-23 15:11:01 +04:00
if ( ctxt - > in = = NULL ) {
2022-09-01 04:14:13 +03:00
ctxt - > in = ( char * ) xmlMallocAtomic ( 65000 ) ;
2009-08-23 15:11:01 +04:00
if ( ctxt - > in = = NULL ) {
xmlHTTPErrMemory ( " allocating input " ) ;
ctxt - > last = - 1 ;
return ( - 1 ) ;
}
ctxt - > inlen = 65000 ;
ctxt - > inptr = ctxt - > content = ctxt - > inrptr = ctxt - > in ;
}
if ( ctxt - > inrptr > ctxt - > in + XML_NANO_HTTP_CHUNK ) {
int delta = ctxt - > inrptr - ctxt - > in ;
int len = ctxt - > inptr - ctxt - > inrptr ;
memmove ( ctxt - > in , ctxt - > inrptr , len ) ;
ctxt - > inrptr - = delta ;
ctxt - > content - = delta ;
ctxt - > inptr - = delta ;
}
2001-02-23 20:55:21 +03:00
if ( ( ctxt - > in + ctxt - > inlen ) < ( ctxt - > inptr + XML_NANO_HTTP_CHUNK ) ) {
2009-08-23 15:11:01 +04:00
int d_inptr = ctxt - > inptr - ctxt - > in ;
int d_content = ctxt - > content - ctxt - > in ;
int d_inrptr = ctxt - > inrptr - ctxt - > in ;
char * tmp_ptr = ctxt - > in ;
2001-02-23 20:55:21 +03:00
2009-08-23 15:11:01 +04:00
ctxt - > inlen * = 2 ;
2001-07-23 23:10:52 +04:00
ctxt - > in = ( char * ) xmlRealloc ( tmp_ptr , ctxt - > inlen ) ;
2009-08-23 15:11:01 +04:00
if ( ctxt - > in = = NULL ) {
xmlHTTPErrMemory ( " allocating input buffer " ) ;
xmlFree ( tmp_ptr ) ;
ctxt - > last = - 1 ;
return ( - 1 ) ;
}
2001-02-23 20:55:21 +03:00
ctxt - > inptr = ctxt - > in + d_inptr ;
ctxt - > content = ctxt - > in + d_content ;
ctxt - > inrptr = ctxt - > in + d_inrptr ;
2009-08-23 15:11:01 +04:00
}
ctxt - > last = recv ( ctxt - > fd , ctxt - > inptr , XML_NANO_HTTP_CHUNK , 0 ) ;
if ( ctxt - > last > 0 ) {
ctxt - > inptr + = ctxt - > last ;
return ( ctxt - > last ) ;
}
if ( ctxt - > last = = 0 ) {
return ( 0 ) ;
}
if ( ctxt - > last = = - 1 ) {
switch ( socket_errno ( ) ) {
case EINPROGRESS :
case EWOULDBLOCK :
2001-02-23 20:55:21 +03:00
# if defined(EAGAIN) && EAGAIN != EWOULDBLOCK
2009-08-23 15:11:01 +04:00
case EAGAIN :
2001-02-23 20:55:21 +03:00
# endif
2009-08-23 15:11:01 +04:00
break ;
case ECONNRESET :
case ESHUTDOWN :
return ( 0 ) ;
default :
__xmlIOErr ( XML_FROM_HTTP , 0 , " recv failed \n " ) ;
return ( - 1 ) ;
}
}
# ifdef HAVE_POLL_H
p . fd = ctxt - > fd ;
p . events = POLLIN ;
if ( ( poll ( & p , 1 , timeout * 1000 ) < 1 )
# if defined(EINTR)
& & ( errno ! = EINTR )
# endif
)
return ( 0 ) ;
# else /* !HAVE_POLL_H */
2009-10-19 16:03:25 +04:00
# ifndef _WINSOCKAPI_
2009-08-23 15:11:01 +04:00
if ( ctxt - > fd > FD_SETSIZE )
return 0 ;
2009-10-19 16:03:25 +04:00
# endif
2001-07-23 23:10:52 +04:00
2009-08-23 15:11:01 +04:00
tv . tv_sec = timeout ;
tv . tv_usec = 0 ;
FD_ZERO ( & rfd ) ;
2001-07-23 23:10:52 +04:00
2005-08-09 00:33:54 +04:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4018)
# endif
2009-08-23 15:11:01 +04:00
FD_SET ( ctxt - > fd , & rfd ) ;
2005-08-09 00:33:54 +04:00
# ifdef _MSC_VER
# pragma warning(pop)
# endif
2009-08-23 15:11:01 +04:00
if ( ( select ( ctxt - > fd + 1 , & rfd , NULL , NULL , & tv ) < 1 )
2001-08-03 16:06:36 +04:00
# if defined(EINTR)
2017-10-09 01:05:04 +03:00
& & ( socket_errno ( ) ! = EINTR )
2001-08-03 16:06:36 +04:00
# endif
2009-08-23 15:11:01 +04:00
)
return ( 0 ) ;
# endif /* !HAVE_POLL_H */
2001-02-23 20:55:21 +03:00
}
2009-08-23 15:11:01 +04:00
return ( 0 ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoHTTPReadLine :
* @ ctxt : an HTTP context
*
* Read one line in the HTTP server output , usually for extracting
2020-03-08 19:19:42 +03:00
* the HTTP protocol information from the answer header .
2001-02-23 20:55:21 +03:00
*
* Returns a newly allocated string with a copy of the line , or NULL
* which indicate the end of the input .
*/
static char *
xmlNanoHTTPReadLine ( xmlNanoHTTPCtxtPtr ctxt ) {
char buf [ 4096 ] ;
char * bp = buf ;
2001-07-23 23:10:52 +04:00
int rc ;
2012-09-11 09:26:36 +04:00
2001-02-23 20:55:21 +03:00
while ( bp - buf < 4095 ) {
if ( ctxt - > inrptr = = ctxt - > inptr ) {
2001-07-23 23:10:52 +04:00
if ( ( rc = xmlNanoHTTPRecv ( ctxt ) ) = = 0 ) {
2001-02-23 20:55:21 +03:00
if ( bp = = buf )
return ( NULL ) ;
else
* bp = 0 ;
return ( xmlMemStrdup ( buf ) ) ;
}
2001-07-23 23:10:52 +04:00
else if ( rc = = - 1 ) {
return ( NULL ) ;
}
2001-02-23 20:55:21 +03:00
}
* bp = * ctxt - > inrptr + + ;
if ( * bp = = ' \n ' ) {
* bp = 0 ;
return ( xmlMemStrdup ( buf ) ) ;
}
if ( * bp ! = ' \r ' )
bp + + ;
}
buf [ 4095 ] = 0 ;
return ( xmlMemStrdup ( buf ) ) ;
}
/**
* xmlNanoHTTPScanAnswer :
* @ ctxt : an HTTP context
* @ line : an HTTP header line
*
2020-03-08 19:19:42 +03:00
* Try to extract useful information from the server answer .
2001-02-23 20:55:21 +03:00
* We currently parse and process :
* - The HTTP revision / return code
2003-10-19 17:35:37 +04:00
* - The Content - Type , Mime - Type and charset used
2001-12-31 19:16:02 +03:00
* - The Location for redirect processing .
2001-02-23 20:55:21 +03:00
*
* Returns - 1 in case of failure , the file descriptor number otherwise
*/
static void
xmlNanoHTTPScanAnswer ( xmlNanoHTTPCtxtPtr ctxt , const char * line ) {
const char * cur = line ;
if ( line = = NULL ) return ;
if ( ! strncmp ( line , " HTTP/ " , 5 ) ) {
int version = 0 ;
int ret = 0 ;
cur + = 5 ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) {
version * = 10 ;
version + = * cur - ' 0 ' ;
cur + + ;
}
if ( * cur = = ' . ' ) {
cur + + ;
if ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) {
version * = 10 ;
version + = * cur - ' 0 ' ;
cur + + ;
}
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) )
cur + + ;
} else
version * = 10 ;
if ( ( * cur ! = ' ' ) & & ( * cur ! = ' \t ' ) ) return ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
if ( ( * cur < ' 0 ' ) | | ( * cur > ' 9 ' ) ) return ;
while ( ( * cur > = ' 0 ' ) & & ( * cur < = ' 9 ' ) ) {
ret * = 10 ;
ret + = * cur - ' 0 ' ;
cur + + ;
}
if ( ( * cur ! = 0 ) & & ( * cur ! = ' ' ) & & ( * cur ! = ' \t ' ) ) return ;
ctxt - > returnValue = ret ;
2009-09-05 16:52:55 +04:00
ctxt - > version = version ;
2001-02-23 20:55:21 +03:00
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " Content-Type: " , 13 ) ) {
2003-10-19 17:35:37 +04:00
const xmlChar * charset , * last , * mime ;
2001-02-23 20:55:21 +03:00
cur + = 13 ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
if ( ctxt - > contentType ! = NULL )
xmlFree ( ctxt - > contentType ) ;
ctxt - > contentType = xmlMemStrdup ( cur ) ;
2003-10-19 17:35:37 +04:00
mime = ( const xmlChar * ) cur ;
last = mime ;
while ( ( * last ! = 0 ) & & ( * last ! = ' ' ) & & ( * last ! = ' \t ' ) & &
( * last ! = ' ; ' ) & & ( * last ! = ' , ' ) )
last + + ;
if ( ctxt - > mimeType ! = NULL )
xmlFree ( ctxt - > mimeType ) ;
ctxt - > mimeType = ( char * ) xmlStrndup ( mime , last - mime ) ;
charset = xmlStrstr ( BAD_CAST ctxt - > contentType , BAD_CAST " charset= " ) ;
if ( charset ! = NULL ) {
charset + = 8 ;
last = charset ;
while ( ( * last ! = 0 ) & & ( * last ! = ' ' ) & & ( * last ! = ' \t ' ) & &
( * last ! = ' ; ' ) & & ( * last ! = ' , ' ) )
last + + ;
if ( ctxt - > encoding ! = NULL )
xmlFree ( ctxt - > encoding ) ;
ctxt - > encoding = ( char * ) xmlStrndup ( charset , last - charset ) ;
}
2001-02-23 20:55:21 +03:00
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " ContentType: " , 12 ) ) {
2003-10-19 17:35:37 +04:00
const xmlChar * charset , * last , * mime ;
2001-02-23 20:55:21 +03:00
cur + = 12 ;
if ( ctxt - > contentType ! = NULL ) return ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
ctxt - > contentType = xmlMemStrdup ( cur ) ;
2003-10-19 17:35:37 +04:00
mime = ( const xmlChar * ) cur ;
last = mime ;
while ( ( * last ! = 0 ) & & ( * last ! = ' ' ) & & ( * last ! = ' \t ' ) & &
( * last ! = ' ; ' ) & & ( * last ! = ' , ' ) )
last + + ;
if ( ctxt - > mimeType ! = NULL )
xmlFree ( ctxt - > mimeType ) ;
ctxt - > mimeType = ( char * ) xmlStrndup ( mime , last - mime ) ;
charset = xmlStrstr ( BAD_CAST ctxt - > contentType , BAD_CAST " charset= " ) ;
if ( charset ! = NULL ) {
charset + = 8 ;
last = charset ;
while ( ( * last ! = 0 ) & & ( * last ! = ' ' ) & & ( * last ! = ' \t ' ) & &
( * last ! = ' ; ' ) & & ( * last ! = ' , ' ) )
last + + ;
if ( ctxt - > encoding ! = NULL )
xmlFree ( ctxt - > encoding ) ;
ctxt - > encoding = ( char * ) xmlStrndup ( charset , last - charset ) ;
}
2001-02-23 20:55:21 +03:00
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " Location: " , 9 ) ) {
cur + = 9 ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
if ( ctxt - > location ! = NULL )
xmlFree ( ctxt - > location ) ;
2004-04-02 13:07:22 +04:00
if ( * cur = = ' / ' ) {
xmlChar * tmp_http = xmlStrdup ( BAD_CAST " http:// " ) ;
2012-09-11 09:26:36 +04:00
xmlChar * tmp_loc =
2004-04-02 13:07:22 +04:00
xmlStrcat ( tmp_http , ( const xmlChar * ) ctxt - > hostname ) ;
2012-09-11 09:26:36 +04:00
ctxt - > location =
2004-04-02 13:07:22 +04:00
( char * ) xmlStrcat ( tmp_loc , ( const xmlChar * ) cur ) ;
} else {
ctxt - > location = xmlMemStrdup ( cur ) ;
}
2001-02-23 20:55:21 +03:00
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " WWW-Authenticate: " , 17 ) ) {
cur + = 17 ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
if ( ctxt - > authHeader ! = NULL )
xmlFree ( ctxt - > authHeader ) ;
ctxt - > authHeader = xmlMemStrdup ( cur ) ;
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " Proxy-Authenticate: " , 19 ) ) {
cur + = 19 ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
if ( ctxt - > authHeader ! = NULL )
xmlFree ( ctxt - > authHeader ) ;
ctxt - > authHeader = xmlMemStrdup ( cur ) ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " Content-Encoding: " , 17 ) ) {
cur + = 17 ;
while ( ( * cur = = ' ' ) | | ( * cur = = ' \t ' ) ) cur + + ;
if ( ! xmlStrncasecmp ( BAD_CAST cur , BAD_CAST " gzip " , 4 ) ) {
ctxt - > usesGzip = 1 ;
ctxt - > strm = xmlMalloc ( sizeof ( z_stream ) ) ;
if ( ctxt - > strm ! = NULL ) {
ctxt - > strm - > zalloc = Z_NULL ;
ctxt - > strm - > zfree = Z_NULL ;
ctxt - > strm - > opaque = Z_NULL ;
ctxt - > strm - > avail_in = 0 ;
ctxt - > strm - > next_in = Z_NULL ;
inflateInit2 ( ctxt - > strm , 31 ) ;
}
}
# endif
2001-07-23 23:10:52 +04:00
} else if ( ! xmlStrncasecmp ( BAD_CAST line , BAD_CAST " Content-Length: " , 15 ) ) {
cur + = 15 ;
ctxt - > ContentLength = strtol ( cur , NULL , 10 ) ;
2001-02-23 20:55:21 +03:00
}
}
/**
* xmlNanoHTTPConnectAttempt :
2001-12-31 19:16:02 +03:00
* @ addr : a socket address structure
2001-02-23 20:55:21 +03:00
*
* Attempt a connection to the given IP : port endpoint . It forces
* non - blocking semantic on the socket , and allow 60 seconds for
* the host to answer .
*
* Returns - 1 in case of failure , the file descriptor number otherwise
*/
2010-11-04 14:08:08 +03:00
static SOCKET
2001-03-24 20:00:36 +03:00
xmlNanoHTTPConnectAttempt ( struct sockaddr * addr )
2001-02-23 20:55:21 +03:00
{
2009-08-23 15:11:01 +04:00
# ifndef HAVE_POLL_H
2001-02-23 20:55:21 +03:00
fd_set wfd ;
2004-02-09 15:39:02 +03:00
# ifdef _WINSOCKAPI_
fd_set xfd ;
# endif
2001-02-23 20:55:21 +03:00
struct timeval tv ;
2009-08-23 15:11:01 +04:00
# else /* !HAVE_POLL_H */
struct pollfd p ;
# endif /* !HAVE_POLL_H */
2001-02-23 20:55:21 +03:00
int status ;
2009-08-23 15:11:01 +04:00
2003-06-21 18:20:04 +04:00
int addrlen ;
2009-08-23 15:11:01 +04:00
2003-06-21 18:20:04 +04:00
SOCKET s ;
2009-08-23 15:11:01 +04:00
2003-06-21 18:20:04 +04:00
# ifdef SUPPORT_IP6
if ( addr - > sa_family = = AF_INET6 ) {
2009-08-23 15:11:01 +04:00
s = socket ( PF_INET6 , SOCK_STREAM , IPPROTO_TCP ) ;
addrlen = sizeof ( struct sockaddr_in6 ) ;
} else
2003-06-21 18:20:04 +04:00
# endif
{
2009-08-23 15:11:01 +04:00
s = socket ( PF_INET , SOCK_STREAM , IPPROTO_TCP ) ;
addrlen = sizeof ( struct sockaddr_in ) ;
2003-06-21 18:20:04 +04:00
}
2010-11-04 14:08:08 +03:00
if ( s = = INVALID_SOCKET ) {
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_HTTP
2009-08-23 15:11:01 +04:00
perror ( " socket " ) ;
2001-02-23 20:55:21 +03:00
# endif
2009-08-23 15:11:01 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , " socket failed \n " ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
# ifdef _WINSOCKAPI_
{
2009-08-23 15:11:01 +04:00
u_long one = 1 ;
2001-02-23 20:55:21 +03:00
2009-08-23 15:11:01 +04:00
status = ioctlsocket ( s , FIONBIO , & one ) = = SOCKET_ERROR ? - 1 : 0 ;
2001-02-23 20:55:21 +03:00
}
# else /* _WINSOCKAPI_ */
# if defined(VMS)
{
2009-08-23 15:11:01 +04:00
int enable = 1 ;
status = ioctl ( s , FIONBIO , & enable ) ;
2001-02-23 20:55:21 +03:00
}
# else /* VMS */
if ( ( status = fcntl ( s , F_GETFL , 0 ) ) ! = - 1 ) {
# ifdef O_NONBLOCK
2009-08-23 15:11:01 +04:00
status | = O_NONBLOCK ;
2001-02-23 20:55:21 +03:00
# else /* O_NONBLOCK */
# ifdef F_NDELAY
2009-08-23 15:11:01 +04:00
status | = F_NDELAY ;
2001-02-23 20:55:21 +03:00
# endif /* F_NDELAY */
# endif /* !O_NONBLOCK */
2009-08-23 15:11:01 +04:00
status = fcntl ( s , F_SETFL , status ) ;
2001-02-23 20:55:21 +03:00
}
if ( status < 0 ) {
# ifdef DEBUG_HTTP
2009-08-23 15:11:01 +04:00
perror ( " nonblocking " ) ;
2001-02-23 20:55:21 +03:00
# endif
2009-08-23 15:11:01 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , " error setting non-blocking IO \n " ) ;
closesocket ( s ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
# endif /* !VMS */
# endif /* !_WINSOCKAPI_ */
2009-08-23 15:11:01 +04:00
if ( connect ( s , addr , addrlen ) = = - 1 ) {
switch ( socket_errno ( ) ) {
case EINPROGRESS :
case EWOULDBLOCK :
break ;
default :
__xmlIOErr ( XML_FROM_HTTP , 0 ,
" error connecting to HTTP server " ) ;
closesocket ( s ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2009-08-23 15:11:01 +04:00
}
}
# ifndef HAVE_POLL_H
2001-02-23 20:55:21 +03:00
tv . tv_sec = timeout ;
tv . tv_usec = 0 ;
2005-08-09 00:33:54 +04:00
# ifdef _MSC_VER
# pragma warning(push)
# pragma warning(disable: 4018)
# endif
2009-10-19 16:03:25 +04:00
# ifndef _WINSOCKAPI_
2009-08-23 15:11:01 +04:00
if ( s > FD_SETSIZE )
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2009-10-19 16:03:25 +04:00
# endif
2001-02-23 20:55:21 +03:00
FD_ZERO ( & wfd ) ;
FD_SET ( s , & wfd ) ;
2004-02-09 15:39:02 +03:00
2009-08-23 15:11:01 +04:00
# ifdef _WINSOCKAPI_
2004-02-09 15:39:02 +03:00
FD_ZERO ( & xfd ) ;
FD_SET ( s , & xfd ) ;
2009-08-23 15:11:01 +04:00
switch ( select ( s + 1 , NULL , & wfd , & xfd , & tv ) )
2004-02-09 15:39:02 +03:00
# else
2009-08-23 15:11:01 +04:00
switch ( select ( s + 1 , NULL , & wfd , NULL , & tv ) )
2005-08-09 00:33:54 +04:00
# endif
# ifdef _MSC_VER
# pragma warning(pop)
2004-02-09 15:39:02 +03:00
# endif
2009-08-23 15:11:01 +04:00
# else /* !HAVE_POLL_H */
p . fd = s ;
p . events = POLLOUT ;
switch ( poll ( & p , 1 , timeout * 1000 ) )
# endif /* !HAVE_POLL_H */
2001-02-23 20:55:21 +03:00
{
2009-08-23 15:11:01 +04:00
case 0 :
/* Time out */
__xmlIOErr ( XML_FROM_HTTP , 0 , " Connect attempt timed out " ) ;
closesocket ( s ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2009-08-23 15:11:01 +04:00
case - 1 :
/* Ermm.. ?? */
__xmlIOErr ( XML_FROM_HTTP , 0 , " Connect failed " ) ;
closesocket ( s ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
2009-08-23 15:11:01 +04:00
# ifndef HAVE_POLL_H
if ( FD_ISSET ( s , & wfd )
2004-02-09 15:39:02 +03:00
# ifdef _WINSOCKAPI_
2009-08-23 15:11:01 +04:00
| | FD_ISSET ( s , & xfd )
2004-02-09 15:39:02 +03:00
# endif
2009-08-23 15:11:01 +04:00
)
# else /* !HAVE_POLL_H */
if ( p . revents = = POLLOUT )
# endif /* !HAVE_POLL_H */
{
XML_SOCKLEN_T len ;
len = sizeof ( status ) ;
2003-09-29 17:20:24 +04:00
# ifdef SO_ERROR
2009-08-23 15:11:01 +04:00
if ( getsockopt ( s , SOL_SOCKET , SO_ERROR , ( char * ) & status , & len ) <
0 ) {
/* Solaris error code */
__xmlIOErr ( XML_FROM_HTTP , 0 , " getsockopt failed \n " ) ;
2013-08-06 10:49:42 +04:00
closesocket ( s ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2009-08-23 15:11:01 +04:00
}
2003-09-29 17:20:24 +04:00
# endif
2009-08-23 15:11:01 +04:00
if ( status ) {
__xmlIOErr ( XML_FROM_HTTP , 0 ,
" Error connecting to remote host " ) ;
closesocket ( s ) ;
errno = status ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2009-08-23 15:11:01 +04:00
}
2001-02-23 20:55:21 +03:00
} else {
2009-08-23 15:11:01 +04:00
/* pbm */
__xmlIOErr ( XML_FROM_HTTP , 0 , " select failed \n " ) ;
closesocket ( s ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
2009-08-23 15:11:01 +04:00
return ( s ) ;
2001-02-23 20:55:21 +03:00
}
2009-08-23 15:11:01 +04:00
2001-02-23 20:55:21 +03:00
/**
* xmlNanoHTTPConnectHost :
* @ host : the host name
* @ port : the port number
*
* Attempt a connection to the given host : port endpoint . It tries
* the multiple IP provided by the DNS if available .
*
* Returns - 1 in case of failure , the file descriptor number otherwise
*/
2010-11-04 14:08:08 +03:00
static SOCKET
2001-02-23 20:55:21 +03:00
xmlNanoHTTPConnectHost ( const char * host , int port )
{
2003-07-08 16:16:59 +04:00
struct sockaddr * addr = NULL ;
2001-03-24 20:00:36 +03:00
struct sockaddr_in sockin ;
2002-03-15 10:57:50 +03:00
2001-02-23 20:55:21 +03:00
# ifdef SUPPORT_IP6
2001-03-24 20:00:36 +03:00
struct sockaddr_in6 sockin6 ;
2001-02-23 20:55:21 +03:00
# endif
2010-11-04 14:08:08 +03:00
SOCKET s ;
2002-03-15 10:57:50 +03:00
2003-06-21 18:20:04 +04:00
memset ( & sockin , 0 , sizeof ( sockin ) ) ;
2005-10-14 03:12:42 +04:00
2022-09-05 03:02:54 +03:00
# if defined(SUPPORT_IP6)
2003-07-07 01:13:49 +04:00
{
2003-06-21 18:20:04 +04:00
int status ;
struct addrinfo hints , * res , * result ;
2022-09-05 03:02:54 +03:00
memset ( & sockin6 , 0 , sizeof ( sockin6 ) ) ;
2003-06-21 18:20:04 +04:00
result = NULL ;
memset ( & hints , 0 , sizeof ( hints ) ) ;
hints . ai_socktype = SOCK_STREAM ;
status = getaddrinfo ( host , NULL , & hints , & result ) ;
if ( status ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , " getaddrinfo failed \n " ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
for ( res = result ; res ; res = res - > ai_next ) {
2005-10-14 03:12:42 +04:00
if ( res - > ai_family = = AF_INET ) {
2017-10-21 15:01:10 +03:00
if ( ( size_t ) res - > ai_addrlen > sizeof ( sockin ) ) {
2005-10-14 03:12:42 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , " address size mismatch \n " ) ;
freeaddrinfo ( result ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
2005-10-14 03:12:42 +04:00
memcpy ( & sockin , res - > ai_addr , res - > ai_addrlen ) ;
sockin . sin_port = htons ( port ) ;
addr = ( struct sockaddr * ) & sockin ;
2022-09-05 03:02:54 +03:00
} else if ( res - > ai_family = = AF_INET6 ) {
2017-10-21 15:01:10 +03:00
if ( ( size_t ) res - > ai_addrlen > sizeof ( sockin6 ) ) {
2005-10-14 03:12:42 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , " address size mismatch \n " ) ;
2003-06-21 18:20:04 +04:00
freeaddrinfo ( result ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
2005-10-14 03:12:42 +04:00
memcpy ( & sockin6 , res - > ai_addr , res - > ai_addrlen ) ;
sockin6 . sin6_port = htons ( port ) ;
addr = ( struct sockaddr * ) & sockin6 ;
} else
continue ; /* for */
s = xmlNanoHTTPConnectAttempt ( addr ) ;
2010-11-04 14:08:08 +03:00
if ( s ! = INVALID_SOCKET ) {
2005-10-14 03:12:42 +04:00
freeaddrinfo ( result ) ;
return ( s ) ;
2003-06-21 18:20:04 +04:00
}
}
2005-10-14 03:12:42 +04:00
2003-07-10 18:04:33 +04:00
if ( result )
freeaddrinfo ( result ) ;
2005-10-14 03:12:42 +04:00
}
2022-09-05 03:02:54 +03:00
# else
2005-10-14 03:12:42 +04:00
{
2017-10-09 03:01:00 +03:00
struct hostent * h ;
struct in_addr ia ;
int i ;
2013-12-12 11:23:09 +04:00
h = gethostbyname ( GETHOSTBYNAME_ARG_CAST host ) ;
2003-06-21 18:20:04 +04:00
if ( h = = NULL ) {
2002-03-25 19:35:28 +03:00
/*
* Okay , I got fed up by the non - portability of this error message
* extraction code . it work on Linux , if it work on your platform
* and one want to enable it , send me the defined ( foobar ) needed
*/
2017-09-14 22:30:51 +03:00
# if defined(HAVE_NETDB_H) && defined(HOST_NOT_FOUND) && defined(__linux__)
2003-06-21 18:20:04 +04:00
const char * h_err_txt = " " ;
switch ( h_errno ) {
case HOST_NOT_FOUND :
2019-09-30 18:04:54 +03:00
h_err_txt = " Authoritative host not found " ;
2003-06-21 18:20:04 +04:00
break ;
case TRY_AGAIN :
h_err_txt =
2019-09-30 18:04:54 +03:00
" Non-authoritative host not found or server failure. " ;
2003-06-21 18:20:04 +04:00
break ;
case NO_RECOVERY :
h_err_txt =
" Non-recoverable errors: FORMERR, REFUSED, or NOTIMP. " ;
break ;
2012-04-02 13:48:53 +04:00
# ifdef NO_ADDRESS
2003-06-21 18:20:04 +04:00
case NO_ADDRESS :
h_err_txt =
" Valid name, no data record of requested type. " ;
break ;
2012-04-02 13:48:53 +04:00
# endif
2003-06-21 18:20:04 +04:00
default :
h_err_txt = " No error text defined. " ;
break ;
}
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , h_err_txt ) ;
2002-03-15 10:57:50 +03:00
# else
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_HTTP , 0 , " Failed to resolve host " ) ;
2002-03-15 10:57:50 +03:00
# endif
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2003-06-21 18:20:04 +04:00
}
2002-03-15 10:57:50 +03:00
2003-06-21 18:20:04 +04:00
for ( i = 0 ; h - > h_addr_list [ i ] ; i + + ) {
if ( h - > h_addrtype = = AF_INET ) {
/* A records (IPv4) */
2004-10-27 13:39:50 +04:00
if ( ( unsigned int ) h - > h_length > sizeof ( ia ) ) {
__xmlIOErr ( XML_FROM_HTTP , 0 , " address size mismatch \n " ) ;
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2004-10-27 13:39:50 +04:00
}
2003-06-21 18:20:04 +04:00
memcpy ( & ia , h - > h_addr_list [ i ] , h - > h_length ) ;
sockin . sin_family = h - > h_addrtype ;
sockin . sin_addr = ia ;
2012-04-02 11:45:13 +04:00
sockin . sin_port = ( unsigned short ) htons ( ( unsigned short ) port ) ;
2003-06-21 18:20:04 +04:00
addr = ( struct sockaddr * ) & sockin ;
} else
break ; /* for */
2001-02-23 20:55:21 +03:00
2003-06-21 18:20:04 +04:00
s = xmlNanoHTTPConnectAttempt ( addr ) ;
2010-11-04 14:08:08 +03:00
if ( s ! = INVALID_SOCKET )
2003-06-21 18:20:04 +04:00
return ( s ) ;
}
}
2005-10-14 03:12:42 +04:00
# endif
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_HTTP
xmlGenericError ( xmlGenericErrorContext ,
2002-03-15 10:57:50 +03:00
" xmlNanoHTTPConnectHost: unable to connect to '%s'. \n " ,
host ) ;
2001-02-23 20:55:21 +03:00
# endif
2010-11-04 14:08:08 +03:00
return INVALID_SOCKET ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoHTTPOpen :
* @ URL : The URL to load
* @ contentType : if available the Content - Type information will be
* returned at that location
*
* This function try to open a connection to the indicated resource
* via HTTP GET .
*
* Returns NULL in case of failure , otherwise a request handler .
* The contentType , if provided must be freed by the caller
*/
void *
xmlNanoHTTPOpen ( const char * URL , char * * contentType ) {
if ( contentType ! = NULL ) * contentType = NULL ;
2001-07-23 23:10:52 +04:00
return ( xmlNanoHTTPMethod ( URL , NULL , NULL , contentType , NULL , 0 ) ) ;
2001-05-28 15:00:53 +04:00
}
/**
* xmlNanoHTTPOpenRedir :
* @ URL : The URL to load
* @ contentType : if available the Content - Type information will be
* returned at that location
2001-12-31 19:16:02 +03:00
* @ redir : if available the redirected URL will be returned
2001-05-28 15:00:53 +04:00
*
* This function try to open a connection to the indicated resource
* via HTTP GET .
*
* Returns NULL in case of failure , otherwise a request handler .
* The contentType , if provided must be freed by the caller
*/
void *
xmlNanoHTTPOpenRedir ( const char * URL , char * * contentType , char * * redir ) {
if ( contentType ! = NULL ) * contentType = NULL ;
if ( redir ! = NULL ) * redir = NULL ;
2001-07-23 23:10:52 +04:00
return ( xmlNanoHTTPMethodRedir ( URL , NULL , NULL , contentType , redir , NULL , 0 ) ) ;
2001-02-23 20:55:21 +03:00
}
/**
* xmlNanoHTTPRead :
* @ ctx : the HTTP context
* @ dest : a buffer
* @ len : the buffer length
*
* This function tries to read @ len bytes from the existing HTTP connection
* and saves them in @ dest . This is a blocking call .
*
* Returns the number of byte read . 0 is an indication of an end of connection .
* - 1 indicates a parameter error .
*/
int
xmlNanoHTTPRead ( void * ctx , void * dest , int len ) {
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
int bytes_read = 0 ;
int orig_avail_in ;
int z_ret ;
# endif
2001-02-23 20:55:21 +03:00
if ( ctx = = NULL ) return ( - 1 ) ;
if ( dest = = NULL ) return ( - 1 ) ;
if ( len < = 0 ) return ( 0 ) ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
if ( ctxt - > usesGzip = = 1 ) {
if ( ctxt - > strm = = NULL ) return ( 0 ) ;
2012-09-11 09:26:36 +04:00
2005-12-15 14:12:26 +03:00
ctxt - > strm - > next_out = dest ;
ctxt - > strm - > avail_out = len ;
2007-05-16 09:19:13 +04:00
ctxt - > strm - > avail_in = ctxt - > inptr - ctxt - > inrptr ;
2005-12-15 14:12:26 +03:00
2007-05-16 09:19:13 +04:00
while ( ctxt - > strm - > avail_out > 0 & &
( ctxt - > strm - > avail_in > 0 | | xmlNanoHTTPRecv ( ctxt ) > 0 ) ) {
2007-05-15 23:42:08 +04:00
orig_avail_in = ctxt - > strm - > avail_in =
ctxt - > inptr - ctxt - > inrptr - bytes_read ;
2005-12-15 14:12:26 +03:00
ctxt - > strm - > next_in = BAD_CAST ( ctxt - > inrptr + bytes_read ) ;
z_ret = inflate ( ctxt - > strm , Z_NO_FLUSH ) ;
bytes_read + = orig_avail_in - ctxt - > strm - > avail_in ;
if ( z_ret ! = Z_OK ) break ;
2007-05-15 23:42:08 +04:00
}
2005-12-15 14:12:26 +03:00
ctxt - > inrptr + = bytes_read ;
return ( len - ctxt - > strm - > avail_out ) ;
}
# endif
2001-02-23 20:55:21 +03:00
while ( ctxt - > inptr - ctxt - > inrptr < len ) {
2001-07-23 23:10:52 +04:00
if ( xmlNanoHTTPRecv ( ctxt ) < = 0 ) break ;
2001-02-23 20:55:21 +03:00
}
if ( ctxt - > inptr - ctxt - > inrptr < len )
len = ctxt - > inptr - ctxt - > inrptr ;
memcpy ( dest , ctxt - > inrptr , len ) ;
ctxt - > inrptr + = len ;
return ( len ) ;
}
/**
* xmlNanoHTTPClose :
* @ ctx : the HTTP context
*
* This function closes an HTTP context , it ends up the connection and
* free all data related to it .
*/
void
xmlNanoHTTPClose ( void * ctx ) {
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
if ( ctx = = NULL ) return ;
xmlNanoHTTPFreeCtxt ( ctxt ) ;
}
2022-11-04 15:34:39 +03:00
/**
* xmlNanoHTTPHostnameMatch :
* @ pattern : The pattern as it appears in no_proxy environment variable
* @ hostname : The hostname to test as it appears in the URL
*
* This function tests whether a given hostname matches a pattern . The pattern
* usually is a token from the no_proxy environment variable . Wildcards in the
* pattern are not supported .
*
* Returns true , iff hostname matches the pattern .
*/
static int
xmlNanoHTTPHostnameMatch ( const char * pattern , const char * hostname ) {
int idx_pattern , idx_hostname ;
const char * pattern_start ;
if ( ! pattern | | * pattern = = ' \0 ' | | ! hostname )
return 0 ;
/* Ignore trailing '.' */
if ( * pattern = = ' . ' ) {
idx_pattern = strlen ( pattern ) - 1 ;
pattern_start = pattern + 1 ;
}
else {
idx_pattern = strlen ( pattern ) ;
pattern_start = pattern ;
}
idx_hostname = strlen ( hostname ) ;
for ( ; idx_pattern > = 0 & & idx_hostname > = 0 ;
- - idx_pattern , - - idx_hostname ) {
if ( tolower ( pattern_start [ idx_pattern ] ) ! = tolower ( hostname [ idx_hostname ] ) )
break ;
}
return idx_pattern = = - 1 & & ( idx_hostname = = - 1 | | hostname [ idx_hostname ] = = ' . ' ) ;
}
/**
* xmlNanoHTTPBypassProxy :
* @ hostname : The hostname as it appears in the URL
*
* This function evaluates the no_proxy environment variable and returns
* whether the proxy server should be bypassed for a given host .
*
* Returns true , iff a proxy server should be bypassed for the given hostname .
*/
static int
xmlNanoHTTPBypassProxy ( const char * hostname ) {
size_t envlen ;
char * env = getenv ( " no_proxy " ) , * cpy = NULL , * p = NULL ;
if ( ! env )
return 0 ;
/* (Avoid strdup because it's not portable.) */
envlen = strlen ( env ) + 1 ;
cpy = xmlMalloc ( envlen ) ;
memcpy ( cpy , env , envlen ) ;
env = cpy ;
/* The remainder of the function is basically a tokenizing: */
while ( isspace ( * env ) )
+ + env ;
if ( * env = = ' \0 ' ) {
xmlFree ( cpy ) ;
return 0 ;
}
p = env ;
while ( * env ) {
if ( * env ! = ' , ' ) {
+ + env ;
continue ;
}
* ( env + + ) = ' \0 ' ;
if ( xmlNanoHTTPHostnameMatch ( p , hostname ) ) {
xmlFree ( cpy ) ;
return 1 ;
}
while ( isspace ( * env ) )
+ + env ;
p = env ;
}
if ( xmlNanoHTTPHostnameMatch ( p , hostname ) ) {
xmlFree ( cpy ) ;
return 1 ;
}
xmlFree ( cpy ) ;
return 0 ;
}
2001-02-23 20:55:21 +03:00
/**
2001-05-28 15:00:53 +04:00
* xmlNanoHTTPMethodRedir :
2001-02-23 20:55:21 +03:00
* @ URL : The URL to load
* @ method : the HTTP method to use
* @ input : the input string if any
* @ contentType : the Content - Type information IN and OUT
2001-05-28 15:00:53 +04:00
* @ redir : the redirected URL OUT
2001-02-23 20:55:21 +03:00
* @ headers : the extra headers
2001-12-31 19:16:02 +03:00
* @ ilen : input length
2001-02-23 20:55:21 +03:00
*
* This function try to open a connection to the indicated resource
* via HTTP using the given @ method , adding the given extra headers
* and the input buffer for the request content .
*
* Returns NULL in case of failure , otherwise a request handler .
2001-05-28 15:00:53 +04:00
* The contentType , or redir , if provided must be freed by the caller
2001-02-23 20:55:21 +03:00
*/
void *
2001-05-28 15:00:53 +04:00
xmlNanoHTTPMethodRedir ( const char * URL , const char * method , const char * input ,
2001-07-23 23:10:52 +04:00
char * * contentType , char * * redir ,
const char * headers , int ilen ) {
2001-02-23 20:55:21 +03:00
xmlNanoHTTPCtxtPtr ctxt ;
char * bp , * p ;
2010-11-04 14:08:08 +03:00
int blen ;
SOCKET ret ;
2001-02-23 20:55:21 +03:00
int nbRedirects = 0 ;
2022-11-04 15:34:39 +03:00
int use_proxy ;
2001-02-23 20:55:21 +03:00
char * redirURL = NULL ;
2003-07-31 18:47:38 +04:00
# ifdef DEBUG_HTTP
int xmt_bytes ;
# endif
2012-09-11 09:26:36 +04:00
2001-02-23 20:55:21 +03:00
if ( URL = = NULL ) return ( NULL ) ;
if ( method = = NULL ) method = " GET " ;
xmlNanoHTTPInit ( ) ;
retry :
2014-07-14 13:50:27 +04:00
if ( redirURL = = NULL ) {
2001-02-23 20:55:21 +03:00
ctxt = xmlNanoHTTPNewCtxt ( URL ) ;
2014-07-14 13:50:27 +04:00
if ( ctxt = = NULL )
return ( NULL ) ;
} else {
2001-02-23 20:55:21 +03:00
ctxt = xmlNanoHTTPNewCtxt ( redirURL ) ;
2014-07-14 13:50:27 +04:00
if ( ctxt = = NULL )
return ( NULL ) ;
2003-10-19 17:35:37 +04:00
ctxt - > location = xmlMemStrdup ( redirURL ) ;
2001-02-23 20:55:21 +03:00
}
if ( ( ctxt - > protocol = = NULL ) | | ( strcmp ( ctxt - > protocol , " http " ) ) ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_HTTP , XML_HTTP_URL_SYNTAX , " Not a valid HTTP URI " ) ;
2001-02-23 20:55:21 +03:00
xmlNanoHTTPFreeCtxt ( ctxt ) ;
if ( redirURL ! = NULL ) xmlFree ( redirURL ) ;
return ( NULL ) ;
}
if ( ctxt - > hostname = = NULL ) {
2003-10-10 23:36:36 +04:00
__xmlIOErr ( XML_FROM_HTTP , XML_HTTP_UNKNOWN_HOST ,
" Failed to identify host in URI " ) ;
2001-02-23 20:55:21 +03:00
xmlNanoHTTPFreeCtxt ( ctxt ) ;
2001-05-28 15:00:53 +04:00
if ( redirURL ! = NULL ) xmlFree ( redirURL ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
2022-11-04 15:34:39 +03:00
use_proxy = proxy & & ! xmlNanoHTTPBypassProxy ( ctxt - > hostname ) ;
if ( use_proxy ) {
2001-02-23 20:55:21 +03:00
blen = strlen ( ctxt - > hostname ) * 2 + 16 ;
ret = xmlNanoHTTPConnectHost ( proxy , proxyPort ) ;
}
else {
blen = strlen ( ctxt - > hostname ) ;
ret = xmlNanoHTTPConnectHost ( ctxt - > hostname , ctxt - > port ) ;
}
2010-11-04 14:08:08 +03:00
if ( ret = = INVALID_SOCKET ) {
2001-02-23 20:55:21 +03:00
xmlNanoHTTPFreeCtxt ( ctxt ) ;
2001-05-28 15:00:53 +04:00
if ( redirURL ! = NULL ) xmlFree ( redirURL ) ;
2001-02-23 20:55:21 +03:00
return ( NULL ) ;
}
ctxt - > fd = ret ;
2001-07-23 23:10:52 +04:00
if ( input = = NULL )
2001-02-23 20:55:21 +03:00
ilen = 0 ;
2001-07-23 23:10:52 +04:00
else
blen + = 36 ;
2001-02-23 20:55:21 +03:00
if ( headers ! = NULL )
2001-07-23 23:10:52 +04:00
blen + = strlen ( headers ) + 2 ;
2001-02-23 20:55:21 +03:00
if ( contentType & & * contentType )
2008-02-06 07:12:46 +03:00
/* reserve for string plus 'Content-Type: \r\n" */
2001-02-23 20:55:21 +03:00
blen + = strlen ( * contentType ) + 16 ;
2005-04-13 06:55:12 +04:00
if ( ctxt - > query ! = NULL )
2008-02-06 07:12:46 +03:00
/* 1 for '?' */
2005-04-13 06:55:12 +04:00
blen + = strlen ( ctxt - > query ) + 1 ;
2001-07-23 23:10:52 +04:00
blen + = strlen ( method ) + strlen ( ctxt - > path ) + 24 ;
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2008-02-06 07:12:46 +03:00
/* reserve for possible 'Accept-Encoding: gzip' string */
2005-12-15 14:12:26 +03:00
blen + = 23 ;
# endif
2008-02-06 07:12:46 +03:00
if ( ctxt - > port ! = 80 ) {
/* reserve space for ':xxxxx', incl. potential proxy */
2022-11-04 15:34:39 +03:00
if ( use_proxy )
2017-04-07 18:13:28 +03:00
blen + = 17 ;
2008-02-06 07:12:46 +03:00
else
2017-04-07 18:13:28 +03:00
blen + = 11 ;
2008-02-06 07:12:46 +03:00
}
2003-10-29 16:39:15 +03:00
bp = ( char * ) xmlMallocAtomic ( blen ) ;
2001-07-23 23:10:52 +04:00
if ( bp = = NULL ) {
xmlNanoHTTPFreeCtxt ( ctxt ) ;
2003-10-10 23:36:36 +04:00
xmlHTTPErrMemory ( " allocating header buffer " ) ;
2001-07-23 23:10:52 +04:00
return ( NULL ) ;
}
p = bp ;
2022-11-04 15:34:39 +03:00
if ( use_proxy ) {
2001-02-23 20:55:21 +03:00
if ( ctxt - > port ! = 80 ) {
2012-09-11 09:26:36 +04:00
p + = snprintf ( p , blen - ( p - bp ) , " %s http://%s:%d%s " ,
2002-06-14 21:07:10 +04:00
method , ctxt - > hostname ,
2012-09-11 09:26:36 +04:00
ctxt - > port , ctxt - > path ) ;
2001-02-23 20:55:21 +03:00
}
2012-09-11 09:26:36 +04:00
else
2002-06-14 21:07:10 +04:00
p + = snprintf ( p , blen - ( p - bp ) , " %s http://%s%s " , method ,
2012-09-11 09:26:36 +04:00
ctxt - > hostname , ctxt - > path ) ;
2001-02-23 20:55:21 +03:00
}
else
2002-06-14 21:07:10 +04:00
p + = snprintf ( p , blen - ( p - bp ) , " %s %s " , method , ctxt - > path ) ;
2001-07-23 23:10:52 +04:00
2005-04-13 06:55:12 +04:00
if ( ctxt - > query ! = NULL )
p + = snprintf ( p , blen - ( p - bp ) , " ?%s " , ctxt - > query ) ;
2007-08-24 06:57:38 +04:00
if ( ctxt - > port = = 80 ) {
2012-09-11 09:26:36 +04:00
p + = snprintf ( p , blen - ( p - bp ) , " HTTP/1.0 \r \n Host: %s \r \n " ,
2002-06-14 21:07:10 +04:00
ctxt - > hostname ) ;
2007-08-24 06:57:38 +04:00
} else {
p + = snprintf ( p , blen - ( p - bp ) , " HTTP/1.0 \r \n Host: %s:%d \r \n " ,
ctxt - > hostname , ctxt - > port ) ;
}
2001-07-23 23:10:52 +04:00
2017-11-13 19:08:38 +03:00
# ifdef LIBXML_ZLIB_ENABLED
2005-12-15 14:12:26 +03:00
p + = snprintf ( p , blen - ( p - bp ) , " Accept-Encoding: gzip \r \n " ) ;
# endif
2012-09-11 09:26:36 +04:00
if ( contentType ! = NULL & & * contentType )
2002-06-14 21:07:10 +04:00
p + = snprintf ( p , blen - ( p - bp ) , " Content-Type: %s \r \n " , * contentType ) ;
2001-07-23 23:10:52 +04:00
if ( headers ! = NULL )
2002-06-14 21:07:10 +04:00
p + = snprintf ( p , blen - ( p - bp ) , " %s " , headers ) ;
2001-07-23 23:10:52 +04:00
2001-02-23 20:55:21 +03:00
if ( input ! = NULL )
2002-06-14 21:07:10 +04:00
snprintf ( p , blen - ( p - bp ) , " Content-Length: %d \r \n \r \n " , ilen ) ;
2001-02-23 20:55:21 +03:00
else
2002-06-14 21:07:10 +04:00
snprintf ( p , blen - ( p - bp ) , " \r \n " ) ;
2001-07-23 23:10:52 +04:00
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_HTTP
xmlGenericError ( xmlGenericErrorContext ,
2022-11-04 15:34:39 +03:00
" -> %s%s " , use_proxy ? " (Proxy) " : " " , bp ) ;
2001-02-23 20:55:21 +03:00
if ( ( blen - = strlen ( bp ) + 1 ) < 0 )
xmlGenericError ( xmlGenericErrorContext ,
" ERROR: overflowed buffer by %d bytes \n " , - blen ) ;
# endif
ctxt - > outptr = ctxt - > out = bp ;
ctxt - > state = XML_NANO_HTTP_WRITE ;
2001-07-23 23:10:52 +04:00
blen = strlen ( ctxt - > out ) ;
# ifdef DEBUG_HTTP
2003-07-31 18:47:38 +04:00
xmt_bytes = xmlNanoHTTPSend ( ctxt , ctxt - > out , blen ) ;
2001-07-23 23:10:52 +04:00
if ( xmt_bytes ! = blen )
xmlGenericError ( xmlGenericErrorContext ,
" xmlNanoHTTPMethodRedir: Only %d of %d %s %s \n " ,
xmt_bytes , blen ,
" bytes of HTTP headers sent to host " ,
ctxt - > hostname ) ;
2003-07-31 18:47:38 +04:00
# else
xmlNanoHTTPSend ( ctxt , ctxt - > out , blen ) ;
2001-07-23 23:10:52 +04:00
# endif
if ( input ! = NULL ) {
2003-07-31 18:47:38 +04:00
# ifdef DEBUG_HTTP
2001-07-23 23:10:52 +04:00
xmt_bytes = xmlNanoHTTPSend ( ctxt , input , ilen ) ;
if ( xmt_bytes ! = ilen )
xmlGenericError ( xmlGenericErrorContext ,
2012-09-11 09:26:36 +04:00
" xmlNanoHTTPMethodRedir: Only %d of %d %s %s \n " ,
2001-07-23 23:10:52 +04:00
xmt_bytes , ilen ,
" bytes of HTTP content sent to host " ,
ctxt - > hostname ) ;
2003-07-31 18:47:38 +04:00
# else
xmlNanoHTTPSend ( ctxt , input , ilen ) ;
2001-07-23 23:10:52 +04:00
# endif
}
2001-02-23 20:55:21 +03:00
ctxt - > state = XML_NANO_HTTP_READ ;
while ( ( p = xmlNanoHTTPReadLine ( ctxt ) ) ! = NULL ) {
2009-09-07 16:58:47 +04:00
if ( * p = = 0 ) {
2001-02-23 20:55:21 +03:00
ctxt - > content = ctxt - > inrptr ;
xmlFree ( p ) ;
break ;
}
xmlNanoHTTPScanAnswer ( ctxt , p ) ;
# ifdef DEBUG_HTTP
xmlGenericError ( xmlGenericErrorContext , " <- %s \n " , p ) ;
# endif
xmlFree ( p ) ;
}
if ( ( ctxt - > location ! = NULL ) & & ( ctxt - > returnValue > = 300 ) & &
( ctxt - > returnValue < 400 ) ) {
# ifdef DEBUG_HTTP
xmlGenericError ( xmlGenericErrorContext ,
" \n Redirect to: %s \n " , ctxt - > location ) ;
# endif
2017-06-17 15:51:10 +03:00
while ( xmlNanoHTTPRecv ( ctxt ) > 0 )
;
2001-02-23 20:55:21 +03:00
if ( nbRedirects < XML_NANO_HTTP_MAX_REDIR ) {
nbRedirects + + ;
2001-05-28 15:00:53 +04:00
if ( redirURL ! = NULL )
xmlFree ( redirURL ) ;
2001-02-23 20:55:21 +03:00
redirURL = xmlMemStrdup ( ctxt - > location ) ;
xmlNanoHTTPFreeCtxt ( ctxt ) ;
goto retry ;
}
xmlNanoHTTPFreeCtxt ( ctxt ) ;
2001-05-28 15:00:53 +04:00
if ( redirURL ! = NULL ) xmlFree ( redirURL ) ;
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_HTTP
xmlGenericError ( xmlGenericErrorContext ,
2001-07-23 23:10:52 +04:00
" xmlNanoHTTPMethodRedir: Too many redirects, aborting ... \n " ) ;
2001-02-23 20:55:21 +03:00
# endif
return ( NULL ) ;
}
if ( contentType ! = NULL ) {
if ( ctxt - > contentType ! = NULL )
* contentType = xmlMemStrdup ( ctxt - > contentType ) ;
else
* contentType = NULL ;
}
2001-05-28 15:00:53 +04:00
if ( ( redir ! = NULL ) & & ( redirURL ! = NULL ) ) {
* redir = redirURL ;
} else {
if ( redirURL ! = NULL )
xmlFree ( redirURL ) ;
if ( redir ! = NULL )
* redir = NULL ;
}
2001-02-23 20:55:21 +03:00
# ifdef DEBUG_HTTP
if ( ctxt - > contentType ! = NULL )
xmlGenericError ( xmlGenericErrorContext ,
" \n Code %d, content-type '%s' \n \n " ,
ctxt - > returnValue , ctxt - > contentType ) ;
else
xmlGenericError ( xmlGenericErrorContext ,
" \n Code %d, no content-type \n \n " ,
ctxt - > returnValue ) ;
# endif
return ( ( void * ) ctxt ) ;
}
2001-05-28 15:00:53 +04:00
/**
* xmlNanoHTTPMethod :
* @ URL : The URL to load
* @ method : the HTTP method to use
* @ input : the input string if any
* @ contentType : the Content - Type information IN and OUT
* @ headers : the extra headers
2001-12-31 19:16:02 +03:00
* @ ilen : input length
2001-05-28 15:00:53 +04:00
*
* This function try to open a connection to the indicated resource
* via HTTP using the given @ method , adding the given extra headers
* and the input buffer for the request content .
*
* Returns NULL in case of failure , otherwise a request handler .
* The contentType , if provided must be freed by the caller
*/
void *
xmlNanoHTTPMethod ( const char * URL , const char * method , const char * input ,
2001-07-23 23:10:52 +04:00
char * * contentType , const char * headers , int ilen ) {
2001-05-28 15:00:53 +04:00
return ( xmlNanoHTTPMethodRedir ( URL , method , input , contentType ,
2001-07-23 23:10:52 +04:00
NULL , headers , ilen ) ) ;
2001-05-28 15:00:53 +04:00
}
2001-02-23 20:55:21 +03:00
/**
* xmlNanoHTTPFetch :
* @ URL : The URL to load
* @ filename : the filename where the content should be saved
* @ contentType : if available the Content - Type information will be
* returned at that location
*
* This function try to fetch the indicated resource via HTTP GET
* and save it ' s content in the file .
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of failure , 0 in case of success . The contentType ,
2001-02-23 20:55:21 +03:00
* if provided must be freed by the caller
*/
int
xmlNanoHTTPFetch ( const char * URL , const char * filename , char * * contentType ) {
2001-07-23 23:10:52 +04:00
void * ctxt = NULL ;
char * buf = NULL ;
2001-02-23 20:55:21 +03:00
int fd ;
int len ;
2011-05-09 13:14:59 +04:00
int ret = 0 ;
2005-02-13 11:18:52 +03:00
if ( filename = = NULL ) return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
ctxt = xmlNanoHTTPOpen ( URL , contentType ) ;
if ( ctxt = = NULL ) return ( - 1 ) ;
2012-09-11 09:26:36 +04:00
if ( ! strcmp ( filename , " - " ) )
2001-02-23 20:55:21 +03:00
fd = 0 ;
else {
fd = open ( filename , O_CREAT | O_WRONLY , 00644 ) ;
if ( fd < 0 ) {
xmlNanoHTTPClose ( ctxt ) ;
if ( ( contentType ! = NULL ) & & ( * contentType ! = NULL ) ) {
xmlFree ( * contentType ) ;
* contentType = NULL ;
}
return ( - 1 ) ;
}
}
2001-07-23 23:10:52 +04:00
xmlNanoHTTPFetchContent ( ctxt , & buf , & len ) ;
if ( len > 0 ) {
2011-05-09 13:14:59 +04:00
if ( write ( fd , buf , len ) = = - 1 ) {
ret = - 1 ;
}
2001-02-23 20:55:21 +03:00
}
xmlNanoHTTPClose ( ctxt ) ;
close ( fd ) ;
2011-05-09 13:14:59 +04:00
return ( ret ) ;
2001-02-23 20:55:21 +03:00
}
2003-09-29 17:20:24 +04:00
# ifdef LIBXML_OUTPUT_ENABLED
2001-02-23 20:55:21 +03:00
/**
* xmlNanoHTTPSave :
* @ ctxt : the HTTP context
* @ filename : the filename where the content should be saved
*
* This function saves the output of the HTTP transaction to a file
* It closes and free the context at the end
*
2020-03-08 19:19:42 +03:00
* Returns - 1 in case of failure , 0 in case of success .
2001-02-23 20:55:21 +03:00
*/
int
xmlNanoHTTPSave ( void * ctxt , const char * filename ) {
2001-07-26 00:25:21 +04:00
char * buf = NULL ;
2001-02-23 20:55:21 +03:00
int fd ;
int len ;
2011-05-09 13:14:59 +04:00
int ret = 0 ;
2005-02-13 11:18:52 +03:00
if ( ( ctxt = = NULL ) | | ( filename = = NULL ) ) return ( - 1 ) ;
2001-02-23 20:55:21 +03:00
2012-09-11 09:26:36 +04:00
if ( ! strcmp ( filename , " - " ) )
2001-02-23 20:55:21 +03:00
fd = 0 ;
else {
2007-08-24 00:47:33 +04:00
fd = open ( filename , O_CREAT | O_WRONLY , 0666 ) ;
2001-02-23 20:55:21 +03:00
if ( fd < 0 ) {
xmlNanoHTTPClose ( ctxt ) ;
return ( - 1 ) ;
}
}
2001-07-23 23:10:52 +04:00
xmlNanoHTTPFetchContent ( ctxt , & buf , & len ) ;
if ( len > 0 ) {
2011-05-09 13:14:59 +04:00
if ( write ( fd , buf , len ) = = - 1 ) {
ret = - 1 ;
}
2001-02-23 20:55:21 +03:00
}
xmlNanoHTTPClose ( ctxt ) ;
2004-03-17 11:44:46 +03:00
close ( fd ) ;
2011-05-09 13:14:59 +04:00
return ( ret ) ;
2001-02-23 20:55:21 +03:00
}
2003-09-29 17:20:24 +04:00
# endif /* LIBXML_OUTPUT_ENABLED */
2001-02-23 20:55:21 +03:00
/**
* xmlNanoHTTPReturnCode :
* @ ctx : the HTTP context
*
2001-07-18 23:30:27 +04:00
* Get the latest HTTP return code received
*
2001-02-23 20:55:21 +03:00
* Returns the HTTP return code for the request .
*/
int
xmlNanoHTTPReturnCode ( void * ctx ) {
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
if ( ctxt = = NULL ) return ( - 1 ) ;
return ( ctxt - > returnValue ) ;
}
/**
* xmlNanoHTTPAuthHeader :
* @ ctx : the HTTP context
*
2001-07-18 23:30:27 +04:00
* Get the authentication header of an HTTP context
*
2001-02-23 20:55:21 +03:00
* Returns the stashed value of the WWW - Authenticate or Proxy - Authenticate
* header .
*/
const char *
xmlNanoHTTPAuthHeader ( void * ctx ) {
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
if ( ctxt = = NULL ) return ( NULL ) ;
return ( ctxt - > authHeader ) ;
}
2001-07-23 23:10:52 +04:00
/**
2002-12-10 18:19:08 +03:00
* xmlNanoHTTPContentLength :
2001-07-23 23:10:52 +04:00
* @ ctx : the HTTP context
*
2002-12-11 17:23:49 +03:00
* Provides the specified content length from the HTTP header .
*
2001-07-23 23:10:52 +04:00
* Return the specified content length from the HTTP header . Note that
* a value of - 1 indicates that the content length element was not included in
* the response header .
*/
int
xmlNanoHTTPContentLength ( void * ctx ) {
2003-10-29 16:39:15 +03:00
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
2001-07-23 23:10:52 +04:00
return ( ( ctxt = = NULL ) ? - 1 : ctxt - > ContentLength ) ;
}
2003-10-18 15:29:40 +04:00
/**
* xmlNanoHTTPRedir :
* @ ctx : the HTTP context
*
* Provides the specified redirection URL if available from the HTTP header .
*
* Return the specified redirection URL or NULL if not redirected .
*/
const char *
xmlNanoHTTPRedir ( void * ctx ) {
2003-10-29 16:39:15 +03:00
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
2003-10-18 15:29:40 +04:00
return ( ( ctxt = = NULL ) ? NULL : ctxt - > location ) ;
}
/**
* xmlNanoHTTPEncoding :
* @ ctx : the HTTP context
*
* Provides the specified encoding if specified in the HTTP headers .
*
* Return the specified encoding or NULL if not available
*/
const char *
xmlNanoHTTPEncoding ( void * ctx ) {
2003-10-29 16:39:15 +03:00
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
2003-10-18 15:29:40 +04:00
return ( ( ctxt = = NULL ) ? NULL : ctxt - > encoding ) ;
}
2003-10-19 17:35:37 +04:00
/**
* xmlNanoHTTPMimeType :
* @ ctx : the HTTP context
*
* Provides the specified Mime - Type if specified in the HTTP headers .
*
* Return the specified Mime - Type or NULL if not available
*/
const char *
xmlNanoHTTPMimeType ( void * ctx ) {
2003-10-29 16:39:15 +03:00
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
2003-10-19 17:35:37 +04:00
return ( ( ctxt = = NULL ) ? NULL : ctxt - > mimeType ) ;
}
2001-07-23 23:10:52 +04:00
/**
2002-12-10 18:19:08 +03:00
* xmlNanoHTTPFetchContent :
2001-07-23 23:10:52 +04:00
* @ ctx : the HTTP context
* @ ptr : pointer to set to the content buffer .
* @ len : integer pointer to hold the length of the content
*
2002-12-11 17:23:49 +03:00
* Check if all the content was read
*
2001-07-23 23:10:52 +04:00
* Returns 0 if all the content was read and available , returns
2012-09-11 09:26:36 +04:00
* - 1 if received content length was less than specified or an error
2001-07-23 23:10:52 +04:00
* occurred .
*/
2004-06-27 16:08:10 +04:00
static int
2001-07-23 23:10:52 +04:00
xmlNanoHTTPFetchContent ( void * ctx , char * * ptr , int * len ) {
2003-10-29 16:39:15 +03:00
xmlNanoHTTPCtxtPtr ctxt = ( xmlNanoHTTPCtxtPtr ) ctx ;
2001-07-23 23:10:52 +04:00
int rc = 0 ;
int cur_lgth ;
int rcvd_lgth ;
int dummy_int ;
char * dummy_ptr = NULL ;
/* Dummy up return input parameters if not provided */
if ( len = = NULL )
len = & dummy_int ;
if ( ptr = = NULL )
ptr = & dummy_ptr ;
/* But can't work without the context pointer */
if ( ( ctxt = = NULL ) | | ( ctxt - > content = = NULL ) ) {
* len = 0 ;
* ptr = NULL ;
return ( - 1 ) ;
}
rcvd_lgth = ctxt - > inptr - ctxt - > content ;
while ( ( cur_lgth = xmlNanoHTTPRecv ( ctxt ) ) > 0 ) {
rcvd_lgth + = cur_lgth ;
if ( ( ctxt - > ContentLength > 0 ) & & ( rcvd_lgth > = ctxt - > ContentLength ) )
break ;
}
* ptr = ctxt - > content ;
* len = rcvd_lgth ;
if ( ( ctxt - > ContentLength > 0 ) & & ( rcvd_lgth < ctxt - > ContentLength ) )
rc = - 1 ;
else if ( rcvd_lgth = = 0 )
rc = - 1 ;
return ( rc ) ;
}
2001-02-23 20:55:21 +03:00
# ifdef STANDALONE
int main ( int argc , char * * argv ) {
char * contentType = NULL ;
if ( argv [ 1 ] ! = NULL ) {
2012-09-11 09:26:36 +04:00
if ( argv [ 2 ] ! = NULL )
2001-02-23 20:55:21 +03:00
xmlNanoHTTPFetch ( argv [ 1 ] , argv [ 2 ] , & contentType ) ;
else
xmlNanoHTTPFetch ( argv [ 1 ] , " - " , & contentType ) ;
if ( contentType ! = NULL ) xmlFree ( contentType ) ;
} else {
xmlGenericError ( xmlGenericErrorContext ,
" %s: minimal HTTP GET implementation \n " , argv [ 0 ] ) ;
xmlGenericError ( xmlGenericErrorContext ,
" \t usage %s [ URL [ filename ] ] \n " , argv [ 0 ] ) ;
}
xmlNanoHTTPCleanup ( ) ;
xmlMemoryDump ( ) ;
return ( 0 ) ;
}
# endif /* STANDALONE */
# else /* !LIBXML_HTTP_ENABLED */
# ifdef STANDALONE
# include <stdio.h>
int main ( int argc , char * * argv ) {
xmlGenericError ( xmlGenericErrorContext ,
" %s : HTTP support not compiled in \n " , argv [ 0 ] ) ;
return ( 0 ) ;
}
# endif /* STANDALONE */
# endif /* LIBXML_HTTP_ENABLED */